一個輕量級的資料驅動列表框架 YHListKit

ShannonChenCHN發表於2018-01-31

GitHub 原始碼地址

YHListKit 是一個基於 UICollectionView 的、輕量級的資料驅動列表框架,其核心思想在於通過 Adapter 模式將繁瑣的 UICollectionView 相關代理方法轉變成資料驅動的介面,更貼近人類的思維方式,同時還將註冊 cell 和 dequeue cell 的邏輯封裝到了內部。另外,還通過藉助訊息轉發機制,將 UICollectionViewDelegateUIScrollViewDelegate 等代理方法由中間人轉發出來,以供外面的業務方在需要時可以使用。

特性

  • 基於 UICollectionView 的介面卡,不需要再面對繁瑣的 register -> data source -> dequeue 流程
  • 真正的資料驅動
  • 自動快取 cell/section header/section footer 的高度
  • 使用了面向協議的設計,去耦合
  • 不需要繼承,即插即用,無侵入性

預覽效果圖

一個輕量級的資料驅動列表框架 YHListKit

架構

一個輕量級的資料驅動列表框架 YHListKit

原來建立實現一個列表需要跟 UICollectionView 繁瑣的 API 打交道:

  1. 建立 UICollectionView;
  2. 註冊 cell;
  3. 解析資料/組裝資料;
  4. 至少實現 3 個代理方法,非常繁瑣;
  5. reload data;

使用 YHListKit 之後只需要跟資料搞好關係:

  1. 建立 UICollectionView;
  2. 解析資料/組裝資料(包含 view model);
  3. 建立 YHCollectionViewAdapter,傳入資料,繫結 UICollectionView;
  4. reload data;

程式的本質就是處理資料,UI 是資料的表現層。對於軟體工程師來講,最理想的效果就是寫一個配置檔案,就能看到效果。YHListKit 所做的就是,去掉解析資料之外的多餘步驟,讓我們只需要關心資料,就是這麼簡單。

類、協議 功能
YHCollectionViewCellModel、YHCollectionViewSectionModel 表徵 cell、 section header 和 section footer 相關資料的 view model
YHCollectionViewAdapter 包裝 UICollectionView 代理方法的核心類,將代理回撥形式的介面轉換成 view model 形式的資料驅動介面
YHCollectionViewCell、YHCollectionViewSectionHeaderFooter 定義 cell 和 section header、footer 的通用介面,用來繫結 view model 資料,以及獲取高度
MessageInterceptor 處理訊息轉發的攔截器

使用方法

1. 建立 collection view(這一步跟平時使用 UICollectionView 的程式碼一樣):

self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds
collectionViewLayout:self.collectionViewLayout]; // 這裡也可以使用自己的 layout
self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.collectionView.backgroundColor = [UIColor colorWithRed:244 green:244 blue:244 alpha:1.0];
self.collectionView.alwaysBounceVertical = YES;
[self.view addSubview:self.collectionView];

複製程式碼

2. 建立 YHCollectionViewAdapter ,繫結 collectionView,設定代理:

self.adapter = [[YHCollectionViewAdapter alloc] init];
self.adapter.collectionView = self.collectionView;    // 繫結 collection view
self.adapter.collectionViewDelegate = self;           // 設定代理不是必需的,視業務情況而定
self.adapter.delegate = self;                         // 設定代理不是必需的,視業務情況而定
複製程式碼

3. 設定 view model 資料,也就是建立 section model 和 cell model,配置相關資料(注:這裡僅僅是舉個例子,你可以配置任何你想要展示的資料,只要符合跟示例程式碼中類似的資料結構即可):

// 可以理解為一個 table view 的資料來源由多個 section model 組成,每個 sectionModel 包括 header 和 footer 相關的資訊、cell models、以及 section 本身的資訊。詳見 YHCollectionViewSectionModel 和 YHCollectionViewCellModel 的標頭檔案。

NSMutableArray *sections = [NSMutableArray array];

for (int section = 0; section < 4; section++) {

	BOOL hasMultiColumns = section % 2;

    // 建立 section model
    YHCollectionViewSectionModel *sectionModel = [[YHCollectionViewSectionModel alloc] init];
    sectionModel.sectionIdentifier = [NSString stringWithFormat:@"section_id_%@", @(section)];  // 設定 section 的唯一標識,可選
    NSMutableArray *rows = [NSMutableArray array];
    for (int row = 0; row < 10; row++) {

        // 建立 cell model
        YHCollectionViewCellModel *cellModel = [[YHCollectionViewCellModel alloc] init];
        cellModel.dataModel = [NSString stringWithFormat:@"%i - %i", section, row]; // 設定 model 資料
        cellModel.cellClass = [SCCutomCollectionViewCell class];                    // 設定 cell class
        if (hasMultiColumns) {
                cellModel.cellWidth = 160;
                cellModel.cellHeight = 160;
         } else {
                cellModel.cellHeight = 70;  // 設定 cell 高度,也可以在對應的 cell 中實現相應的協議方法來實現
         }

        [rows addObject:cellModel];
    }

    sectionModel.cellModels = rows; // 設定該 section 的 cell model 集合
    sectionModel.headerClass = [SCCollectionSectionHeaderView class]; // 設定 section header 的 class
    sectionModel.headerHeight = 50;                                   // 設定 section header 的 高度
    sectionModel.footerClass = [SCCollectionSectionFooterView class]; // 設定 section footer 的 class
    sectionModel.footerHeight = 20;                                   // 設定 section footer 的 高度
    
    if (hasMultiColumns) {
       // 還可以設定 section 的一些佈局引數,比如實現一行兩列的效果
        sectionModel.sectionInsets = UIEdgeInsetsMake(10, 20, 10, 20);
        sectionModel.minimumLineSpacing = 15;
    }
    
    [sections addObject:sectionModel];
}

// 傳入資料
self.adapter.sectionModels = sections;

[self.collectionView reloadData];
複製程式碼

4. 除了在 view model 層設定 cell 、 section header 和 section footer 的高度之外,還可以在對應的 view 層設定高度,只需要實現 YHCollectionViewCellYHCollectionViewSectionHeaderFooter 協議中定義的方法即可:

@protocol YHCollectionViewCell <NSObject>

...

+ (CGFloat)cellHeightWithModel:(YHCollectionViewCellModel *)model;
+ (CGFloat)cellWidthWithModel:(YHCollectionViewCellModel *)model;


@end
複製程式碼
@protocol YHCollectionViewSectionHeaderFooter <NSObject>

...

+ (CGFloat)heightWithModel:(YHCollectionViewSectionModel *)model;
+ (CGFloat)widthWithModel:(YHCollectionViewSectionModel *)model;

@end
複製程式碼

更詳細的使用介紹見示例程式碼 Example

系統要求

該專案最低支援 iOS 7.0。

TODO

  • 完善註釋和文件
  • Swift Version
  • Carthage Support

致謝❤️

感謝 bestswifterIGListKit 帶來的啟發。

如果你有好的想法和問題,歡迎提 issue 和 pull request。?

許可證

該專案使用的是 MIT 許可證。 詳情見 LICENSE 檔案。

相關文章