IOS-UITableView 及自定义cell
2016-01-04 20:41
489 查看
IOS-UITableView 及自定义cell
类似于Android中的ListView,继承自UIScrollView。分为两种样式
UITableViewStylePlain (每组数据之间不留空隙)
UITableViewStyleGrouped (每组数据之间间隔明显)
Plain样式有一个特点:
在展示数据时,不同组的头部标题会在显示着一组数据时停留在顶部
这样可以起到提示当前显示哪一组的作用
我们还可以自定义展示UITableView的HeaderView和FooterView
并且还可以在其代理中自定义每一组的HeaderView和FooterView
如何展示数据
如果使用UITableView来展示数据,
那么这个对象必须遵守UITableViewDataSource协议
并且成为UITableView的数据源
UITableViewDataSource协议的方法
// 一共有多少组数据 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // 每一组有多少行数据 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; // 每一行显示什么内容 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; //每组数据显示怎样的头部和尾部标题 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
数据刷新
[taleView reloadData]; //重新加载全部数据
[tableView reloadRowAtIndexPaths: withRowAnimation:] //刷新某一行
NSIndexPath对象内包含section和row两个属性
UITableViewCell
UITableView的每一行都是一个UITableViewCell,通过dataSource的tableView:cellForRowAtIndexPath:方法来初始化每一行
通过选择UITableViewCell不同的样式,我们可以在UITableViewCell内显示不同的内容
UITableViewCell内部有三个属性
UIImageView* imageView
UILabel* textLabel
UILabel* detailTextLabel
UITableViewCell的样式有:
UITableViewCell内部有个默认的子视图:contentView,
contentView是UITableViewCell所显示内容的父视图,可显示一些辅助指示视图
辅助指示视图的作用是显示一个表示动作的图标,可以通过设置UITableViewCell的accessoryType来显示,默认是UITableViewCellAccessoryNone
其他还有
UITableViewCellAccessoryDisclosureIndicator
UITableViewCellAccessoryDetailDisclosureButton
UITableViewCellAccessoryCheckmark
还可以通过cell的accessoryView属性来自定义辅助指示视图(比如往右边放一个开关)
cell的重用
类似与Android中的ListView的优化问题,IOS中UITableView的优化类似
ios的cell缓存机制
当滚动列表时,部分UITableViewCell会移出窗口,UITableView会将窗口外的UITableViewCell放入一个对象池中,
等待重用。当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个对象池,如果池中有未使用的UITableViewCell,
dataSource会用新的数据配置这个UITableViewCell,然后返回给UITableView,重新显示到窗口中,从而避免创建新对象
简单的cell重用代码如下
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 1.定义一个cell的标识 static NSString *ID = @"mjcell"; // 2.从缓存池中取出cell (其实系统维护了一个cell缓存链表) UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; // 3.如果缓存池中没有cell if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } // 4.设置cell的属性... return cell; }
storyboard中的静态cell
对于app中的cell,有的cell可能就是用来显示固定数据的
这些cell的数据并不需要动态的设置,比如一个设置界面的选项布局
xcode允许我们直接在storyboard中描述这种cell, 这样我们就可以不用实现数据源相关方法了。
注意的是:你如果实现了数据源相关方法,就不可能使用静态单元格成功!!!
xcode在从storyboard中加载tableView时,会直接把我们描述的静态cell给显示在TableView上
对于TableView的content选择 static cell
对于每一种静态cell的布局,我们有两种方式选择,根据 TableViewCell的style属性
使用系统自带的4个样式
选择custom, 这样对于每个静态cell我们可以自己进行布局(拖控件,设置控件内容)
小技巧: 一般先搞定一组,然后在改变section属性时,Interface Builder会自动帮我们按已经搞定的一组复制出其他几组
cell的编辑
IOS中的TableView自带两种编辑状态:添加和删除, 默认进入编辑状态是删除状态
删除状态:自带的侧滑删除的效果
添加状态:可以添加数据
相关方法
// 让tableView进入编辑状态的两种方式 [tableView setEditing: YES animated:YES]; tableView.editing = YES; #pragma mark - tableView的代理方法 /** * 当tableView进入编辑状态的时候会调用,询问每一行进行怎样的操作(添加\删除) */ - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { //TODO:返回要进行的操作类型 } /** * 如果实现了这个方法,就自动实现了添加和滑动删除的功能 * 提交了一个编辑操作就会调用(操作:删除\添加)这个方法 * @param editingStyle 编辑的行为 * @param indexPath 操作的行号 */ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // 提交的是删除操作 //TODO: 更改数据模型,刷新表格 } else if (editingStyle == UITableViewCellEditingStyleInsert) { //TODO: 更改数据模型,刷新表格 } }
如果对展示的数据进行了编辑操作, 那么我们就必须要刷新表格,那么怎么刷新才是比较有效率的呢?
[self.tableView reloadData];
全局刷新, 但性能不好
[tableView deleteRowsAtIndexPaths:(NSArray*)deleteRows withRowAnimation:];
这个方法使用前提是:删除后的行数应和修改后的数据模型中数据的个数相同
这个方法调用后,会刷新被删除的行后面cell,并不会向前刷新
[tableView insertRowsAtIndexPaths:(NSArray*)insertRows withRowAnimation:];
类似与上面的方法,也只是会刷新后面的cell
[tableView reloadRowsAtIndexPaths:(NSArray*)Rows withRowAnimation:]
这个方法用来刷新指定行,要求数据模型内数据的个数不能变。
自定义cell
一共有两种方式,一种是通过xib,一种是通过代码
xib适合定义样式相同的cell
通过代码一般定义样式不同的cell
通过xib
新建一个xib文件,并拖出一个Table View Cell
样式设置为 Custom, 并且定义好标识以便重用
摆放自己需要的控件
定义一个类,描述这个Cell, 并把这个Cell对应的类设置为我们自定义的类
//描述xib中自定义cell的类 //这里只看快速创建cell的类方法 @implementation MJTGCell + (instancetype)cellWithTableView:(UITableView *)tableView { static NSString *ID = @"cell"; //这个标识与xib文件中,cell的标识相同 // dequeueReusableCellWithIdentifier 先从缓存池中取,如果缓存池中没有可循环利用的cell,先去storyboard中找到合适的cell(静态cell) // cell是从storyboard中创建出来的 MJTGCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { //获取xib文件中我们描述的Table View Cell, 并会把这个cell以在xib文件中定义标识为准,丢入缓存池中 cell = [[[NSBundle mainBundle] loadNibNamed:@"MJTGCell" owner:nil options:nil] lastObject]; } return cell; } //如果cell是通过storyboard或者xib创建的,就会调用这个方法来初始化cell - (void)awakeFromNib { // Initialization code UIView *divider = [[UIView alloc] init]; divider.backgroundColor = [UIColor blackColor]; divider.alpha = 0.2; [self.contentView addSubview:divider]; self.divider = divider; } @end
通过代码
对于通过代码自定义的cell,一般每个cell的样式可能都不相同
即其中基本控件相同,但控件大小随数据的变化而变化,即frame不固定
这些控件的frame是在数据决定后才决定的
经过上面的分析,对于这种自定义cell,我们提供两个模型(把data模型算上的话是3个)
自定义cell模型,这个模型中定义了cell中含有的基本控件的样式和属性
FrameData模型,这个模型可以根据data模型,算出data展示时所需要的控件的大小
给cell模型设置FrameData模型就可以使cell变的完整可用,即cell的展示是根据数据来动态变化的
需要注意: 自定义的cell继承自UITableViewCell, 并且自定义的控件都要添加到cell的contentView中!!!!
范例如下
该范例展示的自定义cell中含有一个UIImageView,一个UILabel和一个UIButton
核心方法如下
/** *自定义cell:MJMessageCell */ @implementation MJMessageCell //继承自UITableViewCell //类构造方法,快速创建cell + (instancetype)cellWithTableView:(UITableView *)tableView { static NSString *ID = @"message"; MJMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[MJMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; } return cell; } //重写initWithStyle:reuseIdentifier: 以便cell的可重用 - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { //TODO, 定义cell内基本控件的属性 // 这里需要初识化的控件有有UIImageView 和两个UILabel //这些控件都要添加到cell的contentView中!!!!!!!! } return self; } - (void)setMessageFrame:(MJMessageFrame *)messageFrame { //在这个方法中,根据传入的FrameData模型,设置控件相关的frame } //FrameData模型: @interface MJMessageFrame : NSObject //各种对应cell中控件的Frame @property (nonatomic, assign, readonly) CGRect iconF; @property (nonatomic, assign, readonly) CGRect timeF; @property (nonatomic, assign, readonly) CGRect textF; @property (nonatomic, assign, readonly) CGFloat cellHeight; //数据模型 @property (nonatomic, strong) MJMessage *message; @end @implementation MJMessageFrame - (void)setMessage:(MJMessage *)message { //TODO: 根据数据设置相关的frame属性 } //在控制器中,FrameData模型作为数据源 @interface MJViewController () <UITableViewDataSource, UITableViewDelegate> @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (nonatomic, strong) NSMutableArray *messageFrames; //FrameData模型 @end @implementation MJViewController //懒加载FrameData模型 - (NSMutableArray *)messageFrames { if (_messageFrames == nil) { //TODO, 加载数据模型,并将数据模型设置给FrameData模型 } _messageFrames = mfArray; } return _messageFrames; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 1.创建cell MJMessageCell *cell = [MJMessageCell cellWithTableView:tableView]; // 2.给cell传递模型 cell.messageFrame = self.messageFrames[indexPath.row]; // 3.返回cell return cell; } //设置每个cell的高度 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { MJMessageFrame *mf = self.messageFrames[indexPath.row]; return mf.cellHeight; } @end
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- 讲解iOS开发中基本的定位功能实现
- js判断客户端是iOS还是Android等移动终端的方法
- IOS开发环境windows化攻略
- 浅析iOS应用开发中线程间的通信与线程安全问题
- 检测iOS设备是否越狱的方法
- .net平台推送ios消息的实现方法
- 探讨Android与iOS,我们将何去何从?
- Android、iOS和Windows Phone中的推送技术详解
- IOS 改变键盘颜色代码
- 举例详解iOS开发过程中的沙盒机制与文件
- Android和IOS的浏览器中检测是否安装某个客户端的方法
- 分享一个iOS下实现基本绘画板功能的简单方法
- javascript实现阻止iOS APP中的链接打开Safari浏览器