Cell 動態行高文字顯示不全問題探索
阿新 • • 發佈:2021-02-07
[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