一次cell阴影设置引出的问题

前言

自己在完成一次业务功能开发时,给cell上的视图设置阴影效果,出现了一个奇怪的问题,就是上滑tableview的时候阴影效果展示正常,下滑的时候阴影效果就不正常。就正常的添加阴影效果,出现这个问题让我很困惑,于是各种谷歌百度,尝试各种方案,还是未能解决。

项目在用欧阳大哥开源的一个布局框架MyLinearLayout,熟练这个框架之后,发现布局的时候,要比使用Masonry要快,能快速的搭建一些复杂多样布局,极大提高开发效率。而我所写的cell正是使用这个框架,MyLinearLayout也提供了几种cell动态适应高度的demo,我就怀疑可能是布局库有的问题,大略看了一下实现源码,发现并没有shadow修改代码,也咨询了欧阳大哥,最后排除了我这个怀疑。

之后不断调试,又引出另外一个问题,那就是cell初始化方式会随着滑动调用多次,正常情况应该是只创建屏幕可见内容cell个数到复用池,当有新cell滑出屏幕时,查看复用池有没有可用的cell,有就取出,没有可复用就创建新的cell,但现在会随着滑动一直调用初始化方法,着实不正常。后来排查到是因为estimatedRowHeight设置成2倍屏幕高度,主要是解决MJRefresh刷新抖动问题,改为接近cell高度,发现就没有多次调用问题了,还是基础掌握的不牢固哇,重复调用问题是解决了但是阴影问题还是没有解决。

这个问题一直困扰着我,一时也没排查出原因,后来了解到是cell复用机制导致的,因为cell之间间隔较小,有一个cell的一个子视图距离cell底部距离较大,也设置有阴影效果,随着上下滑动,阴影效果展示正常。猜想是cell子视图距离上下边缘距离太小导致,如果距离设置的足够大,滑动的时候,阴影效果正常。至此,问题解决,但这一系列引出的问题,确实让我收获颇多,也提醒我越是基础,越应该熟练掌握,明白其原理,遇到问题才会有好的解觉思路。

问题解决了,下面是对UITableView cell动态适应高度方式总结。

一、UITableVIewCell注册方式

1
2
3
4
5
// Beginning in iOS 6, clients can register a nib or class for each cell.
// If all reuse identifiers are registered, use the newer -dequeueReusableCellWithIdentifier:forIndexPath: to guarantee that a cell instance is returned.
// Instances returned from the new dequeue method will also be properly sized when they are returned.
- (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier API_AVAILABLE(ios(5.0));
- (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier API_AVAILABLE(ios(6.0));

二、动态适应高度

  • 如果使用AutoLayout布局,除了设置子视图距离cell cotentView上下左右约束,将cell撑起,还需要设置以下代码:

    1
    2
    _tableView.estimatedRowHeight = 50;
    _tableView.rowHeight = UITableViewAutomaticDimension;
  • 如果是frame布局,不通过- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;返回cell高度,需在自定义cell需重写以下方法,让系统评估cell的高度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    - (CGSize)sizeThatFits:(CGSize)size {
    if (@available(iOS 11.0, *)) {
    //如果你的界面要支持横屏的话,因为iPhoneX的横屏左右有44的安全区域,所以这里要减去左右的安全区域的值,来作为布局宽度尺寸的评估值。
    //如果您的界面不需要支持横屏,或者延伸到安全区域外则不需要做这个特殊处理,而直接使用else部分的代码即可。
    return [self.rootLayout sizeThatFits:CGSizeMake(size.width - self.safeAreaInsets.left - self.safeAreaInsets.right, size.height)];
    } else {
    return [self.rootLayout sizeThatFits:size]; //如果使用系统自带的分割线,请记得将返回的高度height+1
    }
    }

    或者以下方法返回正确cell高度

    1
    2
    3
    4
    5
    /* The size fitting most closely to targetSize in which the receiver's subtree can be laid out while optimally satisfying the constraints. If you want the smallest possible size, pass UILayoutFittingCompressedSize; for the largest possible size, pass UILayoutFittingExpandedSize.
    Also see the comment for UILayoutPriorityFittingSizeLevel.
    */
    - (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize API_AVAILABLE(ios(6.0)); // Equivalent to sending -systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority: with UILayoutPriorityFittingSizeLevel for both priorities.
    - (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority API_AVAILABLE(ios(8.0));

总结

问题是解决了,对于常用UI控件的使用,复用原理,还是要牢牢掌握,不然遇到一些奇怪的问题,无从下手,了解其工作原理,是解决问题的关键因素,希望自己以后多多注意吧。


-------------本文结束感谢您的阅读-------------
分享到:
0%