是否可以在 SwiftUI 中将 Button<Text> 添加到 Text 中?
Posted
技术标签:
【中文标题】是否可以在 SwiftUI 中将 Button<Text> 添加到 Text 中?【英文标题】:Is it possible to add Button<Text> to Text in SwiftUI? 【发布时间】: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。
【问题讨论】:
【参考方案1】:您可以扩展 AnyView 以获得您需要的内容。如果你非常擅长编程,你可以为你的目标引入更复杂的自动布局。
extension AnyView
static func + (left: AnyView, right: AnyView) -> AnyView
return AnyView(HStackleft.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)
当您只对链接感兴趣并且可以接受链接的默认显示(据我所知,您无法更改此设置)时,此解决方案具有潜力。
【讨论】:
以上是关于是否可以在 SwiftUI 中将 Button<Text> 添加到 Text 中?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 中将 DatePicker 放入 ContextMenu