Công thức này cho biết cách định dạng nội dung của SwiftUI
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 bằng HTML qua var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 trên bất kỳ phiên bản SwiftUI nàoKết quả cuối cùng trông như thế này
Có hai giải pháp trong công thức này
- SwiftUI 3 [iOS 15, macOS 12] mang đến trình bao bọc
1 mới xung quanh chế độ xemvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
0 vàvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
0 hoạt động tự nhiên với nó. Có một số mã mẫu ở cuối bài viết hướng dẫn cách sử dụngvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
- SwiftUI 1 và 2 [iOS 13-14, macOS 10. 15-11] mờ nhạt một cách đáng ngạc nhiên khi làm việc với
0 trongvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
0 lượt xem. không có hỗ trợ mặc định cho nó và thậm chí cố gắng đưa trực tiếp chuỗi được gán vào Chế độ xem dẫn đến một số vấn đề về bộ nhớ kỳ lạ. Nó không phải là tất cả vô vọng, mặc dù. đọc tiếp để xem giải pháp hiệu quả cho tất cả các phiên bản SwiftUIvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
Công thức cho tất cả các phiên bản
Giải pháp chưa hoàn thiện đầy đủ vì nó không hỗ trợ tất cả các thẻ HTML - nhưng nó luôn hoàn thành công việc
Nó cũng không hỗ trợ các siêu liên kết ngay lập tức - để kiểm tra xem điều đó được thực hiện như thế nào, hãy sử dụng công thức Siêu liên kết trong SwiftUI Text. Sự khác biệt chính là công thức này chỉ hoạt động với chế độ xem Văn bản SwiftUI, đây có thể là một lợi thế lớn
Trước tiên, chúng tôi sẽ kiểm tra giải pháp hiệu quả, giải pháp nào
- Hỗ trợ hầu hết các tùy chọn định dạng HTML,
- không có vấn đề về kích thước hoặc bố cục,
- sử dụng
0 gốc, cho phép bạn sử dụng tất cả các công cụ sửa đổi chế độ xem dành riêng chovar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
0var concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
Sau đó, chúng ta sẽ xem xét một số lần thử khác không thành công do sự cố SwiftUI nội bộ
Giải pháp làm việcOK, vì vậy giải pháp làm việc là hai phần
- Hiển thị một
0 trong mộtvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
0, vàvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
- Chuyển đổi văn bản HTML thành
0 và giải quyết một số chi tiếtvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
Hiển thị NSAttributionString trong một văn bản
Phần đầu tiên chia
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 thành các chuỗi con được phân bổ rõ ràng, tạo và tạo kiểu cho một var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 dựa trên các thuộc tính của nó. Sau đó, nó dựa trên phép nối var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 - thực tế là bạn có thể sử dụng toán tử extension Text {
init[_ attributedString: NSAttributedString] {
self.init[""] // initial, empty Text
// scan the attributed string for distinctly attributed regions
attributedString.enumerateAttributes[in: NSRange[location: 0, length: attributedString.length],
options: []] { [attrs, range, _] in
let string = attributedString.attributedSubstring[from: range].string
var text = Text[string]
// then, read applicable attributes and apply them to the Text
if let font = attrs[.font] as? UIFont {
// this takes care of the majority of formatting - text size, font family,
// font weight, if it's italic, etc.
text = text.font[.init[font]]
}
if let color = attrs[.foregroundColor] as? UIColor {
text = text.foregroundColor[Color[color]]
}
if let kern = attrs[.kern] as? CGFloat {
text = text.kerning[kern]
}
if #available[iOS 14.0, *] {
if let tracking = attrs[.tracking] as? CGFloat {
text = text.tracking[tracking]
}
}
if let strikethroughStyle = attrs[.strikethroughStyle] as? NSNumber,
strikethroughStyle != 0 {
if let strikethroughColor = [attrs[.strikethroughColor] as? UIColor] {
text = text.strikethrough[true, color: Color[strikethroughColor]]
} else {
text = text.strikethrough[true]
}
}
if let underlineStyle = attrs[.underlineStyle] as? NSNumber,
underlineStyle != 0 {
if let underlineColor = [attrs[.underlineColor] as? UIColor] {
text = text.underline[true, color: Color[underlineColor]]
} else {
text = text.underline[true]
}
}
if let baselineOffset = attrs[.baselineOffset] as? NSNumber {
text = text.baselineOffset[CGFloat[baselineOffset.floatValue]]
}
// append the newly styled subtext to the rest of the text
self = self + text
}
}
}
4 trên hai phiên bản var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 và SwiftUI sẽ kết hợp chúng thành một var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 mới, trong khi vẫn đảm bảo bố cục và kích thước________số 8Có một nhược điểm tiềm ẩn đối với điều này - toán tử
extension Text {
init[_ attributedString: NSAttributedString] {
self.init[""] // initial, empty Text
// scan the attributed string for distinctly attributed regions
attributedString.enumerateAttributes[in: NSRange[location: 0, length: attributedString.length],
options: []] { [attrs, range, _] in
let string = attributedString.attributedSubstring[from: range].string
var text = Text[string]
// then, read applicable attributes and apply them to the Text
if let font = attrs[.font] as? UIFont {
// this takes care of the majority of formatting - text size, font family,
// font weight, if it's italic, etc.
text = text.font[.init[font]]
}
if let color = attrs[.foregroundColor] as? UIColor {
text = text.foregroundColor[Color[color]]
}
if let kern = attrs[.kern] as? CGFloat {
text = text.kerning[kern]
}
if #available[iOS 14.0, *] {
if let tracking = attrs[.tracking] as? CGFloat {
text = text.tracking[tracking]
}
}
if let strikethroughStyle = attrs[.strikethroughStyle] as? NSNumber,
strikethroughStyle != 0 {
if let strikethroughColor = [attrs[.strikethroughColor] as? UIColor] {
text = text.strikethrough[true, color: Color[strikethroughColor]]
} else {
text = text.strikethrough[true]
}
}
if let underlineStyle = attrs[.underlineStyle] as? NSNumber,
underlineStyle != 0 {
if let underlineColor = [attrs[.underlineColor] as? UIColor] {
text = text.underline[true, color: Color[underlineColor]]
} else {
text = text.underline[true]
}
}
if let baselineOffset = attrs[.baselineOffset] as? NSNumber {
text = text.baselineOffset[CGFloat[baselineOffset.floatValue]]
}
// append the newly styled subtext to the rest of the text
self = self + text
}
}
}
4 chỉ hoạt động trên var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 và chỉ một số công cụ sửa đổi chế độ xem của nó thực sự trả về var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 chứ không phải var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
00. e. g, cái này không hoạt độngvar concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
Điều này có nghĩa là không phải tất cả các thuộc tính đều có thể được áp dụng cho một
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0. e. g, thuộc tính var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
02 bị bỏ qua vì không có cách nào để phát hiện một lần nhấn vào var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 và vẫn trả về một var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0. Tuy nhiên, nó bao gồm hầu như tất cả các định dạng từ một chuỗi được gán mà bạn thường cần. Đây là mãextension Text {
init[_ attributedString: NSAttributedString] {
self.init[""] // initial, empty Text
// scan the attributed string for distinctly attributed regions
attributedString.enumerateAttributes[in: NSRange[location: 0, length: attributedString.length],
options: []] { [attrs, range, _] in
let string = attributedString.attributedSubstring[from: range].string
var text = Text[string]
// then, read applicable attributes and apply them to the Text
if let font = attrs[.font] as? UIFont {
// this takes care of the majority of formatting - text size, font family,
// font weight, if it's italic, etc.
text = text.font[.init[font]]
}
if let color = attrs[.foregroundColor] as? UIColor {
text = text.foregroundColor[Color[color]]
}
if let kern = attrs[.kern] as? CGFloat {
text = text.kerning[kern]
}
if #available[iOS 14.0, *] {
if let tracking = attrs[.tracking] as? CGFloat {
text = text.tracking[tracking]
}
}
if let strikethroughStyle = attrs[.strikethroughStyle] as? NSNumber,
strikethroughStyle != 0 {
if let strikethroughColor = [attrs[.strikethroughColor] as? UIColor] {
text = text.strikethrough[true, color: Color[strikethroughColor]]
} else {
text = text.strikethrough[true]
}
}
if let underlineStyle = attrs[.underlineStyle] as? NSNumber,
underlineStyle != 0 {
if let underlineColor = [attrs[.underlineColor] as? UIColor] {
text = text.underline[true, color: Color[underlineColor]]
} else {
text = text.underline[true]
}
}
if let baselineOffset = attrs[.baselineOffset] as? NSNumber {
text = text.baselineOffset[CGFloat[baselineOffset.floatValue]]
}
// append the newly styled subtext to the rest of the text
self = self + text
}
}
}
Nếu bạn thử với các phiên bản
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 kết quả, bạn sẽ phát hiện ra rằng việc áp dụng công cụ sửa đổi chế độ xem var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
06 không hoạt động, tôi. evar concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0Mặt khác, các công cụ sửa đổi khác, chẳng hạn như
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
07, var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
08 hoặc var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
09 hoạt động như mong đợi. Đây có vẻ là sự không nhất quán nội bộ của SwiftUI, nhưng điều quan trọng cần lưu ý là phần tiếp theoHiển thị HTML trong văn bản
Swift có thể dễ dàng chuyển đổi một chuỗi HTML thành một
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 và sau đó chúng ta có thể đưa var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 đó vào trình khởi tạo từ phần trước. Điều duy nhất còn lại để sắp xếp là làm thế nào để đặt phông chữ cho toàn bộ văn bản HTML. Để làm điều này, chúng tôi sẽ sử dụng một mẹo nhỏ - chúng tôi sẽ nhúng chuỗi có định dạng HTML vào khung tài liệu HTML và chỉ định kiểu dáng của nó thông qua CSSvar concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
1Và đó là nó. Bạn có thể thử giải pháp với mã này
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
2Giải pháp không hiệu quảGói UILabel trong UIViewRepftimeable
Giải pháp này liên quan đến việc gói
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
12 trong var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
13 và sau đó gán chuỗi được gán cho thuộc tính var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
14 của nó. Một cái gì đó như thế nàyvar concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
6Vấn đề với phương pháp này là văn bản không chia thành nhiều dòng. Tôi đã sửa phần đó, nhưng chế độ xem vẫn không có kích thước phù hợp và có vấn đề về bố cục, đặc biệt là khi được gói trong
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
15. Tôi đã có thể giải quyết nó cho một trường hợp sử dụng cụ thể, nhưng không thể tìm ra giải pháp hoạt động trong bất kỳ bố cục nào, giống như giải pháp dựa trên var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0Sử dụng FlowLayoutView
Giải pháp này liên quan đến việc tạo chế độ xem tùy chỉnh cho mọi dải con chuỗi được phân bổ và sắp xếp chúng bằng Bố cục luồng. Bố cục Luồng sắp xếp thứ tự chế độ xem theo thứ tự trong một dòng và tự động xử lý ngắt dòng và ngắt dòng, vì vậy, đây có vẻ là ứng cử viên hoàn hảo. Ít nhất là cho đến khi SwiftUI quyết định can thiệp
Vì bất kỳ lý do gì,
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
17 của SwiftUI gặp sự cố khi bạn lưu trữ một var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 trong một var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
19. Hãy xem xét ví dụ nàyvar concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
1Nếu chạy mẫu này, bạn sẽ gặp một loạt lỗi
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
17, dẫn đến sự cốTôi đã cố gắng giải quyết vấn đề này theo nhiều cách
- Loại bỏ
21 và làm việc với hằng sốvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
0 đơn giảnvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
- Không lưu trữ
0 ở bất cứ đâu, chỉ chuyển nó vào trình khởi tạovar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
- Thậm chí không chuyển
0 cho chế độ xem mà thay vào đó chuyển trực tiếp mảng mụcvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
- Lưu trữ
0 bên ngoài toàn bộ phân cấp chế độ xem ứng dụngvar concatenatedText: Text { Text["My"] + Text[" text"].onTapGesture { } // nope, as onTapGesture doesn't return a Text }
Bây giờ, nếu bạn chuyển một chuỗi phân bổ được mã hóa cứng cho ứng dụng, nó sẽ không gặp sự cố. Tuy nhiên, nếu bạn định tính toán nó ở đâu đó trong mã [như chúng ta làm khi chuyển đổi chuỗi HTML] hoặc thậm chí đọc nó dưới dạng
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
26, thì nó sẽ gặp sự cố. Tôi nghi ngờ có một vấn đề sâu hơn đang hoạt động, đó cũng có thể là lý do tại sao Apple không cung cấp bất kỳ hỗ trợ SwiftUI gốc nào cho var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0May mắn thay, giải pháp
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0 luôn hoạt động đủ tốt, ít nhất là cho đến khi phiên bản tiếp theo của SwiftUI cung cấp cho chúng tôi sự hỗ trợ mà chúng tôi cần [EDIT. Sự hỗ trợ cuối cùng đã có ở đây trong SwiftUI 3. ]Giải pháp SwiftUI 3
SwiftUI 3 hỗ trợ chuỗi được phân bổ nguyên bản, cũng như hiển thị chúng trong những năm
var concatenatedText: Text {
Text["My"] + Text[" text"].onTapGesture {
} // nope, as onTapGesture doesn't return a Text
}
0, dẫn đến đoạn mã sau