Tôi đã đạt được hiệu quả trên, vì vậy tôi nghĩ rằng tôi sẽ đăng câu trả lời cho cùng một câu trả lời.
Nếu có ai có bất kỳ đề xuất nào về việc làm cho điều này hiệu quả hơn, vui lòng đóng góp. Tôi chắc chắn sẽ đánh dấu câu trả lời của bạn là câu trả lời chính xác. :)
Để thực hiện việc này, bạn sẽ cần phải thêm "thuộc tính tùy chỉnh" vào NSAttributedString
.
Về cơ bản, điều đó có nghĩa là bạn có thể thêm bất kỳ cặp khóa-giá trị nào, miễn là nó là thứ bạn có thể thêm vào một phiên bản NSDictionary
. Nếu hệ thống không nhận ra thuộc tính đó, nó không làm gì cả. Bạn là nhà phát triển, tùy thuộc vào bạn, để cung cấp triển khai và hành vi tùy chỉnh cho thuộc tính đó.
Vì mục đích của câu trả lời này, giả sử tôi đã thêm thuộc tính tùy chỉnh được gọi là: @"MyRoundedBackgroundColor"
với giá trị là [UIColor greenColor]
.
Để biết các bước tiếp theo, bạn sẽ cần phải có hiểu biết cơ bản về cách thực hiện các công việc CoreText
. Kiểm tra Apple's Core Text Programming Guide để hiểu một khung/line/glyph chạy/Glyph là những gì vv
Vì vậy, đây là những bước sau:
- Tạo một lớp con tùy chỉnh UIView.
- Có tài sản để chấp nhận số
NSAttributedString
.
- Tạo
CTFramesetter
bằng cách sử dụng ví dụ NSAttributedString
đó.
- Ghi đè phương thức
drawRect:
- Tạo
CTFrame
ví dụ từ CTFramesetter
.
- Bạn cần cung cấp
CGPathRef
để tạo CTFrame
. Làm cho rằng CGPath
giống với khung mà bạn muốn vẽ văn bản.
- Lấy ngữ cảnh đồ họa hiện tại và lật hệ tọa độ văn bản.
- Sử dụng
CTFrameGetLines(...)
, nhận tất cả các dòng trong CTFrame
bạn vừa tạo.
- Sử dụng
CTFrameGetLineOrigins(...)
, nhận tất cả các xuất xứ của dòng cho CTFrame
.
- Bắt đầu một
for loop
- cho mỗi dòng trong mảng của CTLine
...
- Đặt vị trí văn bản để bắt đầu sử dụng
CTLine
CGContextSetTextPosition(...)
.
- Sử dụng
CTLineGetGlyphRuns(...)
nhận tất cả các lần chạy Glyph (CTRunRef
) từ CTLine
.
- Bắt đầu một số khác
for loop
- cho mỗi glyphRun trong mảng CTRun
...
- Lấy phạm vi chạy bằng cách sử dụng
CTRunGetStringRange(...)
.
- Nhận giới hạn kiểu chữ bằng cách sử dụng
CTRunGetTypographicBounds(...)
.
- Lấy x bù đắp cho lần chạy sử dụng
CTLineGetOffsetForStringIndex(...)
.
- Tính trực tiếp giới hạn (hãy gọi nó là
runBounds
) bằng cách sử dụng các giá trị được trả lại từ các chức năng nói trên.
- Hãy nhớ -
CTRunGetTypographicBounds(...)
yêu cầu con trỏ đến các biến để lưu trữ "tăng" và "gốc" của văn bản. Bạn cần phải thêm chúng để có được chiều cao chạy.
- Lấy thuộc tính cho chạy bằng cách sử dụng
CTRunGetAttributes(...)
.
- Kiểm tra xem từ điển thuộc tính có chứa thuộc tính của bạn hay không.
- Nếu thuộc tính của bạn tồn tại, hãy tính các giới hạn của hình chữ nhật cần được vẽ.
- Văn bản chính có dòng xuất phát tại đường cơ sở. Chúng ta cần vẽ từ điểm thấp nhất của văn bản đến điểm trên cùng. Vì vậy, chúng ta cần phải điều chỉnh cho gốc.
- Vì vậy, trừ gốc từ đường biên giới hạn mà chúng tôi đã tính ở bước 16 (
runBounds
).
- Bây giờ chúng ta có
runBounds
, chúng ta biết khu vực nào chúng ta muốn vẽ - bây giờ chúng ta có thể sử dụng bất kỳ phương pháp CoreGraphis
/UIBezierPath
nào để vẽ và lấp đầy trực tràng với các góc được làm tròn cụ thể.
UIBezierPath
có phương thức lớp tiện lợi gọi là bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
cho phép bạn làm tròn các góc cụ thể. Bạn chỉ định các góc sử dụng bit mask trong tham số thứ 2.
- Bây giờ bạn đã điền trực tiếp, chỉ cần vẽ đường chạy bằng glyph sử dụng
CTRunDraw(...)
.
- Kỷ niệm chiến thắng vì đã tạo thuộc tính tùy chỉnh của bạn - uống bia hoặc gì đó!: D
Liên quan đến việc phát hiện phạm vi thuộc tính kéo dài qua nhiều lần chạy, bạn có thể nhận được toàn bộ phạm vi hiệu quả thuộc tính tùy chỉnh khi lần chạy đầu tiên gặp thuộc tính. Nếu bạn thấy rằng độ dài của phạm vi hiệu quả tối đa của thuộc tính của bạn lớn hơn thời gian chạy của bạn, bạn cần phải vẽ các góc sắc nét ở bên phải (cho tập lệnh từ trái sang phải). Nhiều môn toán hơn sẽ cho phép bạn phát hiện phong cách góc đánh dấu cho dòng tiếp theo. :)
Đính kèm là ảnh chụp màn hình của hiệu ứng. Hộp trên cùng là một tiêu chuẩn UITextView
, mà tôi đã thiết lập các attributedText. Hộp ở phía dưới là hộp đã được triển khai bằng các bước trên. Chuỗi được gán tương tự đã được đặt cho cả hai textViews. ![custom attribute with rounded corners](https://i.stack.imgur.com/XJY5s.png)
Một lần nữa, nếu có cách tiếp cận tốt hơn phương pháp tôi đã sử dụng, vui lòng cho tôi biết! : D
Hy vọng điều này sẽ giúp cộng đồng. :)
Chúc mừng!
Xin chào. Cám ơn bạn đã góp ý. :) Tôi không nghĩ rằng NSLayoutManager có sẵn trong iOS6. iOS6 có CTFrameSetter, sẽ cung cấp cho tôi CTFrame -> CTLine -> CTGlyph. Nếu tôi nhận được phạm vi của văn bản được yêu cầu một cách chính xác, tôi có thể vẽ hình chữ nhật và sau đó nói cho CTFrame vẽ chính nó. – codeBearer
Xin lỗi, vâng. Có thể thử textView-> selectedRange và '- [UITextInput selectionRectsForRange:]' – nielsbot
Bạn có thể? 1. Tạo nhãn trong suốt 2. Nhận khung của phạm vi văn bản chuỗi con (http://stackoverflow.com/questions/19417776/how-do-i-locate-the-cgrect-for-a-substring-of -ext-in-a-uilabel) 3. Thêm một subview rect tròn phía sau nhãn – Robert