手记

iOS学习笔记--UITableView( 一)

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;
}
4人推荐
随时随地看视频
慕课网APP

热门评论

感谢,很有用,一直苦恼于cell的分割线,mark,mark,mark!

查看全部评论