2013-05-03 39 views
39

Tôi có câu hỏi về các góc được làm tròn và màu nền văn bản cho tùy chỉnh UIView.Màu nền NSAttributedString và các góc bo tròn

Về cơ bản, tôi cần phải đạt được một hiệu ứng như thế này (hình ảnh kèm theo - chú ý đến các góc tròn trên một mặt) trong một UIView tùy chỉnh: Background highlight

Tôi đang nghĩ đến phương pháp này để sử dụng là:

  • Sử dụng Văn bản cốt lõi để chạy glyph.
  • Kiểm tra phạm vi đánh dấu.
  • Nếu lần chạy hiện tại nằm trong phạm vi đánh dấu, hãy vẽ hình chữ nhật nền với các góc được làm tròn và màu tô màu mong muốn trước khi vẽ đường chạy glyph.
  • Vẽ đường chạy glyph.

Tuy nhiên, tôi không chắc đây có phải là giải pháp duy nhất (hay cho vấn đề đó, dù đây là giải pháp hiệu quả nhất).

Sử dụng UIWebView không phải là một tùy chọn, vì vậy tôi phải làm điều đó trong tùy chỉnh UIView.

Câu hỏi của tôi là, đây có phải là cách tiếp cận tốt nhất để sử dụng không và tôi có đi đúng hướng không? Hay tôi bỏ lỡ một điều gì đó quan trọng hoặc đi sai đường?

+0

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

+0

Xin lỗi, vâng. Có thể thử textView-> selectedRange và '- [UITextInput selectionRectsForRange:]' – nielsbot

+0

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

Trả lời

47

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:

  1. Tạo một lớp con tùy chỉnh UIView.
  2. Có tài sản để chấp nhận số NSAttributedString.
  3. Tạo CTFramesetter bằng cách sử dụng ví dụ NSAttributedString đó.
  4. Ghi đè phương thức drawRect:
  5. Tạo CTFrame ví dụ từ CTFramesetter.
    1. 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.
  6. Lấy ngữ cảnh đồ họa hiện tại và lật hệ tọa độ văn bản.
  7. Sử dụng CTFrameGetLines(...), nhận tất cả các dòng trong CTFrame bạn vừa tạo.
  8. Sử dụng CTFrameGetLineOrigins(...), nhận tất cả các xuất xứ của dòng cho CTFrame.
  9. Bắt đầu một for loop - cho mỗi dòng trong mảng của CTLine ...
  10. Đặt vị trí văn bản để bắt đầu sử dụng CTLineCGContextSetTextPosition(...).
  11. Sử dụng CTLineGetGlyphRuns(...) nhận tất cả các lần chạy Glyph (CTRunRef) từ CTLine.
  12. Bắt đầu một số khác for loop - cho mỗi glyphRun trong mảng CTRun ...
  13. Lấy phạm vi chạy bằng cách sử dụng CTRunGetStringRange(...).
  14. Nhận giới hạn kiểu chữ bằng cách sử dụng CTRunGetTypographicBounds(...).
  15. Lấy x bù đắp cho lần chạy sử dụng CTLineGetOffsetForStringIndex(...).
  16. 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.
    1. 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.
  17. Lấy thuộc tính cho chạy bằng cách sử dụng CTRunGetAttributes(...).
  18. 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.
  19. 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ẽ.
  20. 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.
  21. 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).
  22. 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ể.
    1. 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.
  23. 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(...).
  24. 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

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!

+1

Bạn có một số mã mẫu mà bạn có thể chia sẻ? – ddiego

+0

Xin chào. Thông thường, tôi muốn dán mã tôi đã sử dụng cho bất kỳ triển khai cụ thể nào. Thật không may, tôi không thể làm tương tự cho trường hợp cụ thể này. :(Xin lỗi về điều đó. – codeBearer

+0

Tôi có thể đánh giá cao điều đó.Nhưng nếu bạn thay đổi ý định và muốn đăng một vài đoạn trích, điều đó sẽ hữu ích. Tôi không thể làm theo hướng dẫn của bạn – ddiego

Các vấn đề liên quan