如何使用 NavigationLink 在 SwiftUI 中创建文本(仅文本中的一些单词)
How can I create text in SwiftUI with NavigationLink (only some words from text)
我正在为 iOS 开发 SwiftUI 应用程序。
我想以这种方式格式化文本,其中蓝色单词应该是 NavigationLinks。文本的外观:
我知道可以将 UIKit 实现到 SwiftUI 代码中。但是,我不明白如何通过正常工作的 NavigationLinks 以这种方式使用 UIKit。
以this SO question为基础,这是一个解决方案。左对齐但是一种方法。
import SwiftUI
struct DynamicLinkTextView: View {
let text: String = "I want text like this, with NavigationLinks to another View. However, this doesn't work"
let wordsWLinks: [String] = ["this", "View"]
@State var selection: String?
var textArray: [String]{
text.components(separatedBy: " ")
}
var body: some View {
NavigationView{
VStack{
MultilineHStack(textArray){ text in
VStack{
if wordsWLinks.contains(text.removePunctiation()){
NavigationLink(text + " ", destination: Text("link = \(text)"), tag: text as String, selection: $selection)
}else{
Text(text + " ").fixedSize()
}
}
}
}
}
}
}
//
public struct MultilineHStack: View {
struct SizePreferenceKey: PreferenceKey {
typealias Value = [CGSize]
static var defaultValue: Value = []
static func reduce(value: inout Value, nextValue: () -> Value) {
value.append(contentsOf: nextValue())
}
}
private let items: [AnyView]
@State private var sizes: [CGSize] = []
public init<Data: RandomAccessCollection, Content: View>(_ data: Data, @ViewBuilder content: (Data.Element) -> Content) {
self.items = data.map { AnyView(content([=10=])) }
}
public var body: some View {
GeometryReader {geometry in
ZStack(alignment: .topLeading) {
ForEach(self.items.indices) { index in
self.items[index].background(self.backgroundView()).offset(self.getOffset(at: index, geometry: geometry))
}
}
}.onPreferenceChange(SizePreferenceKey.self) {
self.sizes = [=10=]
}
}
private func getOffset(at index: Int, geometry: GeometryProxy) -> CGSize {
guard index < sizes.endIndex else {return .zero}
let frame = sizes[index]
var (x,y,maxHeight) = sizes[..<index].reduce((CGFloat.zero,CGFloat.zero,CGFloat.zero)) {
var (x,y,maxHeight) = [=10=]
x += .width
if x > geometry.size.width {
x = .width
y += maxHeight
maxHeight = 0
}
maxHeight = max(maxHeight, .height)
return (x,y,maxHeight)
}
if x + frame.width > geometry.size.width {
x = 0
y += maxHeight
}
return .init(width: x, height: y)
}
private func backgroundView() -> some View {
GeometryReader { geometry in
Rectangle()
.fill(Color.clear)
.preference(
key: SizePreferenceKey.self,
value: [geometry.frame(in: CoordinateSpace.global).size]
)
}
}
}
struct DynamicLinkTextView_Previews: PreviewProvider {
static var previews: some View {
DynamicLinkTextView()
}
}
extension String{
func removePunctiation() -> String {
self.trimmingCharacters(in: CharacterSet(charactersIn: ",."))
}
}
我正在为 iOS 开发 SwiftUI 应用程序。 我想以这种方式格式化文本,其中蓝色单词应该是 NavigationLinks。文本的外观:
我知道可以将 UIKit 实现到 SwiftUI 代码中。但是,我不明白如何通过正常工作的 NavigationLinks 以这种方式使用 UIKit。
以this SO question为基础,这是一个解决方案。左对齐但是一种方法。
import SwiftUI
struct DynamicLinkTextView: View {
let text: String = "I want text like this, with NavigationLinks to another View. However, this doesn't work"
let wordsWLinks: [String] = ["this", "View"]
@State var selection: String?
var textArray: [String]{
text.components(separatedBy: " ")
}
var body: some View {
NavigationView{
VStack{
MultilineHStack(textArray){ text in
VStack{
if wordsWLinks.contains(text.removePunctiation()){
NavigationLink(text + " ", destination: Text("link = \(text)"), tag: text as String, selection: $selection)
}else{
Text(text + " ").fixedSize()
}
}
}
}
}
}
}
//
public struct MultilineHStack: View {
struct SizePreferenceKey: PreferenceKey {
typealias Value = [CGSize]
static var defaultValue: Value = []
static func reduce(value: inout Value, nextValue: () -> Value) {
value.append(contentsOf: nextValue())
}
}
private let items: [AnyView]
@State private var sizes: [CGSize] = []
public init<Data: RandomAccessCollection, Content: View>(_ data: Data, @ViewBuilder content: (Data.Element) -> Content) {
self.items = data.map { AnyView(content([=10=])) }
}
public var body: some View {
GeometryReader {geometry in
ZStack(alignment: .topLeading) {
ForEach(self.items.indices) { index in
self.items[index].background(self.backgroundView()).offset(self.getOffset(at: index, geometry: geometry))
}
}
}.onPreferenceChange(SizePreferenceKey.self) {
self.sizes = [=10=]
}
}
private func getOffset(at index: Int, geometry: GeometryProxy) -> CGSize {
guard index < sizes.endIndex else {return .zero}
let frame = sizes[index]
var (x,y,maxHeight) = sizes[..<index].reduce((CGFloat.zero,CGFloat.zero,CGFloat.zero)) {
var (x,y,maxHeight) = [=10=]
x += .width
if x > geometry.size.width {
x = .width
y += maxHeight
maxHeight = 0
}
maxHeight = max(maxHeight, .height)
return (x,y,maxHeight)
}
if x + frame.width > geometry.size.width {
x = 0
y += maxHeight
}
return .init(width: x, height: y)
}
private func backgroundView() -> some View {
GeometryReader { geometry in
Rectangle()
.fill(Color.clear)
.preference(
key: SizePreferenceKey.self,
value: [geometry.frame(in: CoordinateSpace.global).size]
)
}
}
}
struct DynamicLinkTextView_Previews: PreviewProvider {
static var previews: some View {
DynamicLinkTextView()
}
}
extension String{
func removePunctiation() -> String {
self.trimmingCharacters(in: CharacterSet(charactersIn: ",."))
}
}