自定义UITableViewCell

network | | 访问(65)
// TgCell.h文件 视图View
#import <UIKit/UIKit.h>
@class Tg;

@interface TgCell : UITableViewCell

#warning 这里设置此模型属性是为了接收外界传递进来的模型数据,有了外面的数据传入,才能具体的起到作用
/** 团购的数据模型 */
@property (nonatomic, strong) Tg *tg;

/** 提供一个类方法,可以快速创建 Cell */
+ (instancetype)cellWithTableView:(UITableView *)tableView;

@end
// TgCell.m文件 视图View
#import "TgCell.h"
#import "Tg.h"

@interface TgCell()
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UILabel *priceLabel;
@property (weak, nonatomic) IBOutlet UILabel *buyCountLabel;
@end

@implementation TgCell

+ (instancetype)cellWithTableView:(UITableView *)tableView
{
    // 1. 可重用标示符
    static NSString *ID = @"Cell";
    // 2. tableView查询可重用Cell
    TgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    // 3. 如果没有可重用cell
    if (cell == nil) {
        NSLog(@"加载XIB");
        // 从XIB加载自定义视图
        cell = [[[NSBundle mainBundle] loadNibNamed:@"TgCell" owner:nil options:nil] lastObject];
    }
    
    return cell;
}

- (void)setTg:(Tg *)tg
{
    // setter方法中,第一句要赋值,否则要在其他方法中使用模型,将无法访问到
    _tg = tg;

    self.titleLabel.text = tg.title;
    self.iconView.image = [UIImage imageNamed:tg.icon];
    self.priceLabel.text = tg.price;
    self.buyCountLabel.text = tg.buyCount;
}

#pragma mark - 模板提供的方法
/** 
 初始化方法
 
 使用代码创建Cell的时候会被调用,如果使用XIB或者Storyboard,此方法不会被调用
 */
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        NSLog(@"%s", __func__);
    }
    return self;
}

/**
 从XIB被加载之后,会自动被调用,如果使用纯代码,不会被执行
 */
- (void)awakeFromNib
{
    NSLog(@"%s", __func__);
    self.contentView.backgroundColor = [UIColor clearColor];
}

/**
 Cell 被选中或者取消选中是都会被调用
 
 如果是自定义Cell控件,所有的子控件都应该添加到contentView中
 */
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
    if (selected) {
        self.contentView.backgroundColor = [UIColor redColor];
    } else {
        self.contentView.backgroundColor = [UIColor greenColor];
    }
}

@end
// Tg.h文件 模型Model
#import <Foundation/Foundation.h>

@interface Tg : NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *icon;
@property (nonatomic, copy) NSString *price;
@property (nonatomic, copy) NSString *buyCount;

- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)tgWithDict:(NSDictionary *)dict;

+ (NSMutableArray *)tgs;

@end
// Tg.m文件 模型Model
#import "Tg.h"

@implementation Tg

- (instancetype)initWithDict:(NSDictionary *)dict
{
    self = [super init];
    if (self) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}

+ (instancetype)tgWithDict:(NSDictionary *)dict
{
    return [[self alloc] initWithDict:dict];
}

+ (NSMutableArray *)tgs
{
    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tgs.plist" ofType:nil]];
    
    NSMutableArray *arrayM = [NSMutableArray array];
    for (NSDictionary *dict in array) {
        [arrayM addObject:[self tgWithDict:dict]];
    }
    
    return arrayM;
}

@end
// TgFooterView.h文件 视图View
#import <UIKit/UIKit.h>
@class TgFooterView;

@protocol TgFooterViewDelegate <NSObject>

@optional
/** 视图的下载按钮被点击 */
- (void)tgFooterViewDidDownloadButtonClick:(TgFooterView *)footerView;

@end

@interface TgFooterView : UIView

// 代理如果使用强引用,就会产生循环引用,造成控制器和子视图都无法被释放,造成内存泄露
@property (nonatomic, weak) id <TgFooterViewDelegate> delegate;

+ (instancetype)footerView;

/** 刷新数据结束后,更新页脚的视图显示 */
- (void)endRefresh;

@end
// TgFooterView.m文件 视图View
#import "TgFooterView.h"

