1. 程式人生 > >AutoLayout自定義tableViewCell --- Masonry + UITableView+FDTemplateLayoutCell 純程式碼實現

AutoLayout自定義tableViewCell --- Masonry + UITableView+FDTemplateLayoutCell 純程式碼實現

AutoLayout自定義tableViewCell — Masonry + UITableView+FDTemplateLayoutCell 純程式碼實現

在被frame虐的體無完膚的樓主,在新專案開始的時候毅然決定使用Autolayout來實現專案的絕大多介面,當然這個絕大多數的介面也包括tableView的Cell。本來在樓主看來,這個autolayout根本就是用在storyboard和xib的神器,但用在純程式碼中是相當的雞肋,食之無味,棄之可惜,擔憂不捨器自動佈局的優點,在網上找了很多關於aotoulayout的資料及開源庫:

  • Masonry
  • UITableView+FDTemplateLayoutCell

效果如下:

可以顯示兩種不一樣的cell

兩個開源庫足以

  • Masonry 用來佈局控制元件的位置關係
  • UITableView+FDTemplateLayoutCell 計算各個cell之間的高度

瞭解並使用

這裡面的都比較詳細的demo介紹,而樓主的demo和這幾位哥們的都有點不一樣,樓主是自定義cell、自定義cell、自定義cell,呼……重要的事情都要書三遍。

廢話就不多說,直接上程式碼

首先建立專案,樓主是個程式碼控,比較不喜歡專案裡面有stroyboard,這裡就不浪費大家的時間,自己創好一個沒有空白的專案(也就是刪了strayboard,改info.plish的事)哈。。。。

必須要有UITableViewController 、UITableViewCell、CellModel這三個類

UITableViewController控制器:

首先的有個裝模型的陣列:(樓主的情況是隻有一組)
@interface TableViewController ()

@interface TableViewController ()
@property (nonatomic,strong) NSMutableArray *status; // 動態模型
@end

@implementation TableViewController:

