1. 程式人生 > >Cell 動態行高文字顯示不全問題探索

Cell 動態行高文字顯示不全問題探索

[toc] ## 問題概述 使用的是”預估行高+自動佈局“的方法實現動態行高(適用於 iOS7.0 以後系統)。 預估行高: ```swift self.gTV.estimatedRowHeight = 90; self.gTV.rowHeight = UITableViewAutomaticDimension; ``` 自動佈局,又叫 autolayout,為了使文字可以多行顯示,需要保證如下設定: * 設定 label 的 numberoflines 為 0 * 對 label 進行上左下右的完整約束 在專案實現過程中,遇到了文字內容被截斷最後一行一小部分,無法完全顯示的問題。 為了復現專案中遇到的此問題並找到原因,做了如下嘗試: ## 一、新建工程 新建工程測試,cell上下約束完備,底部高度約束 contentLblBtmCon 為>=9,優先順序預設1000。發現預估行高是正常的。 效果如下: ![Simulator Screen Shot - iPhone SE (1st generation) - 2021-02-07 at 15.27.32](https://tva1.sinaimg.cn/large/008eGmZEgy1gnf049tmmuj30hs0vkq4x.jpg) ## 二、嘗試復現問題 隱藏系統cell分割線:`self.gTV.separatorStyle = UITableViewCellSeparatorStyleNone;` 同時,在自定義cell中重寫 setFrame方法實現分割線效果,結果發現文字開始顯示不全了! ```swift - (void)setFrame:(CGRect)frame{ frame.size.height -= 8; [super setFrame:frame]; } ``` 約束報錯如下: ```swift 2021-02-07 14:56:37.416314+0800 DynamicCellHeightTest[60202:8764494] [LayoutConstraints] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. ( "", "= 20.5 (active)>", "", "", "=9)-| (active, names: '|':UITableViewCellContentView:0x7f898d0061f0 )>", "" ) Will attempt to recover by breaking constraint = 20.5 (active)> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in
may also be helpful. ``` 通過 log 可知,內容 label 的高度約束被捨棄了,因此會出現內容顯示不全的問題。模擬器執行效果: ![Simulator Screen Shot - iPhone SE (1st generation) - 2021-02-07 at 15.28.30](https://tva1.sinaimg.cn/large/008eGmZEgy1gnf055laffj30hs0vk0up.jpg) ## 嘗試解決 ### 修改contentLblBtmCon優先順序為High(750) ![截圖2021-02-07 下午3.14.06](https://tva1.sinaimg.cn/large/008eGmZEgy1gnezq6uslfj31di0f0qa3.jpg) 結果還是不太行: ![Simulator Screen Shot - iPhone SE (1st generation) - 2021-02-07 at 15.29.15](https://tva1.sinaimg.cn/large/008eGmZEgy1gnf05zkrbej30hs0vk0up.jpg) ### 修改contentLblBtmCon優先順序為Low(250) ![截圖2021-02-07 下午3.18.00](https://tva1.sinaimg.cn/large/008eGmZEgy1gnf07t7i34j31cq0dgwjg.jpg) 效果如下: ![Simulator Screen Shot - iPhone SE (1st generation) - 2021-02-07 at 15.26.05](https://tva1.sinaimg.cn/large/008eGmZEgy1gnf02q565dj30hs0vktar.jpg) 可見,此時內容可以顯示全了,Xcode 也不報錯了。但是內容距離 cell 底部的距離太小了,並沒有大於 9。猜測:這個底部約束因為優先順序是Low,所以被系統捨棄,使得內容可以顯示完整,同時導致內容距離 cell 底部的距離太小。 但是,當我嘗試設定底部約束的為 >
= 9+8=17,再執行,居然就是我想要的效果: ![Simulator Screen Shot - iPhone SE (1st generation) - 2021-02-07 at 15.40.45](https://tva1.sinaimg.cn/large/008eGmZEgy1gnf0ja40hkj30hs0vkwgc.jpg) ![Simulator Screen Shot - iPhone SE (1st generation) - 2021-02-07 at 15.40.53](https://tva1.sinaimg.cn/large/008eGmZEgy1gnf0jfcudsj30hs0vkwge.jpg) 分析:系統先在 setFrame 生效之前,對 cell 內的上下所有約束進行行高預估。計算拿出結果後快取。在 cell 顯示之前,setFrame 生效,此時,cell 在之前預估行高的基礎上,根據約束重新佈局,捨棄了內容 label 的高度約束,導致內容顯示不全。 當我們把底部約束的優先順序降低到 Low 時,cell 在之前預估行高的基礎上,根據約束重新佈局,捨棄的就是低優先順序的底部約束了,因此才能看到低優先順序底部約束開始生效,後來因 setFrame 減小了高度,導致底部間隔變小的效果。此時,我們**將計就計**,把底部約束增加 cell 間隔高度(8),即可得出我們想要的效果! ## 小結 重寫 cell 的 setFrame 方法改變 cell 高度來實現分割線效果時,可能導致多行 label 顯示不全,此時,可以通過降低底部約束優先順序為 `Low` + 增加底部約束的值(cell 間距),來實現想要的文字多行顯示效果。 ## 其他解決思路 當然,為了實現行分割線效果,我們也可以在自定義 cell 的底部手動新增一個 UIView 子檢視,高度設定為 cell 間隔高度,顏色改為與 UITableview 背景色一致(與 cell 背景色不同),也能達到同樣的效果。這種方法就不會因為重寫 cell 的 setFrame 方法導致多行文字顯示不全了。但是,當 cell 有選中效果或左滑刪除效果時,相關效果就不是很好了,因為分隔線 View 屬於 cell 的一部分被一起選中或移動,看起來效果有點不太好。 好了,這次的探索就到這裡了。下面附上測試用的原始碼,歡迎 star!3Q! ## 原始碼地址 [OCDailyTests/DynamicCellHeightTest](https://github.com/Dast1Woop/OCDail