iOS 一個比較完美的 Growing TextView

Jaly_xxx發表於2019-03-29

iOS 一個比較完美的 Growing TextView

文章緣由

現在都 2019 年了,App 中使用自動增高的輸入框已經很常見了,即時通訊的 Chat 介面、社交類 App 的評論功能都可以看到自增高輸入框。但寫出一個自增高輸入框容易,寫好難。現在市面上一些主流 App 的輸入框依然會有一些瑕疵,例如:文字擋住一部分、貼上大量文字時出現偏移,具體問題下面詳細分析。

現在 iOS 開發已經過了搭建 UI 和普通業務功能的初級階段,App 要想贏得使用者的青睞,除了 App 的功能、UI 設計,互動體驗的細節處理至關重要。一般使用者只要使用輸入框能正常輸入即可,90% 的使用者不會察覺輸入框的一些細節,但作為開發人員應該知道這些細節(bug)並做出處理。

主流 App 的輸入框之痛

貼上文字出現文字偏移

這個問題嚴格來說算 bug,畢竟貼上還是一個很常見的操作。

貼上文字出現文字偏移

擋住部分文字

一個輸入框要麼顯示 N 行文字、要麼顯示 N + 1行,如果顯示 N + 0.5 行就有點不可思議了。這個問題對 App 功能沒有任何影響,但這麼多 App 竟然都有這個問題而且非常普遍,是我始料未及的。測試了多個 App 後,只有QQ的輸入框做的最好,貼上、遮擋文字等問題根本不存在。

1_zhiHu_cover.PNG
weiBo_cover.PNG
touTiao_cover.PNG
jd_cover.PNG
weixin_cover.png

比較完美的輸入框

寫出一個自增高的輸入框還是比較容易的,大致過程就是給 textView 新增左、右、下/上、高度四個約束,然後監聽文字變化的通知,進而修改輸入框的高度。如果想寫好,就要花時間打磨了。我接下來主要說一下大家可能遇到的一些細節問題。

1、貼上文字,文字偏移

我的做法是繼承 UITextView 重寫 setBounds 方法,重新調整contentOffset

- (void)setBounds:(CGRect)bounds
{
    [super setBounds:bounds];
    //    NSLog(@"bounds:%@", NSStringFromCGRect(bounds));
    if (self.contentSize.height <= self.bounds.size.height + 1){
        self.contentOffset = CGPointZero; // Fix wrong contentOfset
    } else if (!self.tracking) {
        CGPoint offset = self.contentOffset;
        if (offset.y  > self.contentSize.height - bounds.size.height) {
            offset.y = self.contentSize.height - bounds.size.height;
            if (!self.decelerating && !self.tracking && !self.dragging) {
                self.contentOffset = offset;
            }
            // Fix wrong contentOfset when paster huge text
        }
    }
}
複製程式碼

2、文字離輸入框頂部間隙時大時小

正常情況下滾動輸入框的文字,文字可以滾動到控制元件頂部。而 QQ 的輸入框,不管怎麼滑動文字,文字和輸入框頂部都有一段固定間隔。

QQ_Top_margin

先了解輸入框的一個屬性textContainerInset,這個值預設是 (8, 0, 8, 0),就是說預設情況下文字和輸入框頂部有 8pt 的偏移,所以當文字輸入較多的時候文字向上滾動,那麼文字和控制元件頂部間隙會減小到 0。

實現QQ輸入框的效果,我能想到的方案是把textContainerInset全設定為 0(或者top/bottom為0),這樣文字就緊挨著輸入框,文字和輸入框頂部的固定間距就是 0 了。接著要給UITextView新增一個 containerViewcontainerView 豎向比 UITextView 高出一部分,從而實現 頂部/底部 的固定間距。

3、擋住部分文字

這個問題是因為 單行文字高度 * 最大行數 != 輸入框的最大高度,輸入框的最大高度可不是隨便設定的,先確定輸入框的font和最大行數,font.lineHeight * 行數就是輸入框的最大高度。這樣就不會出現文字擋住一部分的問題了

GrowTextView

接下來就是我自己寫的自增高輸入框了,目前沒發現什麼問題,至少沒有上面涉及的問題。

jl_txv_addLine.gif
jl_txv_paster.gif

[Reference]

相關文章