我正在尝试创建 2 个大小相同的按钮,但大小由按钮内的文本决定。这两个按钮是“登录”和“创建帐户”,因此“创建帐户”按钮更大。我尝试使用 .frame() 来调整大小,但这只是让它周围有额外的填充。
这是我的代码:
HStack {
Button(action: {
print("Login button pressed")
}) {
Text("Login")
.padding()
.foregroundColor(Color.white)
.background(Color(UIColor.buttonColor))
.cornerRadius(15)
}
Button(action: {
print("Create Account button pressed")
}) {
Text("Create Account")
.padding()
.foregroundColor(Color.white)
.background(Color(UIColor.buttonColor))
.cornerRadius(15)
}
}
这是显示的内容
最好制作一个按钮样式,你可以在你的应用程序中使用它,这也将确保任何未来的堆栈按比例填充。否则你会发现你的 UI 会变得混乱,用这样的 Text()s 制作按钮。
在 HStack 中使用自定义样式布置按钮:
HStack(spacing: 20) {
Button("Login", action: { print("login")})
.buttonStyle(PrimaryButtonStyle())
Button("Create Account", action: { print("create account")})
.buttonStyle(PrimaryButtonStyle())
}.padding([.leading, .trailing], 10)
PrimaryButtonStyle:
struct PrimaryButtonStyle: ButtonStyle {
var backgroundColor: Color = .black
var textColor: Color = Color.white
var height: CGFloat = 46
var cornerRadius: CGFloat = 15
var fontSize: CGFloat = 15
var disabled: Bool = false
var textSidePadding: CGFloat = 30
var weight: Font.Weight = .semibold
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding([.leading, .trailing], textSidePadding)
.frame(maxWidth: .infinity, maxHeight: height)
.background(disabled ? .gray : backgroundColor)
.foregroundColor(textColor)
.cornerRadius(cornerRadius)
.font(.system(size: fontSize, weight: weight, design: .default))
.scaleEffect(configuration.isPressed ? 1.2 : 1)
.animation(.easeOut(duration: 0.2), value: configuration.isPressed)
}
}
结果:
Layout
协议。
此代码来自 WWDC 2022 视频Compose custom layouts with SwiftUI,它将多个按钮水平调整为等宽。
struct ButtonEqualWidth: Layout {
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let maxSize = maxSize(subviews: subviews)
let spacing = spacing(subviews: subviews)
let totalSpacing = spacing.reduce(0, +)
return CGSize(width: maxSize.width * CGFloat(subviews.count) + totalSpacing,
height: maxSize.height)
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let maxSize = maxSize(subviews: subviews)
let spacing = spacing(subviews: subviews)
let sizeProposal = ProposedViewSize(width: maxSize.width, height: maxSize.height)
var x = bounds.minX + maxSize.width / 2
for index in subviews.indices {
subviews[index].place(
at: CGPoint(x: x, y: bounds.midY),
anchor: .center,
proposal: sizeProposal)
x += maxSize.width + spacing[index]
}
}
func maxSize(subviews: Subviews) -> CGSize {
let subviewSizes = subviews.map{ $0.sizeThatFits(.unspecified) }
return subviewSizes.reduce(.zero) { currentMax, subviewSize in
CGSize(
width: max(currentMax.width, subviewSize.width),
height: max(currentMax.height, subviewSize.height)
)
}
}
func spacing(subviews: Subviews) -> [Double] {
return subviews.indices.map { index in
guard index < subviews.count - 1 else { return 0.0 }
return subviews[index].spacing.distance(
to: subviews[index + 1].spacing,
along: .horizontal)
}
}
}
在您的示例中,将此修饰符添加到两个
Text
视图
.frame(maxWidth: .infinity)
并将
HStack
替换为ButtonEqualWidth
如何让两个视图的宽度或高度相同
当你想让两个视图具有相同的宽度时,这种方法同样有效:
VStack {
Button("Log in") { }
.foregroundColor(.white)
.padding()
.frame(maxWidth: .infinity)
.background(.red)
.clipShape(Capsule())
Button("Reset Password") { }
.foregroundColor(.white)
.padding()
.frame(maxWidth: .infinity)
.background(.red)
.clipShape(Capsule())
}
.fixedSize(horizontal: true, vertical: false)
有 ↑ .fixedSize(horizontal: true, vertical: false) & 没有它
重要的是要了解
.frame(maxWidth: .infinity)
也很重要
.frame 并将宽度设置为 UI 屏幕 - 空白应该可以工作