UICollectionView 讲解
什么是UICollectionView
UICollectionView是一种新的数据展示方式,简单来说可以把他理解成多列的UITableView(请一定注意这是 UICollectionView的最最简单的形式)。如果你用过iBooks的话,可能你还对书架布局有一定印象:一个虚拟书架上放着你下载和购买的各 类图书,整齐排列。其实这就是一个UICollectionView的表现形式,或者iPad的iOS6中的原生时钟应用中的各个时钟,也是 UICollectionView的最简单的一个布局,如图:
最简单的UICollectionView就是一个GridView,可以以多列的方式将数据进行展示。标准的UICollectionView包含三个部分,它们都是UIView的子类:
- Cells 用于展示内容的主体,对于不同的cell可以指定不同尺寸和不同的内容,这个稍后再说
- Supplementary Views 追加视图 如果你对UITableView比较熟悉的话,可以理解为每个Section的Header或者Footer,用来标记每个section的view
- Decoration Views 装饰视图 这是每个section的背景,比如iBooks中的书架就是这个
不管一个UICollectionView的布局如何变化,这三个部件都是存在的。再次说明,复杂的UICollectionView绝不止上面的几幅图,关于较复杂的布局和相应的特性,我会在本文稍后和下一篇笔记中进行一些深入。
实现一个简单的UICollectionView
先从最简单的开始,UITableView是iOS开发中的非常非常非常重要的一个类,相信如果你是开发者的话应该是对这个类非常熟悉了。实现一个
UICollectionView和实现一个UITableView基本没有什么大区别,它们都同样是datasource和delegate设计模式
的:datasource为view提供数据源,告诉view要显示些什么东西以及如何显示它们,delegate提供一些样式的小细节以及用户交互的相
应。因此在本节里会大量对比collection view和table view来进行说明,如果您还不太熟悉table
view的话,也是个对照着复习的好机会。
UICollectionViewDataSource
- section的数量 -numberOfSectionsInCollection:
- 某个section里有多少个item -collectionView:numberOfItemsInSection:
- 对于某个位置应该显示什么样的cell -collectionView:cellForItemAtIndexPath:
实现以上三个委托方法,基本上就可以保证CollectionView工作正常了。当然,还有提供Supplementary View的方法
- collectionView:viewForSupplementaryElementOfKind:atIndexPath:
对于Decoration Views,提供方法并不在UICollectionViewDataSource中,而是直接在UICollectionViewLayout类中的(因为它仅仅是视图相关,而与数据无关),放到稍后再说。
关于重用
为了得到高效的View,对于cell的重用是必须的,避免了不断生成和销毁对象的操作,这与在UITableView中的情况是一致的。但值得注意的
时,在UICollectionView中,不仅cell可以重用,Supplementary View和Decoration
View也是可以并且应当被重用的。在iOS5中,Apple对UITableView的重用做了简化,以往要写类似这样的代码:
1
2
3
4
5
6
|
UITableViewCell *cell=[tableViewdequeueReusableCellWithIdentifier:@"MY_CELL_ID"];
if(!cell)//如果没有可重用的cell,那么生成一个 {
cell=[[UITableViewCell alloc]init];
}
//配置cell,blablabla
returncell;
|
而 如果我们在TableView向数据源请求数据之前使用-registerNib:forCellReuseIdentifier:方法为 @“MY_CELL_ID”注册过nib的话,就可以省下每次判断并初始化cell的代码,要是在重用队列里没有可用的cell的话,runtime将自 动帮我们生成并初始化一个可用的cell。
这个特性很受欢迎,因此在UICollectionView中Apple继承使用了这个特性,并且把其进行了一些扩展。使用以下方法进行注册:
- -registerClass:forCellWithReuseIdentifier:
- -registerClass:forSupplementaryViewOfKind:withReuseIdentifier:
- -registerNib:forCellWithReuseIdentifier:
- -registerNib:forSupplementaryViewOfKind:withReuseIdentifier:
相 比UITableView有两个主要变化:一是加入了对某个Class的注册,这样即使不用提供nib而是用代码生成的view也可以被接受为cell 了;二是不仅只是cell,Supplementary View也可以用注册的方法绑定初始化了。在对collection view的重用ID注册后,就可以像UITableView那样简单的写cell配置了:
1
2
3
4
5
6
|
-(UICollectionView*)collectionView:(UICollectionView*)cvcellForItemAtIndexPath:(NSIndexPath*)indexPath{
MyCell *cell=[cvdequeueReusableCellWithReuseIdentifier:@”MY_CELL_ID”];
// Configure the cell's content
cell.imageView.image=...
returncell;
}
|
需要吐槽的是,对collection view,取重用队列的方法的名字和UITableView里面不一样了,在Identifier前面多加了Reuse五个字母,语义上要比以前清晰,命 名规则也比以前严谨了..不知道Apple会不会为了追求完美而把UITableView中的命名不那么好的方法deprecate掉。
UICollectionViewDelegate
数据无关的view的外形啊,用户交互啊什么的,由UICollectionViewDelegate来负责:
- cell的高亮
- cell的选中状态
- 可以支持长按后的菜单
关于用户交互,UICollectionView也做了改进。每个cell现在有独立的高亮事件和选中事件的delegate,用户点击cell的时候,现在会按照以下流程向delegate进行询问:
- -collectionView:shouldHighlightItemAtIndexPath: 是否应该高亮?
- -collectionView:didHighlightItemAtIndexPath: 如果1回答为是,那么高亮
- -collectionView:shouldSelectItemAtIndexPath: 无论1结果如何,都询问是否可以被选中?
- -collectionView:didUnhighlightItemAtIndexPath: 如果1回答为是,那么现在取消高亮
- -collectionView:didSelectItemAtIndexPath: 如果3回答为是,那么选中cell
状态控制要比以前灵活一些,对应的高亮和选中状态分别由highlighted和selected两个属性表示。
关于Cell
相对于UITableViewCell来说,UICollectionViewCell没有这么多花头。首先UICollectionViewCell不 存在各式各样的默认的style,这主要是由于展示对象的性质决定的,因为UICollectionView所用来展示的对象相比UITableView 来说要来得灵活,大部分情况下更偏向于图像而非文字,因此需求将会千奇百怪。因此SDK提供给我们的默认的UICollectionViewCell结构 上相对比较简单,由下至上:
- 首先是cell本身作为容器view
- 然后是一个大小自动适应整个cell的backgroundView,用作cell平时的背景
- 再其上是selectedBackgroundView,是cell被选中时的背景
- 最后是一个contentView,自定义内容应被加在这个view上
这次Apple给我们带来的好康是被选中cell的自动变化,所有的cell中的子view,也包括contentView中的子view,在当cell 被选中时,会自动去查找view是否有被选中状态下的改变。比如在contentView里加了一个normal和selected指定了不同图片的 imageView,那么选中这个cell的同时这张图片也会从normal变成selected,而不需要额外的任何代码。
UICollectionViewLayout
终于到UICollectionView的精髓了…这也是UICollectionView和UITableView最大的不同。 UICollectionViewLayout可以说是UICollectionView的大脑和中枢,它负责了将各个cell、 Supplementary View和Decoration Views进行组织,为它们设定各自的属性,包括但不限于:
- 位置
- 尺寸
- 透明度
- 层级关系
- 形状
- 等等等等…
Layout决定了UICollectionView是如何显示在界面上的。在展示之前,一般需要生成合适的 UICollectionViewLayout子类对象,并将其赋予CollectionView的collectionViewLayout属性。关于 详细的自定义UICollectionViewLayout和一些细节,我将写在之后一篇笔记中。
Apple为我们提供了一个最简单可能也是最常用的默认layout对象,UICollectionViewFlowLayout。Flow Layout简单说是一个直线对齐的layout,最常见的Grid View形式即为一种Flow Layout配置。上面的照片架界面就是一个典型的Flow Layout。
- 首先一个重要的属性是itemSize,它定义了每一个item的大小。通过设定itemSize可以全局地改变所有cell的尺寸,如果想要对 某个cell制定尺寸,可以使用-collectionView:layout:sizeForItemAtIndexPath:方法。
- 间隔 可以指定item之间的间隔和每一行之间的间隔,和size类似,有全局属性,也可以对每一个item和每一个section做出设定:
- @property (CGSize) minimumInteritemSpacing
- @property (CGSize) minimumLineSpacing
- -collectionView:layout:minimumInteritemSpacingForSectionAtIndex:
- -collectionView:layout:minimumLineSpacingForSectionAtIndex:
- 滚动方向 由属性scrollDirection确定scroll view的方向,将影响Flow Layout的基本方向和由header及footer确定的section之间的宽度
- UICollectionViewScrollDirectionVertical
- UICollectionViewScrollDirectionHorizontal
- Header和Footer尺寸 同样地分为全局和部分。需要注意根据滚动方向不同,header和footer的高和宽中只有一个会起作用。垂直滚动时section间宽度为该尺寸的高,而水平滚动时为宽度起作用,如图。
- @property (CGSize) headerReferenceSize
- @property (CGSize) footerReferenceSize
- -collectionView:layout:referenceSizeForHeaderInSection:
- -collectionView:layout:referenceSizeForFooterInSection:
- 缩进
- @property UIEdgeInsets sectionInset;
- -collectionView:layout:insetForSectionAtIndex:
总结
一个UICollectionView的实现包括两个必要部分:UICollectionViewDataSource和 UICollectionViewLayout,和一个交互部分:UICollectionViewDelegate。而Apple给出的 UICollectionViewFlowLayout已经是一个很强力的layout方案了。
几个自定义的Layout
但是光是UICollectionViewFlowLayout的话,显然是不够用的,而且如果单单是这样的话,就和现有的开源各类Grid View没有区别了…UICollectionView的强大之处,就在于各种layout的自定义实现,以及它们之间的切换。先看几个相当 exiciting的例子吧~
比如,堆叠布局:
圆形布局:
和Cover Flow布局:
所有这些布局都采用了同样的数据源和委托方法,因此完全实现了model和view的解耦。但是如果仅这样,那开源社区也已经有很多相应的解决方案了。
Apple的强大和开源社区不能比拟的地方在于对SDK的全局掌控,CollectionView提供了非常简单的API可以令开发者只需要一次简单调
用,就可以使用CoreAnimation在不同的layout之间进行动画切换,这种切换必定将大幅增加用户体验,代价只是几十行代码就能完成的布局实
现,以及简单的一句API调用,不得不说现在所有的开源代码与之相比,都是相形见拙了…不得不佩服和感谢UIKit团队的努力。
关于上面几种自定义Layout和实现细节,和其他高级CollectionView应用,将在下一篇笔记中进行详细说明~
这是博主的WWDC2012笔记系列中的一篇,完整的笔记列表可以参看这里。如果您是首次来到本站,也许您会有兴趣通过RSS,或者通过页面左侧的邮件订阅的方式订阅本站。
在上一篇UICollectionView的入门介绍中, 大概地对iOS6新加入的强大的UICollectionView进行了一些说明。在这篇博文中,将结合WWDC2012 Session219:Advanced Collection View的内容,对Collection View进行一个深入的使用探讨,并给出一个自定义的Demo。
UICollectionView的结构回顾
首先回顾一下Collection View的构成,我们能看到的有三个部分:
- Cells
- Supplementary Views 追加视图 (类似Header或者Footer)
- Decoration Views 装饰视图 (用作背景展示)
而在表面下,由两个方面对UICollectionView进行支持。其中之一和tableView一样,即提供数据的 UICollectionViewDataSource以及处理用户交互的UICollectionViewDelegate。另一方面,对于cell的 样式和组织方式,由于collectionView比tableView要复杂得多,因此没有按照类似于tableView的style的方式来定义,而 是专门使用了一个类来对collectionView的布局和行为进行描述,这就是UICollectionViewLayout。
这次的笔记将把重点放在UICollectionViewLayout上,因为这不仅是collectionView和tableView的最重要求的区别,也是整个UICollectionView的精髓所在。
如果对UICollectionView的基本构成要素和使用方法还不清楚的话,可以移步到我之前的一篇笔记:Session笔记——205 Introducing Collection Views中进行一些了解。
UICollectionViewLayoutAttributes
UICollectionViewLayoutAttributes是一个非常重要的类,先来看看property列表:
- @property (nonatomic) CGRect frame
- @property (nonatomic) CGPoint center
- @property (nonatomic) CGSize size
- @property (nonatomic) CATransform3D transform3D
- @property (nonatomic) CGFloat alpha
- @property (nonatomic) NSInteger zIndex
- @property (nonatomic, getter=isHidden) BOOL hidden
可以看到,UICollectionViewLayoutAttributes的实例中包含了诸如边框,中心点,大小,形状,透明度,层次关系和是 否隐藏等信息。和DataSource的行为十分类似,当UICollectionView在获取布局时将针对每一个indexPath的部件(包括 cell,追加视图和装饰视图),向其上的UICollectionViewLayout实例询问该部件的布局信息(在这个层面上说的话,实现一个 UICollectionViewLayout的时候,其实很像是zap一个delegate,之后的例子中会很明显地看出),这个布局信息,就以 UICollectionViewLayoutAttributes的实例的方式给出。
自定义的UICollectionViewLayout
UICollectionViewLayout的功能为向UICollectionView提供布局信息,不仅包括cell的布局信息,也包括追加 视图和装饰视图的布局信息。实现一个自定义layout的常规做法是继承UICollectionViewLayout类,然后重载下列方法:
-(CGSize)collectionViewContentSize
- 返回collectionView的内容的尺寸
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
- 返回rect中的所有的元素的布局属性
- 返回的是包含UICollectionViewLayoutAttributes的NSArray
UICollectionViewLayoutAttributes可以是cell,追加视图或装饰视图的信息,通过不同的 UICollectionViewLayoutAttributes初始化方法可以得到不同类型的 UICollectionViewLayoutAttributes:
- layoutAttributesForCellWithIndexPath:
- layoutAttributesForSupplementaryViewOfKind:withIndexPath:
- layoutAttributesForDecorationViewOfKind:withIndexPath:
-(UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath
- 返回对应于indexPath的位置的cell的布局属性
-(UICollectionViewLayoutAttributes )layoutAttributesForSupplementaryViewOfKind:(NSString )kind atIndexPath:(NSIndexPath *)indexPath
- 返回对应于indexPath的位置的追加视图的布局属性,如果没有追加视图可不重载
-(UICollectionViewLayoutAttributes * )layoutAttributesForDecorationViewOfKind:(NSString)decorationViewKind atIndexPath:(NSIndexPath )indexPath
- 返回对应于indexPath的位置的装饰视图的布局属性,如果没有装饰视图可不重载
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
- 当边界发生改变时,是否应该刷新布局。如果YES则在边界变化(一般是scroll到其他地方)时,将重新计算需要的布局信息。
另外需要了解的是,在初始化一个UICollectionViewLayout实例后,会有一系列准备方法被自动调用,以保证layout实例的正确。
首先,-(void)prepareLayout将被调用,默认下该方法什么没做,但是在自己的子类实现中,一般在该方法中设定一些必要的layout的结构和初始需要的参数等。
之后,-(CGSize) collectionViewContentSize将被调用,以确定collection应该占据的尺寸。注意这里的尺寸不是指可视部分的尺寸,而应该 是所有内容所占的尺寸。collectionView的本质是一个scrollView,因此需要这个尺寸来配置滚动行为。
接下来-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect被调用,这个没什么值得多说的。初始的layout 的外观将由该方法返回的UICollectionViewLayoutAttributes来决定。
另外,在需要更新layout时,需要给当前layout发送 -invalidateLayout,该消息会立即返回,并且预约在下一个loop的时候刷新当前layout,这一点和UIView的 setNeedsLayout方法十分类似。在-invalidateLayout后的下一个collectionView的刷新loop中,又会从 prepareLayout开始,依次再调用-collectionViewContentSize和 -layoutAttributesForElementsInRect来生成更新后的布局。
Demo
说了那么多,其实还是Demo最能解决问题。Apple官方给了一个flow layout和一个circle layout的例子,都很经典,需要的同学可以从这里下载。
LineLayout——对于个别UICollectionViewLayoutAttributes的调整
先看LineLayout,它继承了UICollectionViewFlowLayout这个Apple提供的基本的布局。它主要实现了单行布局,自动对齐到网格以及当前网格cell放大三个特性。如图:
先看LineLayout的init方法:
1 |
|
self.sectionInset = UIEdgeInsetsMake(200, 0.0, 200, 0.0); 确定了缩进,此处为上方和下方各缩进200个point。由于cell的size已经定义了为200x200,因此屏幕上在缩进后就只有一排item的空 间了。
self.minimumLineSpacing = 50.0; 这个定义了每个item在水平方向上的最小间距。
UICollectionViewFlowLayout是Apple为我们准备的开袋即食的现成布局,因此之前提到的几个必须重载的方法中需要我们 操心的很少,即使完全不重载它们,现在也可以得到一个不错的线状一行的gridview了。而我们的LineLayout通过重载父类方法后,可以实现一 些新特性,比如这里的动对齐到网格以及当前网格cell放大。
自动对齐到网格
1 |
|
当前item放大
1 |
|
对于个别UICollectionViewLayoutAttributes进行调整,以达到满足设计需求是UICollectionView使用 中的一种思路。在根据位置提供不同layout属性的时候,需要记得让-shouldInvalidateLayoutForBoundsChange: 返回YES,这样当边界改变的时候,-invalidateLayout会自动被发送,才能让layout得到刷新。
CircleLayout——完全自定义的Layout,添加删除item,以及手势识别
CircleLayout的例子稍微复杂一些,cell分布在圆周上,点击cell的话会将其从collectionView中移出,点击空白处会加入一个cell,加入和移出都有动画效果。
这放在以前的话估计够写一阵子了,而得益于UICollectionView,基本只需要100来行代码就可以搞定这一切,非常cheap。通过CircleLayout的实现,可以完整地看到自定义的layout的编写流程,非常具有学习和借鉴的意义。
CircleLayout
首先,布局准备中定义了一些之后计算所需要用到的参数。
1 |
|
其实对于一个size不变的collectionView来说,除了_cellCount之外的中心和半径的定义也可以扔到init里去做,但是显 然在prepareLayout里做的话具有更大的灵活性。因为每次重新给出layout时都会调用prepareLayout,这样在以后如果有 collectionView大小变化的需求时也可以自动适应变化。
然后,按照UICollectionViewLayout子类的要求,重载了所需要的方法:
1 |
|
现在已经得到了一个circle layout。为了实现cell的添加和删除,需要为collectionView加上手势识别,这个很简单,在ViewController中:
1 |
|
对应的处理方法handleTapGesture:为
1 |
|
performBatchUpdates:completion: 再次展示了block的强大的一面..这个方法可以用来对collectionView中的元素进行批量的插入,删除,移动等操作,同时将触发 collectionView所对应的layout的对应的动画。相应的动画由layout中的下列四个方法来定义:
- initialLayoutAttributesForAppearingItemAtIndexPath:
- initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:
- finalLayoutAttributesForDisappearingItemAtIndexPath:
- finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:
更正:正式版中API发生了变化(而且不止一次变化 initialLayoutAttributesForInsertedItemAtIndexPath:在正式版中已经被废除。现在在insert或者 delete之前,prepareForCollectionViewUpdates:会被调用,可以使用这个方法来完成添加/删除的布局。关于更多这方 面的内容以及新的示例demo,可以参看这篇博文(需要翻墙)。新的示例demo在Github上也有,链接
在CircleLayout中,实现了cell的动画。
1 |
|
在插入或删除时,将分别以插入前和删除后的attributes和普通状态下的attributes为基准,进行UIView的动画过渡。而这一切并没有很多代码要写,几乎是free的,感谢苹果…
布局之间的切换
有时候可能需要不同的布局,Apple也提供了方便的布局间切换的方法。直接更改collectionView的 collectionViewLayout属性可以立即切换布局。而如果通过setCollectionViewLayout:animated:,则可 以在切换布局的同时,使用动画来过渡。对于每一个cell,都将有对应的UIView动画进行对应,又是一个接近free的特性。
对于我自己来说,UICollectionView可能是我转向iOS 6 SDK的最具有吸引力的特性之一,因为UIKit团队的努力和CoreAnimation的成熟,使得创建一个漂亮优雅的UI变的越来越简单了。可以断言 说UICollectionView在今后的iOS开发中,一定会成为和UITableView一样的强大和最常用的类之一。在iOS 6还未正式上市前,先对其特性进行一些学习,以期尽快能使用新特性来简化开发流程,可以说是非常值得的。
UICollectionView 讲解的更多相关文章
- UICollectionView 讲解-备
什么是UICollectionView UICollectionView是一种新的数据展示方式,简单来说可以把他理解成多列的UITableView(请一定注意这是UICollectionView的最最 ...
- iOS6新特征:UICollectionView介绍
http://blog.csdn.net/eqera/article/details/8134986 1.1. Collection View 全家福: UICollectionView, UITab ...
- UICollectionView介绍
文章原出处未知,如有朋友知道,请告诉我,我会补上. 1.1. Collection View 全家福: UICollectionView, UITableView, NSCollectionView ...
- UICollectionView使用
本文原文 原文转自 1.1. Collection View 全家福: UICollectionView, UITableView, NSCollectionView n 不直接等效于NSColl ...
- iOS6新特征:UICollectionView高级使用示例之CircleLayout
DEMO 下面再看看Demo运行的效果图,通过这样的一个Demo,我们可以看出,使用UICollectionView可以很方便的制作出照片浏览等应用.并且需要开发者写的代码也不多. 程序刚刚启 ...
- iOS 高效添加圆角效果实战讲解
圆角(RounderCorner)是一种很常见的视图效果,相比于直角,它更加柔和优美,易于接受.但很多人并不清楚如何设置圆角的正确方式和原理.设置圆角会带来一定的性能损耗,如何提高性能是另一个需要重点 ...
- 利用UICollectionView实现列表和宫格视图的切换
很多时候我们需要列表和宫格视图的来回切换,就像苹果的天气应用一样,我之前见过一个用tableview和collectionview来实现这种效果的,我本人不太喜欢这个,那么有没有更好的方法呢?答案是: ...
- iOS -数据持久化方式-以真实项目讲解
前面已经讲解了SQLite,FMDB以及CoreData的基本操作和代码讲解(CoreData也在不断学习中,上篇博客也会不断更新中).本篇我们将讲述在实际开发中,所使用的iOS数据持久化的方式以及怎 ...
- 使用 UICollectionView 实现网格化视图效果
讲解 UICollectionView 的相关链接:http://blog.csdn.net/eqera/article/details/8134986 关键操作: 效果如下: KMCollectio ...
随机推荐
- Re:从零开始的Linux之路(基础篇)
基于 Red Hat Enterprise Linux 7.5 或者 CentOS 7.4 Linux的命令一定遵循以下格式:command指令 [-options]选项 parameter1参数 ...
- 细说unittest-1
转自:https://www.jianshu.com/p/6c07be6d61dc 一.什么是unittest unittest是Python单元测试框架,类似于JUnit框架. unittest中有 ...
- LCD驱动分析(一)字符设备驱动框架分析
参考:S3C2440 LCD驱动(FrameBuffer)实例开发<一> S3C2440 LCD驱动(FrameBuffer)实例开发<二> LCD驱动也是字符设备驱动,也 ...
- MPEG-4视频编码核心思想
1 引言 当今时代,信息技术和计算机互联网飞速发展,在此背景下,多媒体信息已成为人类获取信息的最主要载体,同时也成为电子信息领域技术开发和研究的热点.多媒体信息经数字化处理后具有易于加密.抗干扰能 ...
- linux下如何编译运行c程序
GCC是Linux操作系统下一个非常重要的源代码编译工具,有着许多重要的选项,支持许多不同语言的编译,如C.C++.Ada.Fortran.Objective.Perl.Python.Ruby以及Ja ...
- ubuntu下svn在挂在的NTFS分区上无法报错,提示没有权限
终极解决方案: 赋予svn文件root权限 1. 查找svn文件: $ whereis svn svn: /usr/bin/svn /usr/bin/X11/svn /usr/share/.gz $ ...
- 在java中使用dom4j解析xml
创建xml文档并输出到文件 import java.io.File; import java.io.FileOutputStream; import org.dom4j.Document; impor ...
- 4C. Stars
4C. Stars Time Limit: 2000ms Case Time Limit: 2000ms Memory Limit: 65536KB 64-bit integer IO forma ...
- heartbeat负载均衡详解
heartbeat高可用软件http://www.linux-ha.org/wiki/Main_Page 1 heartbeat作用通过heartbeat将资源(IP)从一台已经故障的计算机快速转移到 ...
- UITableView点击切换状态分析
原理:多选+点击动画 初始化和点击都调用的方法 - (void)changeStateAnimated:(BOOL)animated { //不需要动画,初始化的时候 if (animated == ...