IOS - 自定义cell

来源:互联网 发布:黑马校对软件多少钱 编辑:程序博客网 时间:2024/05/29 16:41

因为休假了好几天, 好多东西都忘记了,所以决定写一篇开发过程,找找缺漏........



模拟实现一个团购界面


底部按钮




我们知道tableview 是可以用三部分描述的

tableHeaderView + tableFooterView + cell

我们先实现cell部分, 在此之前先把数据模拟加载.这次详细的复习下数据的模拟加载.

1.数据加载

将数据封装成对象, 然后放到数组中.

我们会在内存中用一个数组来存放数据, 我们希望将数据封装起来, 所以创建一个类, 用来描述所有的数据.

(根据plist文件在类中定义属性, 属性名字最好和plist中的属性名一样,这样我们可以使用KVC的方式读取. 对于源数据封装到plist中, 我们最常见的是每一条记录封装成一个字典项,这样当我们读取的时候可以用KVC的 setValuesForKeysWithDictionary: (NSDictionary *) ;  语句进行读取.)

在类中定义完属性, 还需要定义方法, 用来初始化并从文件中读取数据


- (instancetype)initWithDic:(NSDictionary *)dic;+ (instancetype)groupBuyingWithDic:(NSDictionary *)dic;  //用类方法, 直接返回用字典转换为模型的对象.
+ (NSMutableArray *)groupBuyingsList;  
实现: 
- (instancetype)initWithDic:(NSDictionary *)dic{    if (self = [super init]) {        [self setValuesForKeysWithDictionary:dic];   //读取数据    }    return self;}+ (instancetype)groupBuyingWithDic:(NSDictionary *)dic{    return [[self alloc] initWithDic:dic];   }+ (NSMutableArray *)groupBuyingsList     //将封装好的对象 加载到数组中, 返回给内存中模拟的数组{    //加载plist    NSString *path = [[NSBundle mainBundle] pathForResource:@"tgs" ofType:@"plist"];    NSArray *dicArray = [NSArray arrayWithContentsOfFile:path];        //字典转模型    NSMutableArray *tmpArray = [NSMutableArray array];  //将要返回给内存中的数组    for (NSDictionary *dic in dicArray) {        CZGroupBuying *groupBuying = [CZGroupBuying groupBuyingWithDic:dic];        [tmpArray addObject:groupBuying];    }    return tmpArray;}

当我们的字典项中还嵌套了数组, 数组又嵌套了字典的时候 ,我们需要两次转换..

比如这种..

+ (NSArray *) carGroupsList{    NSString * path = [[NSBundle mainBundle] pathForResource: @"cars_total" ofType: @"plist"];    NSArray * dicArray = [NSArray arrayWithContentsOfFile: path];        NSMutableArray * tmpArray = [NSMutableArray array];        for (NSDictionary * dic in dicArray) {        AMCarGroup * cargroup = [AMCarGroup carGroupWithDic: dic];        NSMutableArray * tmpCarArray = [NSMutableArray array];        for (NSDictionary * tmpdic in cargroup.cars) {    //在加一次循环,读取嵌套的字典中的内容...                        AMcar * car = [AMcar carWithDic: tmpdic];            [tmpCarArray addObject: car];        }                cargroup.cars = tmpCarArray;        [tmpArray addObject: cargroup];    }    return tmpArray;}


由于上面的封装, 所以在给内存中模拟的数组, 加载数据就很简单了...


- (NSMutableArray *)groupBuyings{    if (_groupBuyings ==nil) {        _groupBuyings = [CZGroupBuying groupBuyingsList];    }    return _groupBuyings;}

2. 自定义cell 

大多时候,我们需要进行自定义cell, 所以要用到xib, 在xib中布局好控件后,我们将它封装成类. 并且 这个类是继承  UITableViewCell类的, 这一点很重要. 

但是,控件还没有描述信息, 所以我们再在类中添加一个信息的属性.

@class CZGroupBuying;@interface CZGroupBuyingCell : UITableViewCell@property (nonatomic, strong) CZGroupBuying *groupBuying;+ (instancetype)groupBuyingCellWithTableView:(UITableView *)tableView;@end

因为我们已经将描述信息封装成了类,所以我们字需要定义一个对象属性即可.

而我们定义的类方法,是直接从xib中读取控件, 这里需要主要的是, 需要传入一个UITableView * 参数, 因为在创建缓冲池的时候需要用到.

实现:

+ (instancetype)groupBuyingCellWithTableView:(UITableView *)tableView{    static NSString *reuseId = @"gb";    CZGroupBuyingCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseId];    if (cell == nil) {        cell = [[[NSBundle mainBundle] loadNibNamed:@"CZGroupBuyingCell" owner:nil options:nil] lastObject];    }    return cell;}//重写属性的setter方法,给子控件赋值- (void)setGroupBuying:(CZGroupBuying *)groupBuying{    _groupBuying = groupBuying;        self.titleView.text = groupBuying.title;    self.priceView.text = [NSString stringWithFormat:@"¥ %@",groupBuying.price];    self.buyCountView.text = [NSString stringWithFormat:@"%@人已购买",groupBuying.buyCount];    self.iconView.image = [UIImage imageNamed:groupBuying.icon];}

这里再说明下, 我们将xib中的控件, 封装成的类是继承UITableViewCell类的..然后通过类方法 ,返回xib中读取到的对象(控件).

最后在数据源协议方法中调用

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    //1 创建可重用的自定义的cell    CZGroupBuyingCell *cell = [CZGroupBuyingCell groupBuyingCellWithTableView:tableView];        //2 设置cell内部的子控件    CZGroupBuying *gb = self.groupBuyings[indexPath.row];        cell.groupBuying = gb;   //重写的setter方法    //3 返回    return cell;}


 3. 创建tableHeaderView

因为tableHeaderView是一个UIView所以可以很随意的使用控件..这里我们用到的是一个scrollView,  正好复习下,所详细说一下...

由于这个头部控件 ,是多个控件所以用xib 组合一下, 最重要的还是scrollView. 

当我们在xib中创建好scrollView的时候 ,由于我们需要大量操作他,我们使用最简单的方法, 直接连线解决, 这样就可以得到一个outlet属性...

首先定义xib的实现类, 用类方法返回加载到的控件.因为加载到的控件里面的scrollView需要滚动, 他的滚动时机,需要一个 方法控制


- (void)awakeFromNib{    CGFloat iconW = self.scrollView.frame.size.width;    CGFloat iconH = self.scrollView.frame.size.height;    for (int i = 0; i < 5; i++) {        NSString *imgName = [NSString stringWithFormat:@"ad_%02d",i];        UIImageView *iconView = [[UIImageView alloc] init];        [self.scrollView addSubview:iconView];                iconView.image = [UIImage imageNamed:imgName];                        CGFloat iconX = i * iconW;        CGFloat iconY = 0;        iconView.frame = CGRectMake(iconX, iconY, iconW, iconH);    }    self.scrollView.contentSize = CGSizeMake(5 * iconW, 0);}

这个函数 是在xib加载完成的时候 触发的..我们只需要实现他即可....

注意这次是代码实现的imageview控件, 需要我们设置imageview的位置

iconView.frame = CGRectMake(iconX, iconY, iconW, iconH);

最后还需要设置  scrollview的滚动范围.

 self.scrollView.contentSize = CGSizeMake(5 * iconW, 0);


4. 创建tableFooterView

同样还是xib先实现

这个布局很具有代表性, 首先最外层是一个View, 所有的控件都在这个View中, 然后根据效果, 再点击了加载更多按钮后要显示一个lable..

这样当需要要操作某些控件的时候, 都能清晰的找到其父控件 , 我们只需要对其父控件进行隐藏 或显示 , 就可以不必挨个的对其子控件 设置隐藏或显示...


这想说的是, 我们使用了一个代理 去实现点击按钮后要触发的事件...复习下代理:

1.给相应的类定义代理协议, 并声明 该类还具备的某些能力

 

@protocol CZFooterViewDelegate <NSObject>  //定义协议@optional- (void)footerViewDidClickedLoadMoreBtn:(CZFooterView *)footerView;   //具备的能力@end
上面的footerViewDidClickedLoadMoreBtn:(CZFooterView *)footerView    参数是一个 czfooterview * 类型的. 这个footerview 参数就是从xib中读取的控件..

2. 在类添加 与 代理 沟通的媒介 (代理属性)

@interface CZFooterView : UIView//2 定义代理属性@property (nonatomic, weak) id<CZFooterViewDelegate> delegate;  //代理属性+ (instancetype)footerView;@end

3. 用点击按钮所注册的事件处理方法中, 调用代理属性 去调用协议中的方法

- (IBAction)loadMoreClick {    self.loadMoreBtn.hidden = YES;          self.loadMoreView.hidden = NO;        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        self.loadMoreBtn.hidden = NO;        self.loadMoreView.hidden = YES;                //3 向代理对象发送消息        if ([self.delegate respondsToSelector:@selector(footerViewDidClickedLoadMoreBtn:)]) {            [self.delegate footerViewDidClickedLoadMoreBtn:self];        }    });    }

上面代码中的self 就是xib中所读取到的控件, 因为我们的xib文件的实现类就是CZfooterView, 虽然这个类中没有其他属性, 看似是一个空类, 但是我们仍可以用self 来描述他所产生的对象.

self --------> CZfooterVIew对象.

我们在写方法的时候, 我们是在为对象 写方法...类方法 也是 内部调用了对象的.

再加深下对self 的理解...................





0 0
原创粉丝点击