【问题标题】:Is it possible to add Button<Text> to Text in SwiftUI?是否可以在 SwiftUI 中将 Button<Text> 添加到 Text 中?
【发布时间】:2019-11-16 20:11:11
【问题描述】:

通常,添加两个文本视图将生成一个文本视图,保留每个文本视图的属性。例如:

Text(“Hello ”) + Text(“world!”).foregroundColor(.blue)

这应该产生Hello world!,蓝色的world!。现在,如果我想让world! 可点击并充当按钮,我该怎么办?好吧,从逻辑上讲,这样做是有意义的:

Text(“Hello ”) + Button(action: {}) { Text(“world!”).foregroundColor(.blue) }

但是,直接上面的代码无法编译。是否可以按照所述创建带有可点击部分的文本视图?我的用例是用于带有 @ 提及或 # 主题标签的推文,您可以在其中点击提及或主题标签以显示详细视图。

编辑:在 HStack 中使用 Text 视图和 Button 不合适的原因是因为这是在返回推文内容的 Text 视图的函数中:

func styledText(text: String) -> Text {
    var output = Text("")
    let components = text.tokenize("@#. ")
    for component in components {
        if component.rangeOfCharacter(from: CharacterSet(charactersIn: "@#")) != nil {
            output = output + Text(component).foregroundColor(.accentColor)
        } else {
            output = output + Text(component)
        }
    }
    return output
}

String.tokenize 如下:

extension String {
    func tokenize(_ delimiters: String) -> [String] {
        var output = [String]()
        var buffer = ""
        for char in self {
            if delimiters.contains(char) {
                output.append(buffer)
                buffer = String(char)
            } else {
                buffer += String(char)
            }
        }
        output.append(buffer)
        return output
    }
}

编辑 2: 如果有帮助,我正在尝试创建一个 SwiftUI 版本:https://github.com/optonaut/ActiveLabel.swift。

【问题讨论】:

    标签: swift swiftui


    【解决方案1】:

    您可以扩展 AnyView 以获得您需要的内容。如果你非常擅长编程,你可以为你的目标引入更复杂的自动布局。

    extension AnyView{
        static func + (left: AnyView, right: AnyView) -> AnyView{
            return AnyView(HStack{left.fixedSize(horizontal: true, vertical: false)
                                  right.fixedSize(horizontal: true, vertical: false)})
        }
    }
    
    
    func styledText(text: String) -> AnyView {
        var output = AnyView(Text(""))
        let components = text.tokenize("@#. ")
        for component in components {
            if component.rangeOfCharacter(from: CharacterSet(charactersIn: "@#")) != nil {
                output = output + AnyView(Text(component).foregroundColor(.accentColor).onTapGesture {
                    print(component)
                })
            } else {
                output = output + AnyView(Text(component))
            }
        }
    
        return output
    }
    

    【讨论】:

    • 谢谢!如果您使AnyView 扩展中HStack 的间距等于0,它几乎会产生所需的结果!唯一的问题是 HStack 没有包装它的内容,所以整个文本段落将在一行结束,打乱了视图。有什么办法可以克服或实现它?
    • 所以你需要 fixSize 来测试不同的配置
    【解决方案2】:

    我不确定你是想要这个还是你想明确地使用 +,但你可以通过这个来达到你的目标

     HStack {
                    Text("Hello ")
                    Button(action: {
                        // do something
                        print("tapped")
                    }, label: {
                        Text("world!").foregroundColor(.blue)
                    })
                }
    

    【讨论】:

    • 感谢您的回复 — 这不合适,因为 @ 提及或 # 主题标签按钮将位于正文中,高度超过一行,并且可能是所述文本中的任何位置。
    【解决方案3】:

    这是另一种解决方案,但这仅对链接类型的样式真正有用。换句话说,如果需要,我认为没有简单的解决方案可以执行任何自定义操作。

    我的解决方案建议创建一个可以显示属性字符串的UIViewRepresentable:

    struct AttributedText: UIViewRepresentable {
        
        var attributedString: NSAttributedString
        
        func makeUIView(context: Context) -> UITextView {
            let textView = UITextView()
            textView.attributedText = self.attributedString
            return textView
        }
        
        func updateUIView(_ uiView: UITextView, context: Context) {}
        
    }
    

    然后你可以像这样创建一个属性字符串:

    var attributedString: NSAttributedString = {
        let attrString = NSMutableAttributedString(string: "Hello, ")
        let blueWorld = NSMutableAttributedString(string: "world!")
        let attributes: [NSAttributedString.Key : Any ] = [
            .link: NSURL(string: "https://twitter.com")!
        ]
        let fullRange = NSRange(location: 0, length: blueWorld.length)
        blueWorld.setAttributes(attributes, range: fullRange)
        attrString.append(blueWorld)
        return attrString
    }()
    

    或使用任何好的库,直到苹果有更好的选择。这使您可以简单地显示文本,因为它是常规的Text:

    struct MyText {
    
        var body: some View {
            AttributedText(attributedString: myCustomAttributedString)
        }
    
    }
    

    当您只对链接感兴趣并且可以接受链接的默认显示(据我所知,您无法更改此设置)时,此解决方案具有潜力。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多