一周随笔--15.11.02
一周新知识点记录(15.11.02)
一、storyboard中搭建tableViewCell
在storyboard中搭建tableView,一种是以UITableViewController为容器,另一种则是以UIViewController为容器,拖出一个tableView来。
当以UITableViewController为容器时,UITableViewCell可以是动态也可以是静态的,并且可以不关联文件。
当UIViewController为容器时,cell必须是动态的,并且控制器必须得关联文件,将tableView对象关联到控制器来使用。
二、UIScrollView的contentSize、contentInset、contentOffset的理解
原以为对scrollView的这几个属性已经够了解了,最近碰到contentInset才发现自己依旧是含糊不清的,在此再做一番理解:
UIScrollView:以容器的方式存在
contentView:内容视图,scrollView上用来滚动的区域,姑且将其当做是一个view方便理解,add到scrollView上的视图或者控件都是添加在这上面的。这个东西并不存在,或者说不知道是否存在,至少我们看不到,只是个遐想的东西。
contentSize:contentView的size,即滚动视图的大小。
contentInset:contentView的展示区域,或者滚动区域,默认为UIEdgeInsetsZero,即默认整个scrollView(容器)为展示区域。所谓展示区域,就是contentView可以在这个范围内任意滚动。
contentOffset:CGPonit属性,是scrollView左上角原点相对于contentView左上角的偏移量。
这样讲可能有点抽象了,打个比方,将一张画布放在一个橱窗上展示,那么:
scrollView <————> 橱窗
contentView <————> 画布
contentSize <————> 画布大小
contentInset <————> 决定橱窗上的展示画布的区域
contentOffset <————> 橱窗原点相对于画布当前位置原点的偏移
当画布大小大于展示区域,即画布的长或宽大于展示区域的长或宽时,这时候画布是不能够在橱窗上完整显示的,这个时候画布就能在橱窗的展示区域内任意滚动,但是画布边缘不能越过展示区域边缘。
假设有一个scrollView,frame为{0 ,0,self.view.frame.size.width, self.view.frame.size.height}。
设置contentInset为UIEdgeInsetsMake(100, 0, 100, 0),即上下均偏移100,那么这个scrollView的滚动区域(展示区域)则为{0,100 ,self.view.frame.size.width, self.view.frame.size.height-200 }。
接下来设置scrollView的contentSize,即内容视图的大小,假如我们将尺寸宽高设置为和滚动区域一样大或者比滚动区域小,那么运行发现是无法滚动的,因为这个时候滚动区域能完全展示内容视图,还要它滚动干嘛呢?如果contentSize的尺寸比展示区域大,那么运行发现是可以滑动的,假如宽度和滚动区域一致,高度比它大100,那么就能在垂直方向滚动,滚动上下极限偏差相差100。
设置contentOffset的效果则是指定画布滚动到什么位置。调用方法- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated可以使这个过程伴随滚动动画。
几个注意点:
1、添加到scrollView上的视图是被添加上contentView上的。
2、先设置contentInset再设置contentSize和先设置contentSize再设置contentInset的一开始展示效果(即初始效果)是不一样的,实际效果是一样的。在一开始不设置contentOffset的情况下,对前者而言,一开始展示出来的效果是content view的上沿跟滚动区域的上沿贴合;而对于后者而言,contentView的上沿则是跟scrollView的上沿贴合。通常情况下,前者才是我们想要的结果,因此一般情况下先设置contentInset再设置contentSize。
三、掌握CollectionView用法
UICollectionView的精髓在于它的布局,UICollectionViewFlowLayout是系统定义好的规则矩形流布局方式,要挖掘UICollectionView的强大之处,就得自定义布局方式,即自己定义一个布局类继承自UICollectionViewLayout。
UICollectionView常规用法:
(1)初始化UICollectionViewFlowLayout实例并设置好响应属性,若属性不写死,即各个section属性值不一,就调用相应的代理方法设置。
(2)根据布局实例初始化UICollectionView实例,设置好代理及数据源等属性。
(3)实现相应的代理方法。
UICollectionView的自定义用法(即自定义布局方式):
(1)定义一个布局类继承自UICollectionView,在控制器中初始化布局类实例。
(2)根据布局实例初始化UICollectionView实例,设置好代理及数据源等属性。
(3)实现相应的代理方法。
(4)自定义布局(核心所在)
关于自定义布局,是通过重载父类的方法实现的,具体方法实现如下:
(1)首先,-(void)prepareLayout将被调用,默认下该方法什么没做,但是在自己的子类实现中,一般在该方法中设定一些必要的layout的结构和初始需要的参数等。
(2)之后,-(CGSize) collectionViewContentSize将被调用,以确定内容视图的尺寸(UIScrollView的概念)。
(3)接下来-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect被调用,用于返回包含了每个单元、补充视图、修饰视图布局属性的数组。每一个布局属性对应一个实例,在方法中手动调用下面三个方法以得到对应的布局属性:
layoutAttributesForCellWithIndexPath: //单元布局属性
*layoutAttributesForSupplementaryViewOfKind:withIndexPath: //补充视图布局属性 根据需要调用
*layoutAttributesForDecorationViewOfKind:withIndexPath: //装饰视图布局属性 根据需要调用
(4)重写layoutAttributesForCellWithIndexPath,设置布局属性(这里是布局的关键所在)。根据需要重写layoutAttributesForSupplementaryViewOfKind:withIndexPath:和layoutAttributesForDecorationViewOfKind:withIndexPath:
(5)-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds。
当边界发生改变时,是否应该刷新布局。默认返回NO,如果返回YES则在边界变化(通常是滑动)时刷新布局,即会重新先后调用上面(1)(2)(3)方法。根据需要重写该方法,如果滑动过程中需要时刻刷新布局就重写返回YES(通常用于滑动过程中动画实现),如果没有这个需求就不用重写了。
具体见Demo