UITableView笔记一
2016-03-15 22:57:37
本文绝非抄袭,创建于本人静态博客上,现挪过来供自己个更多的同伴们参考学习。
UITableView笔记一
UITableView作为iOS开发最常用的控件,没有之一.可见其使用的频繁度,现在我先从最简单的使用说起,虽然简单但是也最能提现一个程序员的基本功吧,如果对你没有帮助请略过。
<!-- more -->
#pragma mark tableView Getter
-(UITableView *)tableView
{
if (!_tableView) {
_tableView = [[UITableView alloc]initWithFrame:self.view.bounds];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.rowHeight = 50;
_tableView.separatorInset = UIEdgeInsetsZero;
[self.view addSubview:_tableView];
}
return _tableView;
}
注意一、_tableView.rowHeight = 50;
在行高为定值的时候最好替换掉下面的方法 在下面的测试中会介绍为什么最好用这种方法,而不用heightForRowAtIndexPath
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//如果不是定值可用Switch语法,提高代码可读性
switch (indexPath.row) {
case 0:
return 20;
break;
case 1:
return 30;
break;
case 2:
return 40;
break;
default:
break;
}
return 50;///此方法如果返回的是定值,例如每一行都是50,那么最好用_tableView.rowHeight = 50;替换此方法
}
注意二、tableView的两个必须实现的代理方法
numberOfRowsInSection 返回的是所在区的行数,也可以用switch
至于cellForRowAtIndexPath 看代码注释,这里为系统cell类,注意思考①
#pragma mark - dataSource
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"reuse";///此处用static的原因 可以思考一下①
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];///在tableView的重用队列里面取带有identifier标记的cell,也就是目标cell
if (!cell) {///如果重用池(重用队列)里没有这种cell
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];///没有目标cell就去初始化新的cell 并制定标记identifier
}
// cell.textLabel.text = self.dataArray[indexPath.row];///简单的可以直接用系统的cell
return cell;
}
下面咱们测试一下这几个方法的执行顺序和执行次数,认真思考,就会有意外收获。注意我写的Demo里面一共有五条数据
从图上我们可以看出UITableView这三个代理方法的顺序和次数,很惊人heightForRowAtIndexPath方法走了四遍,numberOfRowsInSection走了三遍,cellForRowAtIndexPath走了一遍,这就是为什么我们要尽量要使用tableView.rowHeight 替换掉heightForRowAtIndexPath方法的原因,避免不必要的资源浪费,每一次刷新TableView都会是这种顺序执行,千万要注意。
这里也就可以解释一下思考①的问题了,有多少条数据就会走至少多少遍cellForRowAtIndexPath,如果我们static NSString *identifier = @"reuse";不写static也就是不在静态区存取identifier,那么每次走cellForRowAtIndexPath都会copy一个identifier字符串存起来,虽然占用不了多少内存,但是开辟内存和copy总会浪费不必要的资源从而影响UITableView的性能。
注意三、下面介绍UITableViewCell的分割线左右边距控制,直接控制系统的cell分割线,有些特殊需求的例如系统分割线样式不能满足需求的,可以使用自定义,有两种方式①是通过addSubview在cell上添加一条线②是drawRect方法里面自己绘制,贝塞尔曲线绘制
控制系统cell左右边距的代码如下:
///这里通过改变系统绘制的边线来实现分割线左右贯穿
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
//1.调整(iOS7以上)表格分隔线边距
if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
self.tableView.separatorInset = UIEdgeInsetsZero;
}
//2.调整(iOS8以上)tableView边距
if([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]){
[cell setPreservesSuperviewLayoutMargins:NO];
}
//3.调整(iOS8以上)view边距
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
注意四、说到分割线,在实际的开发中系统的分割线很是单调,往往不能满足产品设计那挑剔的眼光,这里忍不住要吐槽一下产品经理和设计(虽然不一定都是像我说的这样的),他们老是觉得系统的是最丑的,虽然有时候是这样,就像系统cell分割线,但是许多情况下就是最好的,不要觉得花哨的就是好的,不仅耗费性能而且BUG频频,百害而无一利,更不要为了所谓的成就感,非要自己设计一套与iOS系统格格不入的东西来取悦视觉。。。
自定义分割线样式的代码如下:
纯代码自定义cell .h 文件
#import <UIKit/UIKit.h>
#define kNewTableViewCellId @"NewTableViewCellIdentifier"
typedef enum : NSUInteger {
SeperateStyle_Long,///长分割线
SeperateStyle_Short,///短分割线
SeperateStyle_LongWidth,///长宽分割线
} SeperateStyle;
@interface NewTableViewCell : UITableViewCell
@property (nonatomic, assign)SeperateStyle seperateStyle;////分割线样式
@end
.m文件 顺便贴上自定义cell选中色的实现方式,很简单,看代码注释
#import "NewTableViewCell.h"
@implementation NewTableViewCell
- (void)awakeFromNib {
// Initialization code
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.selectionStyle = UITableViewCellSelectionStyleNone;///先设置系统cell的选中样式
}
return self;
}
-(void)setSeperateStyle:(SeperateStyle)seperateStyle
{
_seperateStyle = seperateStyle;
// ///方法一 addSubView
// ({
// switch (seperateStyle) {
// case SeperateStyle_Long:{
// UIView *sep = [self addSeperateViewWithwidth:0.5 isLong:YES];
// [self.contentView addSubview:sep];
// break;
// }
// case SeperateStyle_Short:{
// UIView *sep = [self addSeperateViewWithwidth:0.5 isLong:NO];
// [self.contentView addSubview:sep];
// break;
// }
// case SeperateStyle_LongWidth:{
// UIView *sep = [self addSeperateViewWithwidth:3 isLong:YES];
// [self.contentView addSubview:sep];
// break;
// }
// default:
// break;
// }
// });
({
///方法二 贝塞尔曲线绘制
[self setNeedsDisplay];
});
}
-(void)drawRect:(CGRect)rect
{
[super drawRect:rect];
UIBezierPath *path = [UIBezierPath bezierPath];
CGPoint start = CGPointMake(0, self.frame.size.height);
CGPoint end = CGPointMake(self.frame.size.width, self.frame.size.height);
CGFloat w = 0.5;
switch (self.seperateStyle) {
case SeperateStyle_Long:{
break;
}
case SeperateStyle_Short:{
start = CGPointMake(20, self.frame.size.height);
end = CGPointMake(self.frame.size.width, self.frame.size.height);
break;
}
case SeperateStyle_LongWidth:{
w = 3;
break;
}
default:
break;
}
[path moveToPoint:start];
[path addLineToPoint:end];
[path setLineCapStyle:kCGLineCapRound];
[path setLineJoinStyle:kCGLineJoinRound];
path.lineWidth = w;
[[UIColor lightGrayColor]setStroke];
[path stroke];
}
///封装的分割线初始化方法
- (UIView *)addSeperateViewWithwidth:(CGFloat)w isLong:(BOOL)isLong
{
CGFloat x = 0;
if (!isLong) {
x = 20;
}
UIView *sep = [[UIView alloc]initWithFrame:CGRectMake(x, self.frame.size.height-0.5, self.frame.size.width-2*x, w)];
sep.backgroundColor = [UIColor redColor];
sep.tag = 10080;
return sep;
}
///设置选中样式
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected) {
self.backgroundColor = [UIColor cyanColor];
}else{
self.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.3];
}
}
@end
这是使用方式,但是要把系统的样式设置成无:_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;///在这里先把系统的cell的分割线关掉
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NewTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kNewTableViewCellId];///在tableView的重用队列里面取带有identifier标记的cell,也就是目标cell
if (!cell) {///如果重用池(重用队列)里没有这种cell
cell = [[NewTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kNewTableViewCellId];///没有目标cell就去初始化新的cell 并制定标记identifier
}
cell.textLabel.text = self.dataArray[indexPath.row];///简单的可以直接用系统的cell
cell.seperateStyle0 = SeperateStyle_LongWidth;///其实这两步应该交给cell自己处理,由于数据原因写在这里
return cell;
}
热门评论
感谢,很有用,一直苦恼于cell的分割线,mark,mark,mark!