背景:前些天忽然想作一個筆記本功能,一開始,以爲挺簡單的呀,一個UITextView,網絡緩存也不幹了,直接本地NSUserDefault存儲,而後完事了,美工,弄幾張好看的圖片,加幾個動畫,也就這樣了。接着,按照慣例,查看已有的備忘錄軟件,其app store知名的軟件:Weiconote等。
才發現沒那麼簡單。這裏先不考慮圖文混排的問題,首先面對的就是:鍵盤隱藏以後,文字的位置移動問題啦。細心的體驗後發現:系統的備忘錄,已經一些作得好的軟件,都會進行一些處理,例如:
1.當我編輯的時候,光標應該是一直不被鍵盤高度隱藏的纔對。
2.我在文字中間進行編輯的話,編輯完成隱藏鍵盤,UITextView的文字位置這個時候應該是我剛纔編輯的部分。
因而開始寫:
1. 查看了暴露出來的API,屬性,不被鍵盤高度遮住,frame,contentInset,textContainerInset,均可以作到。
根據鍵盤的自己的 notification ,或者UITextView delegate ,能輕易作到。
部分代碼:
2.解決方法比較麻煩,查看了全部的api,就只有父類的這個api有用的:
- (void)scrollRectToVisible:(CGRect)rect animated:(bool)animate;
接下來的問題來了,根據光標當前的位置高度,手動計算屬性,而後,獲取要移動的位置,進行跳轉。由於默認的狀況是:只要鍵盤隱藏了,會自動跳到UITextView的最前面的。至於獲取光標位置,以及計算移動的位置的問題,能夠很快查到資料的。
事實上,問題2最好的解決方式是:本身根據TextKit封裝一個UITextView...
上面的背景就是這樣了,解決了問題後,發現,爲何不順便把圖文混排的問題也一次性解決了。一直以來,富文本編輯都是沒有深刻的,以前也是直接用的開源代碼,或者UIWebView,老是內心不踏實,卡頓的狀況偶爾發生,很是不開心。因而,接下來,纔是今天主要想分享的東西了:富文本問題。
關鍵詞:coretext textkit
第三方庫分析:DTCoretext M80AttributedLabel FastText EGOText
官網參考資料:
TextKit能讓咱們本身手動管理字體的顏色,樣式(Text Layout),觸摸事件,排版,圖文的混排規則。
Textkit是基於CoreText的,與WebKit是兩個不一樣的分支。我主要查看的也是TextKit,用coreText太麻煩了。而它們之間的關係邏輯以下圖所示:
具體到顯示上,渲染的流程是先從存儲的NSTextStorage中獲取text以及它的attributes,再通過NSLayoutManager佈局顯示容器包括形狀,大小等,再通過NSTextContainer佈局呈具體的顯示,最後展現在UI上。渲染和實現的流程:
這裏注意描述:By using multiple text containers, each with an associated text view, more complex layout arrangements are possible.
到了這裏,基本心理有個譜了。大體清楚這個邏輯了。接下來細分一下:
a.這裏,先說一下具體到文本的樣式,先上一張官方的說明圖:
咱們能夠設置文字的字體各類細節,段落排版,對其方式,縮進規則等。
關於樣式:自帶有六種,經過UIFont直接設置:
b.而後開始寫圖文混排了
參考代碼:
NSMutableAttributedString *string;
經過插入NSTextAttachment設置image對象,其中NSTextAttachment能夠繼承重寫方法實現修改插入內容大小。
這裏實際上就是找到一個NSRange位置而後插入圖片,常見的插入表情。而後表情轉換成字符串輸出出來。字符串再轉換成圖片輸出。
咱們能夠遍歷輸入的字符串,經過NSTextStorage設置字符串的字體,進行自定義規則處理等,例如,##進行標題大寫,高亮等。
經過NSLayoutManager來設置輸入文本內容行數,文本段的縮進規則,行間距等。
經過NSTextContainer來設置文字的佈局方式,例如圖文環繞方式,等。
基本的Text Kit 功能這樣子了,基本能知足富文本的全部要求了。本身排版,按照本身項目的業務邏輯作一些事情。
最後仍是附加開頭提到的一些庫,閱讀好的源碼分析比什麼都好:
M80AttributedLabel:基本的TextKit封裝,代碼易懂,例子很是好用簡單,試過效果挺好,須要作一些性能優化處理。
DTCoretext: CoreText封裝,解析正規的HTML源碼,展現出來成富文本,很是強大,若是安卓端和IOS使用同一套接口的時候,就很是好用了。兼容問題。
部分參考連接:
⚠:DTCoreText 運行的時候有提示須要先進行:git submodule init update