Attributed Text là một cơ chế của iOS SDK, được thể hiện bởi các lớp NSAttributedString và NSMutableAttributedString, cho phép áp dụng nhiều kiểu khác nhau cho các phần khác nhau của một chuỗi văn bản. Không giống như NSString thông thường, Attributed String không chỉ lưu trữ các ký tự mà còn lưu trữ một từ điển thuộc tính cho mỗi phạm vi: phông chữ, màu sắc, khoảng cách dòng, bóng và căn chỉnh. Theo Tài liệu Nhà phát triển Apple, Attributed String là nền tảng để hiển thị văn bản được định dạng trong UILabel, UITextView và UITextField. Đây là cách tiêu chuẩn để định kiểu văn bản mà không cần WebKit hoặc thư viện bên thứ ba.
Ý chính
NSAttributedString là một lớp của framework Foundation đại diện cho một chuỗi với một tập hợp các thuộc tính được đặt tên gắn với các phạm vi ký tự. Mỗi thuộc tính là một cặp khóa-giá trị: khóa được xác định bởi một hằng số (NSFontAttributeName, NSForegroundColorAttributeName) và giá trị là đối tượng tương ứng (UIFont, UIColor). Các thuộc tính được áp dụng cho một phạm vi ký tự thông qua NSRange.
Lớp này có sẵn trên tất cả các nền tảng Apple: iOS (2.0+), macOS, tvOS, watchOS. NSAttributedString là bất biến — sau khi được tạo, các thuộc tính của nó được cố định. Để thay đổi động, người ta sử dụng NSMutableAttributedString, kế thừa từ NSAttributedString và thêm các phương thức setAttributes, addAttributes, addAttribute, removeAttribute.
NSString là một chuỗi ký tự đơn giản không có thông tin định kiểu. Bất kỳ văn bản nào được truyền vào UILabel qua text đều được hiển thị với một phông chữ, màu sắc và kích thước duy nhất. NSAttributedString, được truyền qua attributedText, cho phép mỗi ký tự có tập thuộc tính riêng. UILabel, UITextView và UITextField tự động nhận dạng NSAttributedString và hiển thị văn bản theo các thuộc tính của nó.
Bên trong, NSAttributedString lưu trữ một NSString với văn bản và một mảng các phạm vi thuộc tính. Mỗi phạm vi được đại diện bởi một cấu trúc NSRange và một từ điển thuộc tính. Trong quá trình hiển thị, hệ thống duyệt qua các phạm vi và áp dụng các thuộc tính tương ứng cho từng phần. Hiệu quả phụ thuộc vào số lượng chuyển đổi thuộc tính — các thay đổi thường xuyên trên các phần ngắn sẽ làm tăng thời gian hiển thị.
Các thuộc tính NSAttributedString là các hằng số được xác định trong UIKit (iOS) và AppKit (macOS), mỗi thuộc tính tương ứng với một khía cạnh cụ thể của việc định dạng trực quan văn bản. Tất cả các thuộc tính đều là chuỗi NSAttributedString.Key và giá trị của chúng là các đối tượng của các lớp cụ thể. Các thuộc tính được chia thành cấp độ ký tự (ảnh hưởng đến các ký tự) và cấp độ đoạn văn (ảnh hưởng đến các đoạn văn).
Các thuộc tính cấp độ ký tự bao gồm phông chữ (NSFontAttributeName), màu văn bản (NSForegroundColorAttributeName), màu nền (NSBackgroundColorAttributeName), gạch chân (NSUnderlineStyleAttributeName), gạch ngang (NSStrikethroughStyleAttributeName), bóng (NSShadowAttributeName). Các thuộc tính cấp độ đoạn văn được thiết lập thông qua NSParagraphStyleAttributeName, kiểm soát căn chỉnh, thụt lề, khoảng cách dòng và tab.
NSLinkAttributeName tạo một liên kết có thể nhấp được trong văn bản: giá trị là một URL hoặc chuỗi. UITextView tự động xử lý các liên kết này nếu tương tác được bật. NSAttachmentAttributeName cho phép nhúng một NSTextAttachment — một hình ảnh bên trong văn bản được hiển thị dưới dạng phần tử nội dòng. Điều này được sử dụng để tạo văn bản với các biểu tượng, biểu tượng cảm xúc hoặc chế độ xem tùy chỉnh trong một chuỗi.
Mỗi thuộc tính NSAttributedString có một giá trị được phân loại nghiêm ngặt. Hãy xem xét các thuộc tính được sử dụng phổ biến nhất trong phát triển iOS. Phông chữ được thiết lập thông qua một đối tượng UIFont, màu sắc thông qua UIColor, khoảng cách dòng thông qua NSMutableParagraphStyle, cho phép cấu hình căn chỉnh, thụt lề và khoảng cách trong một đối tượng duy nhất.
| Khóa thuộc tính | Loại giá trị | Mục đích |
|---|---|---|
| NSFontAttributeName | UIFont | Phông chữ văn bản |
| NSForegroundColorAttributeName | UIColor | Màu văn bản |
| NSBackgroundColorAttributeName | UIColor | Màu nền phía sau văn bản |
| NSUnderlineStyleAttributeName | NSNumber (Int) | Kiểu gạch chân |
| NSParagraphStyleAttributeName | NSParagraphStyle | Cài đặt đoạn văn |
| NSKernAttributeName | NSNumber (Float) | Khoảng cách chữ (kerning) |
NSParagraphStyle là một container cho các thuộc tính đoạn văn: alignment, lineSpacing, paragraphSpacing, firstLineHeadIndent, lineBreakMode, minimumLineHeight và các thuộc tính khác. Để sửa đổi các tham số này, một NSMutableParagraphStyle được tạo, các thuộc tính mong muốn được thiết lập và đối tượng được truyền dưới dạng giá trị của thuộc tính NSParagraphStyleAttributeName. Đây là cách duy nhất để kiểm soát khoảng cách dòng trong NSAttributedString.
NSShadow cho phép thêm bóng vào văn bản: các tham số shadowOffset, shadowBlurRadius, shadowColor thiết lập độ dịch chuyển, độ mờ và màu của bóng. Các thuộc tính gạch chân và gạch ngang chấp nhận các kết hợp kiểu: NSUnderlineStyle.single, .double, .thick, .patternDash, .patternDot. Để kiểm soát chính xác độ dày và màu sắc của đường kẻ, người ta sử dụng NSUnderlineColorAttributeName và NSStrikethroughColorAttributeName.
Việc tạo NSAttributedString trong Swift được thực hiện thông qua một bộ khởi tạo với văn bản và một từ điển thuộc tính, hoặc thông qua NSMutableAttributedString với việc áp dụng kiểu từng bước. Cách tiếp cận cơ bản là xác định một từ điển thuộc tính cho toàn bộ văn bản, sau đó thêm hoặc sửa đổi thuộc tính cho các phạm vi cụ thể.
Một ví dụ đơn giản — thiết lập phông chữ, màu sắc và căn chỉnh cho toàn bộ chuỗi. Từ điển thuộc tính được truyền vào bộ khởi tạo NSAttributedString. Các khóa của từ điển là các hằng số NSAttributedString.Key, các giá trị là các đối tượng UIKit tương ứng. Đây là trường hợp cơ bản khi toàn bộ văn bản được định dạng đồng nhất.
let attributes: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: 16),
.foregroundColor: UIColor.darkGray,
.paragraphStyle: let style = NSMutableParagraphStyle()
style.alignment = .center
style.lineSpacing = 4
return style
]
let attributedString = NSAttributedString(
string: "Hello world",
attributes: attributes
)
label.attributedText = attributedString
Văn bản sẽ được hiển thị với systemFont 16, màu xám đậm, căn giữa và khoảng cách dòng 4pt. Cách tiếp cận này thuận tiện cho các tiêu đề tĩnh và nút bấm.
NSMutableAttributedString cho phép áp dụng các kiểu khác nhau cho các phần khác nhau của văn bản. Phương thức addAttribute thêm một thuộc tính đơn lẻ vào một phạm vi, addAttributes thêm một từ điển thuộc tính. Phương thức setAttributes thay thế tất cả các thuộc tính hiện có trong một phạm vi bằng các thuộc tính mới. Đây là công cụ chính để tạo văn bản có đánh dấu.
let text = "Price: 1999 rubles"
let attributed = NSMutableAttributedString(string: text)
attributed.addAttribute(.foregroundColor,
value: UIColor.green, range: NSRange(location: 6, length: 4))
attributed.addAttribute(.font,
value: UIFont.boldSystemFont(ofSize: 20), range: NSRange(location: 6, length: 4))
label.attributedText = attributed
Từ “1999” sẽ có màu xanh lá cây và in đậm, phần còn lại của văn bản sẽ là tiêu chuẩn. NSRange được tính toán thủ công — điều quan trọng là phải đếm chính xác độ dài theo ký tự, đặc biệt là khi làm việc với biểu tượng cảm xúc và các ký tự Unicode phức hợp.
NSMutableAttributedString cung cấp các phương thức để thay đổi động văn bản và thuộc tính: append, insert, replace, delete, setAttributes, addAttribute, removeAttribute, enumerateAttributes. Điều này cho phép xây dựng văn bản từ các nguồn khác nhau, kết hợp các kiểu và phản hồi các sự kiện giao diện.
Không giống như NSAttributedString bất biến, phiên bản có thể thay đổi hỗ trợ việc thay đổi nội dung mà không cần tạo đối tượng mới. Điều này rất quan trọng đối với các trình soạn thảo văn bản, trò chuyện và biểu mừu nơi người dùng có thể chỉnh sửa văn bản trong khi các kiểu phải được giữ nguyên.
Trong các ứng dụng nhắn tin, mỗi tin nhắn chứa tên người dùng (chữ đậm), nội dung tin nhắn (thường), thời gian (màu xám). NSMutableAttributedString cho phép xây dựng chuỗi như vậy trong một lần bằng cách thêm các phần theo thứ tự mong muốn với các thuộc tính tương ứng.
let result = NSMutableAttributedString()
let name = NSAttributedString(string: "Anna: ",
attributes: [.font: UIFont.boldSystemFont(ofSize: 15)])
let message = NSAttributedString(string: "Hello, how are you?",
attributes: [.font: UIFont.systemFont(ofSize: 15)])
let time = NSAttributedString(string: " 12:30",
attributes: [.foregroundColor: UIColor.gray])
result.append(name)
result.append(message)
result.append(time)
label.attributedText = result
Kết quả là một chuỗi duy nhất với ba phần được định kiểu. Append tự động tính NSRange, không cần tính toán vị trí thủ công. Cách tiếp cận này có thể mở rộng cho bất kỳ số lượng đoạn nào.
Phương thức enumerateAttributes(in:options:using:) duyệt qua tất cả các phạm vi thuộc tính trong khoảng được chỉ định. Điều này hữu ích cho việc phân tích định dạng: tìm tất cả các liên kết, thay đổi màu của các thuộc tính cụ thể hoặc xuất văn bản sang HTML. Closure nhận được từ điển thuộc tính và NSRange của phần hiện tại.
Tất cả các thành phần UI chính để hiển thị văn bản trong UIKit đều hỗ trợ NSAttributedString thông qua thuộc tính attributedText. UILabel hiển thị văn bản được định kiểu tĩnh, UITextView hỗ trợ chỉnh sửa và liên kết, UITextField chấp nhận các thuộc tính riêng cho văn bản gợi ý và văn bản đã nhập.
UILabel là thành phần nhẹ nhất để hiển thị văn bản được định kiểu. Nó hỗ trợ tất cả các thuộc tính cấp độ ký tự nhưng không xử lý các liên kết có thể nhấp được một cách tự động (để làm điều đó cần UITextView). UILabel lý tưởng cho các tiêu đề, nhãn và văn bản ngắn được định dạng.
UITextView xử lý NSLinkAttributeName và hiển thị các liên kết dưới dạng các phần tử tương tác. Để bật chức năng này, hãy đặt isSelectable = true và isEditable = false. Khi nhấp vào một liên kết, ủy quyền sẽ nhận được lời gọi textView(_:shouldInteractWith:in:interaction:). UITextView cũng hỗ trợ NSTextAttachment cho hình ảnh bên trong văn bản.
let text = "Details on developer.apple.com"
let attributed = NSMutableAttributedString(string: text)
attributed.addAttribute(.link,
value: URL(string: "https://developer.apple.com")!,
range: NSRange(location: 0, length: text.count))
textView.attributedText = attributed
textView.isSelectable = true
textView.isEditable = false
Sau khi đặt isSelectable và isEditable, vùng văn bản hoạt động như một khối văn bản tĩnh, nhưng các liên kết vẫn hoạt động. UITextViewDelegate kiểm soát hành vi khi nhấp.
Core Text là một framework cấp thấp của Apple để hiển thị văn bản, hoạt động trực tiếp với NSAttributedString. Không giống như UIKit, Core Text không sử dụng NSAttributedString trực tiếp như một đối tượng hiển thị — thay vào đó, nó chuyển đổi nó thành CTFramesetter, sau đó thành CTFrame và hiển thị nó trong một ngữ cảnh Core Graphics. Điều này mang lại khả năng kiểm soát hoàn toàn đối với bố cục dòng và glyph.
Việc sử dụng Core Text là hợp lý cho các bố cục văn bản tùy chỉnh: cột, bao quanh hình ảnh, xoay văn bản, ngắt dòng không tiêu chuẩn. NSMutableParagraphStyle của Core Text bao gồm các thuộc tính không có trong UIKit: kCTParagraphStyleSpecifierMaximumLineSpacing, kCTParagraphStyleSpecifierLineBreakMode với các chế độ bổ sung.
NSAttributedString chuyển đổi liền mạch giữa UIKit và Core Text, vì cả hai framework đều làm việc với cùng một loại. Các thuộc tính UIKit (NSFontAttributeName, NSForegroundColorAttributeName) được Core Text tự động nhận dạng và ngược lại — các thuộc tính Core Text (kCTFontAttributeName) được UIKit đọc. Điều này cho phép sử dụng UIKit cho các tác vụ đơn giản và Core Text cho việc hiển thị tùy chỉnh trên cùng một đối tượng NSAttributedString.
Câu hỏi thường gặp
NSString chỉ lưu trữ văn bản mà không có thông tin định kiểu. NSAttributedString bổ sung văn bản với một từ điển thuộc tính cho mỗi phạm vi ký tự. Khi được truyền vào UILabel qua thuộc tính text, NSString được hiển thị dưới dạng văn bản thuần. Khi NSAttributedString được truyền qua attributedText, tất cả các thuộc tính đều được áp dụng: các phông chữ, màu sắc và khoảng cách khác nhau trong một chuỗi duy nhất.
Sử dụng phương thức addAttributes(_:range:) với một từ điển thuộc tính: addAttributes([.font: font, .foregroundColor: color], range: range). Để thêm hoặc thay đổi một thuộc tính đơn lẻ, hãy sử dụng addAttribute(_:value:range:). Phương thức setAttributes thay thế tất cả các thuộc tính hiện có trong phạm vi bằng các thuộc tính được cung cấp.
Tạo một NSMutableParagraphStyle, đặt thuộc tính lineSpacing, sau đó truyền nó dưới dạng giá trị của thuộc tính NSParagraphStyleAttributeName. Để kiểm soát hoàn toàn, minimumLineHeight, maximumLineHeight, paragraphSpacing, lineBreakMode và alignment cũng có sẵn. ParagraphStyle là cách duy nhất để kiểm soát khoảng cách dòng.
Có, SwiftUI hỗ trợ NSAttributedString thông qua Text(attributedString:) trong iOS 15+. Ở các phiên bản cũ hơn, hãy sử dụng UIViewRepresentable với UILabel hoặc UITextView. SwiftUI cũng cung cấp kiểu AttributedString riêng (SwiftUI, không phải Foundation) để định dạng khai báo với cú pháp giống Markdown.
Sử dụng phương thức boundingRect(with:options:context:), phương thức này trả về CGRect cần thiết để hiển thị chuỗi với các thuộc tính đã cho. Tham số options: [.usesLineFragmentOrigin, .usesFontLeading] tính đến khoảng cách dòng và số liệu phông chữ. Đối với UILabel với số lượng dòng giới hạn, hãy sử dụng sizeThatFits.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm