我有这个视图,想简化它:
struct SUIBorderedIconTextButton: View {
struct IconInfo {
enum Position {
case left
case right
case top
case bottom
var isHorizontal: Bool {
return self == .left || self == .right
}
var isBeforeText: Bool {
return self == .left || self == .top
}
}
let icon: Image
let position: Position
}
let iconInfo: IconInfo?
let title: String
let fontSize: CGFloat
let backgroundColor: Color
let enabled: Bool
let action: () -> Void
@ViewBuilder
private var content: some View {
if let iconInfo = iconInfo {
switch iconInfo.position {
case .left:
HStack {
iconInfo.icon
Text(title).fontSize(fontSize)
}
case .right:
HStack {
Text(title).fontSize(fontSize)
iconInfo.icon
}
case .top:
VStack {
iconInfo.icon
Text(title).fontSize(fontSize)
}
case .bottom:
VStack {
Text(title).fontSize(fontSize)
iconInfo.icon
}
}
} else {
Text(title).fontSize(fontSize)
}
}
var body: some View {
Button(action: action) {
content
.padding()
.foregroundColor(color_button_text)
.background {
RoundedRectangle(cornerRadius: text_button_border_radius)
.foregroundColor(enabled ? backgroundColor : color_disabled_background)
}
}
.disabled(!enabled)
}
}
该视图只显示一个文本按钮,带有可选图标(位于文本的左/右/上/下(
如果位置是左或右,我们希望使用HStack。否则,请使用VStack。
若位置在顶部或左侧,我们希望将图标放在文本之前。否则,将图标放在文本后面。
请注意,在content
构建器中有相当多的样板。
我为.top或.left案例创建了这个助手函数:
@ViewBuilder
private func group(iconInfo: IconInfo) -> some View {
if iconInfo.position.isBeforeText {
iconInfo.icon
Text(title).fontSize(fontSize)
} else {
Text(title).fontSize(fontSize)
iconInfo.icon
}
}
但我不知道如何选择构造函数。我可能需要一个指向init函数的指针,但我已经尝试过
let constructor = position.isHorizontal ? HStack.init : VStack.init
constructor {
...
}
这显然不能编译。我不知道该怎么办。如果你有其他想法可以简化这个逻辑,也可以尝试一下。
三元运算符实际上不适用于SwiftUI类型,因为它们都是具有泛型的值类型,因此会导致构造不同的类型实体,并且不能分配给一个变量。
相反,你的案例可能的方法是类似
@ViewBuilder var content: some View {
Text("Text")
Image(systemName: "checkmark")
}
var body: some View {
if isHorizontal {
HStack{ content }
} else {
VStack{ content }
}
}