@implementation TableViewController
- (NSMutableArray *)status { // 懶載入模型陣列 if (!_status) { _status = [NSMutableArray array]; } return _status; } - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor grayColor]; // 背景色 self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; // 不顯示分割線 [self jsonData]; // 載入json } #pragma mark - 載入json資料 - (void)jsonData { NSString *path = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"]; // 解析json NSData *data = [NSData dataWithContentsOfFile:path]; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; NSArray *jsonArray = dict[@"status"]; NSMutableArray *arrM = [NSMutableArray array]; [jsonArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [arrM addObject:[XQFeedModel feedWithDictionary:obj]]; }]; self.status = arrM; [self.tableView registerClass:[StatusCell class] forCellReuseIdentifier:@"status"]; // 不要忘註冊cell [self.tableView reloadData]; // 同時要重新整理表格 } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.status.count;; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { StatusCell *cell = [StatusCell cellWithTableView:tableView]; cell.status = self.status[indexPath.row]; return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [self.tableView fd_heightForCellWithIdentifier:@"status" cacheByIndexPath:indexPath configuration:^(StatusCell *cell) { cell.status = self.status[indexPath.row]; }]; } @end
到這裡控制器的戲份也就沒有了

模型類:

模型類也即是把json裡面的key一個一個寫在模型的屬性上,然後再賦一下值

@interface StatusModel : NSObject

@interface StatusModel : NSObject

@property (copy, nonatomic) NSString *username;
@property (copy, nonatomic) NSString *title;
@property (copy, nonatomic) NSString *content;
@property (copy, nonatomic) NSString *imageName;
@property (copy, nonatomic) NSString *time;
@property (copy, nonatomic) NSString *icon;
@property (copy, nonatomic) NSString *type;

+ (instancetype) feedWithDictionary:(NSDictionary *) dictionary;

- (instancetype) initWithDictionary:(NSDictionary *) dictionary;
@end

這些看個人習慣,有用自動轉模型的也可以那個,這個demo就隨便寫寫,哈…

@implementation StatusModel

@implementation StatusModel
+ (instancetype)feedWithDictionary:(NSDictionary *)dictionary {
    return [[self alloc] initWithDictionary:dictionary];
}

- (instancetype) initWithDictionary:(NSDictionary *) dictionary {
    if (self = [super init]) {
        self.title = dictionary[@"title"];
        self.content = dictionary[@"content"];
        self.username = dictionary[@"username"];
        self.time = dictionary[@"time"];
        self.imageName = dictionary[@"imageName"];
        self.icon = dictionary[@"icon"];
        self.type = dictionary[@"type"];
    }
    return self;
}
@end

檢視控制元件類(說白了就是cell):

一般有這個情況,用自動佈局,就不能用frame計算尺寸,否則會報錯.會報錯.會報錯,樓主也是有故事的人……

#樓主有個這個返回工廠方法cell的習慣

@interface StatusCell : UITableViewCell

@class StatusModel;
@interface StatusCell : UITableViewCell
@property (strong, nonatomic) StatusModel *status;
+ (instancetype)cellWithTableView:(UITableView *)tableView;
@end
這裡下面的TopView *topGroup,MidView *midGroup,BottomView *bottomGroup都是樓主自定義的控制元件,裡面呢也全是masonry約束的控制元件,有興趣的親可以自己下demo來研究研究,這裡就不詳細列出了

@implementation StatusCell

@interface StatusCell ()

@property (nonatomic,strong) UIView *cellGroup; // 底板
@property (nonatomic,strong) TopView *topGroup; // 頂部組別
@property (nonatomic,strong) MidView *midGroup; // 中部組別
@property (nonatomic,strong) BottomView *bottomGroup; // 底部組別
@property (assign, nonatomic) BOOL didSetupConstraints; // 判斷是否已加過約束

@end

@implementation StatusCell

+ (instancetype)cellWithTableView:(UITableView *)tableView
{
    static NSString *ID = @"status";
    StatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (!cell) {
        cell = [[StatusCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    }
    return cell;
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {

    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        self.backgroundColor = [UIColor grayColor];
        [self createView];
        [self updateConstraints];
    }
    return self;
}

- (void)updateConstraints
{
    if (!self.didSetupConstraints) {
        [self setttingViewAtuoLayout];
        self.didSetupConstraints = YES;
    }
    [super updateConstraints];
}

#pragma make 建立子控制元件
- (void) createView
{
#pragma mark - 共有的
    self.cellGroup = [[UIView alloc] init];
    self.cellGroup.translatesAutoresizingMaskIntoConstraints = NO;
    self.cellGroup.layer.cornerRadius = 3;
    self.cellGroup.clipsToBounds = YES;
    self.cellGroup.backgroundColor = [UIColor whiteColor];
    [self.contentView addSubview:self.cellGroup];

#pragma mark - 頭部
    self.topGroup = [[XQTopView alloc] init];
    self.topGroup.translatesAutoresizingMaskIntoConstraints = NO;
    self.topGroup.layer.cornerRadius = 3;
    self.topGroup.clipsToBounds = YES;
    self.topGroup.backgroundColor = [UIColor whiteColor];
    [self.cellGroup addSubview:self.topGroup];

#pragma mark - 公眾號推送
    self.midGroup = [[XQMidView alloc] init];
    self.midGroup.translatesAutoresizingMaskIntoConstraints = NO;
    self.midGroup.layer.cornerRadius = 3;
    self.midGroup.clipsToBounds = YES;
    self.midGroup.backgroundColor = [UIColor whiteColor];
    [self.cellGroup addSubview:self.midGroup];

#pragma mark - 底部組別
    self.bottomGroup = [[XQBottomView alloc] init];
    self.bottomGroup.translatesAutoresizingMaskIntoConstraints = NO;
    self.bottomGroup.layer.cornerRadius = 3;
    self.bottomGroup.clipsToBounds = YES;
    self.bottomGroup.backgroundColor = [UIColor whiteColor];
    [self.cellGroup addSubview:self.bottomGroup];
}

#pragma mark - 在此方法內使用 Masonry 設定控制元件的約束
- (void) setttingViewAtuoLayout
{
    [self top];
    [self mid];
    [self bottom];
}

- (void)setStatus:(StatusModel *)status
{
    _status = status;
    self.topGroup.status = status;
    self.midGroup.status = status;
    self.bottomGroup.status = status;
}

- (void)top
{
    [self.cellGroup mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.contentView).offset(7);
        make.left.mas_equalTo(self.contentView).offset(10);
        make.bottom.mas_equalTo(self.contentView);
        make.right.mas_equalTo(self.contentView).offset(-10);
    }];

    [self.topGroup mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.cellGroup).offset(10);
        make.left.mas_equalTo(self.cellGroup).offset(10);
        make.right.mas_equalTo(self.cellGroup).offset(-10);
        make.height.mas_equalTo(40);
    }];
}

- (void)mid
{
    [self.midGroup mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.topGroup.mas_bottom);
        make.left.mas_equalTo(self.cellGroup).offset(10);
        make.right.mas_equalTo(self.cellGroup).offset(-10);
        make.bottom.mas_equalTo(self.bottomGroup.mas_top);
    }];
}

- (void)bottom
{
    [self.bottomGroup mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(self.cellGroup).offset(10);
        make.right.mas_equalTo(self.cellGroup).offset(-10);
        make.height.mas_equalTo(@33);
        make.bottom.mas_equalTo(self.contentView.mas_bottom);
    }];
}

可以顯示兩種不一樣的cell,只是在不同條件下顯示不同風格的cell,關鍵點在與控制約束的啟用和不啟用,和更新約束高度,另外樓主測試過,如果把不需顯示的控制元件hidden變為yes的記憶體會比較少,系統免去話控制元件的任務肯定會優化效能一些,哈….

另外感謝@格式化油條 提供的技術貼,樓主的也是基於格式化油條大大的技術貼延伸開來的,鑑於網上的教程都是stroyboard和xib的,樓主等人也只能讓程式碼版的也來個正名,autolayout不是視覺化的專利,程式碼也是很好用很直觀的…..哈…未完待續!! 另網路網路大神歡迎來噴,因為本人也需要多點不一樣的觀點來創新一下思維,大家多多指教!!!

* 喜歡九宮格的可以開啟midView中的註釋*

有錯請註明,謝謝!!