iOS初学历程

创建UITableViewCell子类

2019-08-02  本文已影响0人  水无月之痕

UITableViewCell是UIView的子类。创建UIView子类时,定制界面的方法是覆盖drawRect:,但是在创建UITableViewCell子类时,定制界面的方法是向UITableViewCell加入子视图。不过,并不是直接将子视图加入UITableViewCell,而是加入UITableViewCell的另一个子视图:contentView。

contentView起容器的作用,用于存放其他子视图。这些子视图构成UITableViewCell的布局(见图192)。要改变UITableViewCell子类的外观,需要修改contentView所包含的子视图。


UITableViewCell的视图层次结构

  必须将子视图加入contentView而不是UITableViewCell对象自身的原因是,UITableViewCell对象会根据外部条件改变contentView的大小。例如,当UITableView对象进入编辑模式时,UITableViewCell对象会改变contentView的大小,为编辑控件(例如删除控件和移位控件)留出位置(见图193)。如果直接将子视图加入UITableViewCell对象,编辑控件就会遮住这些子视图。进入编辑模式时,UITableViewCell对象不会改变大小(UITableViewCell对象的宽度必须和UITableView对象的宽度相等),但是其包含的contentView会改变大小。
  读者可能已经注意到视图层次结构中的UIScrollView对象,当UITableView对象进入编辑模式时,UITableViewCell对象会将contentView移动到左侧,这个过程需要借助UIScrollView对象。同样,在UITableViewCell对象中从右向左滑动显示删除控件时,也需要借助UIScrollView对象。实际上,contentView是UIScrollView对象的一个子视图。


UITableViewCell对象的布局(标准模式和编辑模式)

创建UITableViewCell子类界面的最简单方法就是使用XIB文件。

UITableViewCell的XIB文件不会使用File'sOwner,所以不用为其设置类名,也不用为其创建任何关联。与UIViewController的XIB文件不同,UITableViewCell的XIB文件在解固时,不需要使用某个对象代替File'sOwner,也不需要将其中的固化对象关联到File'sOwner。为了理解两种XIB文件的区别,首先需要知道UITableView加载UITableViewCell的过程。

image.png

注册NIB文件的原理非常简单,仅仅是将UINib对象以“BNRItemCell”作为键保存到NSDictionary中。UINib对象包含所有保存在其XIB文件中的数据,当UITableView对象需要使用UITableViewCell对象时,就会使用相应的UINib对象创建新的UITableViewCell对象。
 在UITableView对象中注册了包含xib的UINib对象之后,UITableView对象就可以通过“BNRItemCell”键找到并加载BNRItemCell对象。


image.png

缩略图

详细看19.2

iOS SDK提供了多种创建缩略图的途径,其中之一是根据原图在屏外上下文(offscreencontext)中画出按比率缩小后的版本,然后从上下文取出新创建的图片。下面通过这种途径为BNRItem对象的图片创建缩略图。

由UITableViewCell对象转发动作消息
Block对象的语法

请注意,Block被声明为copy。系统对Block对象和其他对象的内存管理方式不同,Block对象是在栈中创建的,而其他对象是在堆中创建的。这意味着,即使应用针对新创建的Block对象保留了强引用类型的指针,一旦创建该对象的方法返回,那么与方法内部的其他局部变量相同,新创建的Block对象也会被立即释放。为了在声明Block对象的方法返回后仍然保留该对象,必须向其发送copy消息。拷贝某个Block对象时,应用会在堆中创建该对象的备份。这样,即使应用释放了当前方法的栈,堆中的Block对象也不会被释放。


image.png
捕获变量

Block对象可以使用其封闭作用域(enclosingscope)内的所有变量。对声明了某个Block对象的方法,该方法的作用域就是这个Block对象的封闭作用域。因此,这个Block对象可以访问该方法的所有局部变量、传入该方法的实参以及所属对象的实例变量。如果捕获变量是ObjectiveC对象,那么Block对象对捕获变量具有强引用。如果捕获变量也对Block对象具有强引用,就会导致强引用循环。


解决问题的方法是:将actionBlock对cell的引用改为弱引用。
image.png

在Block对象执行过程中,必须保证Block对象始终可以访问cell。因此,以上代码在actionBlock内部创建了strongCell,以保持对cell的强引用。这与Block对象对捕获变量的强引用不同,strongCell只是在Block对象执行过程中对cell保持强引用。

UICollectionView

UICollectionView与UITableView非常相似:
  •UICollectionView是UIScrollView的子类。
  •与UITableViewCell类似,UICollectionView对象显示一组UICollectionViewCell或其子类。
  •UICollectionView具有数据源,负责提供UICollectionViewCell。  •UICollectionView具有委托,可以在委托方法中处理相关回调事件,例如选择了某一个UICollectionViewCell。
  •UICollectionViewController与UITableViewController类似,UICollectionViewController也是UIViewController的子类,其view是UICollectionView。
  UICollectionView与UITableView的区别是,UITableView只能显示一列UITableViewCell,在大屏幕设备(如iPad)中有很大的局限性。UICollectionView则可以将UICollectionViewCell按任意方式布局,其中最常见的是网格布局


image.png UICollectionView对象图示例

UICollectionView是如何布局UICollectionViewCell的?UICollectionView含有一个布局对象,负责控制每一个UICollectionViewCell的属性,包括位置和大小。UICollectionView的布局对象继承自一个名为UICollectionViewLayout的抽象类。如果需要将UICollectionViewCell按网格布局,则可以使用系统提供的UICollectionViewFlowLayout。但是,如果需要实现其他的布局方式,就必须创建UICollectionViewLayout的自定义子类。

UICollectionViewCell也有contentView,但是与UITableViewCell不同,UICollectionViewCell的contentView在默认情况下没有任何子视图(UITableView默认是有Cell,不一定要自主创建)。因此,如果需要使用UICollectionView,通常还需要创建一个UICollectionViewCell子类。

最后,UICollectionViewCell也具有背景视图和选中状态下的背景视图(当UICollectionViewCell处于选中状态时,该视图会覆盖在背景视图上方)。

上一篇下一篇

猜你喜欢

热点阅读