我从 another question 获得以下代码并尝试在方法 ViewBuilder
上使用 func text(for word: String) -> some View
以将一些 HStack 文本内容包装到 NavigationLink
中。< /p>
问题是,一旦我这样做,计算出的对齐就会被破坏。
如果从命名方法中删除 @ViewBuilder
注释,内容将正确对齐。
我该如何解决这个问题?
public struct HStackTextWrapping: View {
private let words: [String]
private let parentView: ParentView
private let textModifiers: (Text) -> Text
@State private var totalHeight: CGFloat
public init(_ string: String,
in parentView: ParentView,
@ViewBuilder textModifiers: @escaping (Text) -> Text = { $0 })
{
self.words = string.components(separatedBy: .whitespaces)
self.parentView = parentView
self.textModifiers = textModifiers
switch parentView {
case .scrollview:
totalHeight = .zero
case .vstack:
totalHeight = .infinity
}
}
public var body: some View {
VStack {
GeometryReader { geometry in
self.generateContent(in: geometry)
}
}
.ifCondition(self.parentView == .scrollview) {
$0.frame(height: totalHeight)
}
.ifCondition(self.parentView == .vstack) {
$0.frame(maxHeight: totalHeight)
}
}
private func generateContent(in g: GeometryProxy) -> some View {
var width: CGFloat = .zero
var height: CGFloat = .zero
return ZStack(alignment: .topLeading) {
ForEach(self.words, id: \.self) { word in
self.text(for: word)
.padding(0)
.alignmentGuide(.leading) { d in
if abs(width - d.width) > g.size.width {
width = 0
height -= d.height
}
let result = width
if word == self.words.last {
width = 0
} else {
width -= d.width
}
print("(\(result), ")
return result
}
.alignmentGuide(.top) { d in
let result = height
if word == self.words.last {
height = 0
}
print("\(result)) " + word)
return result
}
}
}
.background(viewHeightReader($totalHeight))
}
@ViewBuilder
private func text(for word: String) -> some View {
let potentialWhitespace = word == self.words.last ? "" : " "
let text = self.textModifiers(Text(word + potentialWhitespace))
if word.first == "@" {
NavigationLink(destination: AnyView(ProfileView(username: String(word.dropFirst()))), label: { text })
.foregroundColor(ColorPalette.primary.color)
}
else if word.first == "#" {
NavigationLink(destination: AnyView(Text(word)), label: { text })
.foregroundColor(ColorPalette.primary.color)
}
else {
text
}
}
private func viewHeightReader(_ binding: Binding<CGFloat>) -> some View {
return GeometryReader { geometry -> Color in
let rect = geometry.frame(in: .local)
DispatchQueue.main.async {
binding.wrappedValue = rect.size.height
}
return .clear
}
}
private func resolveTags(in text: String) {
}
}
public enum ParentView {
case scrollview
case vstack
}