@interface TgFooterView()
@property (weak, nonatomic) IBOutlet UIButton *loadMoreButton;
@property (weak, nonatomic) IBOutlet UIView *tipsView;
@end

@implementation TgFooterView

+ (instancetype)footerView
{
    return [[[NSBundle mainBundle] loadNibNamed:@"TgFooterView" owner:nil options:nil] lastObject];
}

- (IBAction)loadMore
{
    NSLog(@"加载更多");
    // 1. 隐藏按钮
    self.loadMoreButton.hidden = YES;
    // 2. 显示提示视图
    self.tipsView.hidden = NO;

    // 3.1 判断代理是否实现了协议方法
    if ([self.delegate respondsToSelector:@selector(tgFooterViewDidDownloadButtonClick:)]) {
        [self.delegate tgFooterViewDidDownloadButtonClick:self];
    }
}

/** 视图控制器刷新完成调用方法 */
- (void)endRefresh
{
    // 4. 加载完成数据
    self.loadMoreButton.hidden = NO;
    self.tipsView.hidden = YES;
}

@end
TgCell.xib文件
TgHeadView.xib文件
TgFooterView.xib文件
// ViewController.h控制器
#import <UIKit/UIKit.h>

@interface ViewController : UITableViewController

@end
// ViewController.m控制器
#import "ViewController.h"
#import "Tg.h"
#import "TgCell.h"
#import "TgFooterView.h"

@interface ViewController () <TgFooterViewDelegate>
@property (nonatomic, strong) NSMutableArray *tgs;
@end

@implementation ViewController

- (NSArray *)tgs
{
    if (_tgs == nil) _tgs = [Tg tgs];
    return _tgs;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.tableView.rowHeight = 80;
    
    // 调整边距,可以让表格视图让开状态栏
    self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0);
    
    // footerView
    // footerView的宽度会和表格整体宽度一致,只需要指定高度即可
//    self.tableView.tableFooterView = [UIButton buttonWithType:UIButtonTypeContactAdd];
//    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 44)];
//    view.backgroundColor = [UIColor redColor];
//    self.tableView.tableFooterView = view;
    // 从XIB加载最后一个视图设置为footerView
    TgFooterView *footer = [TgFooterView footerView];
    // 视图控制器成为footerView的代理
    footer.delegate = self;
    self.tableView.tableFooterView = footer;
    
    self.tableView.tableHeaderView = [[[NSBundle mainBundle] loadNibNamed:@"TgHeadView" owner:nil options:nil] lastObject];
}

///** 隐藏状态栏 */
//- (BOOL)prefersStatusBarHidden
//{
//    return YES;
//}

#pragma mark - footerView的代理方法
/** 
 预处理指令
 #if 0
 所有代码都不会执行
 
 #endif
 */
#if 1
- (void)tgFooterViewDidDownloadButtonClick:(TgFooterView *)footerView
{
    // 模拟取网络上获取数据加载数据
    NSLog(@"努力加载数据中....");
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 获得网络数据之后执行的操作
        
        // 向数组中添加数据,模拟网络加载完成之后的效果
        NSDictionary *dict = @{@"title": @"哈哈", @"icon": @"ad_00", @"price": @"100.2", @"buyCount": @"250"};
        Tg *tg = [Tg tgWithDict:dict];
        
        NSLog(@"加数据前 %lu", (unsigned long)self.tgs.count);
        
        [self.tgs addObject:tg];
        
        NSLog(@"加数据后 %lu", (unsigned long)self.tgs.count);
        // 刷新数据
        //    [self.tableView reloadData];
        // 新建一个indexPath
        NSIndexPath *path = [NSIndexPath indexPathForRow:(self.tgs.count - 1) inSection:0];
        [self.tableView insertRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationMiddle];
        
        // 通知页脚视图调整视图显示状态
        [footerView endRefresh];
    });
    
}
#endif

#pragma mark - 数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.tgs.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1. 创建cell
    TgCell *cell = [TgCell cellWithTableView:tableView];
    
    // 2. 通过数据模型,设置Cell内容,可以让视图控制器不需要了解cell内部的实现细节
    cell.tg = self.tgs[indexPath.row];
    
    return cell;
}

@end