时间都去哪儿了
时间都去哪儿了?这是我们自问最多的一个问题。每天有
开不完的会
,写不完的页面
,调不完的接口
,加不完的班
……
- 当我们静下心来忽然发现,时间都浪费在
copy
和paste
上了。 - 你是否会发现
UITableView
,UICollectionView
在项目页面中的使用频率高达80-90%。 - 你可能也会发现大部分页面代码结构相同或者相似,不同的地方可能在于Cell的展示效果有所差异。
- 所以,你的时间都浪费编写重复代码上了。
如何拯救你的时间
- 我们都知道面向对象语言三大特性:
继承
,封装
,多态
。 - 继承:子类继承自父类,父类提供模板,模板可以降低代码的重复性。
- 封装:封装是对某一功能特性的函数或者方法进行封装,它可以提升代码的可维护性和降低耦合度。
- 多态:一个类实例的相同方法在不同情形有不同表现形式。
- 继承,封装,多态就是拯救我们时间的三把利器。
UITableView
案例
- 大部分项目中,滚动列表页面都是基于
UITableView
来实现的,每个页面常规编码步骤大致如下: -
- 创建
ViewController
- 创建
-
- 自定义
TableViewCell
- 自定义
-
- 初始化
UITableView
- 初始化
-
- 注册
TableViewCell
- 注册
-
- 遵从
UITableViewDelegate
,UITableViewDataSource
代理
- 遵从
-
- 实现
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
以及- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
等代理
- 实现
-
- 编写网络加载及数据加工模块
-
- 将数据与Cell进行绑定
- ……
- 基本上每个页面都是重复如上操作。
步骤分解
- 哪些步骤可以封装到基类中呢?
- 通过分析我们可以发现,步骤1,7,8是每次必须要做了,因为每个页面存在差异性,不适合封装;而2,3,5,6有共性,可以封装到基类中。步骤4应该封装到
TableViewCell
分类中。 - 选
Controller
作为基类(模板)还是UIView
作为基类呢? *Controller
扮演的是协调者的工作,而UIView
负责页面展示,所以UIView
更适合作为基类。
代码实现如下:
- 注册TableViewCell封装
//UITableViewCell分类的.h文件
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UITableViewCell (XBAdd)
/** 从xib加载cell,自动复用 */
+ (instancetype)cellFromXibWithTableView:(UITableView *)tableView;
/** 加载纯代码cell,自动复用 */
+ (instancetype)cellFromClassWithTableView:(UITableView *)tableView;
@end
NS_ASSUME_NONNULL_END
//UITableViewCell分类的.m文件
#import "UITableViewCell+XBAdd.h"
#import "UIView+XBAdd.h"
@implementation UITableViewCell (XBAdd)
/** 从xib加载cell,自动复用 */
+ (instancetype)cellFromXibWithTableView:(UITableView *)tableView {
NSString *identifier = self.reusedId;
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
NSLog(@"register cell");
[tableView registerNib:[UINib nibWithNibName:identifier bundle:nil]
forCellReuseIdentifier:identifier];
cell = [self cellFromXibWithTableView:tableView];
}
return cell;
}
/** 加载纯代码cell,自动复用 */
+ (instancetype)cellFromClassWithTableView:(UITableView *)tableView {
NSString *identifier = self.reusedId;
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
NSLog(@"register cell");
[tableView registerClass:NSClassFromString(identifier) forCellReuseIdentifier:identifier];
cell = [self cellFromXibWithTableView:tableView];
}
return cell;
}
@end
复制代码
UITableViewHeaderFooter
注册封装
//分类.h文件
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UITableViewHeaderFooterView (XBAdd)
/** 从xib加载, 自动复用 */
+ (instancetype)headerFooterViewFromXibWithTableView:(UITableView *)tableView;
/** 加载纯代码header footer view, 自动复用 */
+ (instancetype)headerFooterViewFromClassWithTableView:(UITableView *)tableView;
@end
NS_ASSUME_NONNULL_END
//分类.m文件
#import "UITableViewHeaderFooterView+XBAdd.h"
#import "UIView+XBAdd.h"
@implementation UITableViewHeaderFooterView (XBAdd)
/** 从xib加载 */
+ (instancetype)headerFooterViewFromXibWithTableView:(UITableView *)tableView {
NSString *identifier = self.reusedId;
UITableViewHeaderFooterView *view =
[tableView dequeueReusableHeaderFooterViewWithIdentifier:identifier];
if (!view) {
NSLog(@"register header footer view");
[tableView registerNib:[UINib nibWithNibName:identifier bundle:nil]
forHeaderFooterViewReuseIdentifier:identifier];
view = [self headerFooterViewFromXibWithTableView:tableView];
}
return view;
}
/** 加载纯代码header footer view, 自动复用 */
+ (instancetype)headerFooterViewFromClassWithTableView:(UITableView *)tableView {
NSString *identifier = self.reusedId;
UITableViewHeaderFooterView *view =
[tableView dequeueReusableHeaderFooterViewWithIdentifier:identifier];
if (!view) {
NSLog(@"register header footer view");
[tableView registerClass:[self class] forHeaderFooterViewReuseIdentifier:identifier];
view = [self headerFooterViewFromXibWithTableView:tableView];
}
return view;
}
@end
复制代码
UIView
对TableView
列表基类的封装
//.h文件
#import <UIKit/UIKit.h>
@class BNBaseTableListView;
@protocol BNBaseTableListViewDelegate <NSObject>
@optional
- (void)tableListView:(BNBaseTableListView *)listView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface BNBaseTableListView : UIView<UITableViewDataSource, UITableViewDelegate>
/** table view*/
@property (nonatomic, strong) UITableView *tableView;
/** dataSource*/
@property (nonatomic, strong) NSArray *dataSource;
/** tableViewStyle*/
@property (nonatomic, assign) UITableViewStyle tableViewStyle;
/** 构造方法*/
- (instancetype)initWithFrame:(CGRect)frame tableViewStyle:(UITableViewStyle)style;
/** BNBaseTableListViewDelegate*/
@property (nonatomic, weak) id<BNBaseTableListViewDelegate>delegate;
/** didSelectRowAtIndexPath actionHandle*/
@property(nonatomic, copy) void(^didSelectRowAtIndexPathHandler)(NSIndexPath *indexPath);
#pragma mark - refreshUI
- (void)refreshUI;
@end
//.m文件
#import "BNBaseTableListView.h"
@implementation BNBaseTableListView
- (instancetype)initWithFrame:(CGRect)frame tableViewStyle:(UITableViewStyle)style
{
self = [super initWithFrame:frame];
if (self) {
self.tableViewStyle = self.tableViewStyle;
}
return self;
}
#pragma mark - ----------------SetupUI----------------
- (void)setupUI {
self.backgroundColor = [UIColor whiteColor];
if ([self.subviews containsObject:self.tableView]) {
[self.tableView removeFromSuperview];
self.tableView = nil;
}
[self addSubview:self.tableView];
[self addLayouts];
}
#pragma mark - ----------------AddLayouts----------------
- (void)addLayouts {
[self.tableView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_offset(0);
}];
}
#pragma mark - ----------------Public Methods----------------
#pragma mark - ----------------refreshUI----------------
- (void)refreshUI {
[self.tableView reloadData];
}
#pragma mark - -------------UICollectionViewDataSource----------------
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return [UITableViewCell cellFromClassWithTableView:tableView];
}
#pragma mark - -------------HeaderFooter----------------
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
return nil;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return CGFLOAT_MIN;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return CGFLOAT_MIN;
}
#pragma mark - ----------------UICollectionViewDelegate-------------------
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
!self.didSelectRowAtIndexPathHandler?:self.didSelectRowAtIndexPathHandler(indexPath);
if ([self.delegate respondsToSelector:@selector(tableListView:didSelectRowAtIndexPath:)]) {
[self.delegate tableListView:self didSelectRowAtIndexPath:indexPath];
}
}
#pragma mark - ----------------Getter & Setter----------------
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:self.tableViewStyle];
_tableView.backgroundColor = self.backgroundColor;
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
_tableView.dataSource = self;
_tableView.delegate = self;
_tableView.estimatedRowHeight = 0;
_tableView.estimatedSectionFooterHeight = 0;
_tableView.estimatedSectionHeaderHeight = 0;
_tableView.rowHeight = UITableViewAutomaticDimension;
}
return _tableView;
}
- (void)setTableViewStyle:(UITableViewStyle)tableViewStyle {
_tableViewStyle = tableViewStyle;
[self setupUI];
}
@end
复制代码
UICollectionView
案例
代码实现如下:
- 注册
CollectionCell
封装
//分类.h文件
NS_ASSUME_NONNULL_BEGIN
@interface UICollectionViewCell (BNAdd)
/** 从xib加载cell,自动复用 */
+ (instancetype)cellFromXibWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath;
/** 加载纯代码cell,自动复用 */
+ (instancetype)cellFromClassWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath;
@end
NS_ASSUME_NONNULL_END
//分类.m文件
#import "UICollectionViewCell+BNAdd.h"
@implementation UICollectionViewCell (BNAdd)
/** 从xib加载cell,自动复用 */
+ (instancetype)cellFromXibWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = self.reusedId;
NSMutableSet *identifierSet = [self setCellIdentifierSetForCollectionView:collectionView];
if (![identifierSet containsObject:identifier]) {
NSLog(@"register nib cell");
[collectionView registerNib:[UINib nibWithNibName:identifier bundle:nil] forCellWithReuseIdentifier:identifier];
[identifierSet addObject:identifier];
}
return [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
}
/** 加载纯代码cell,自动复用 */
+ (instancetype)cellFromClassWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = self.reusedId;
NSMutableSet *identifierSet = [self setCellIdentifierSetForCollectionView:collectionView];
if (![identifierSet containsObject:identifier]) {
NSLog(@"register class cell");
[collectionView registerClass:[self class] forCellWithReuseIdentifier:identifier];
[identifierSet addObject:identifier];
}
return [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
}
/** 关联 IdentifierSet*/
+ (NSMutableSet *)setCellIdentifierSetForCollectionView:(UICollectionView *)collectionView {
if (![collectionView getAssociatedValueForKey:_cmd]) {
NSMutableSet *identifierSet = [[NSMutableSet alloc] init];
[collectionView setAssociateValue:identifierSet withKey:_cmd];
return identifierSet;
}
return [collectionView getAssociatedValueForKey:_cmd];
}
@end
复制代码
- 注册
UICollectionReusableView
封装
//分类.h文件
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UICollectionReusableView (BNAdd)
/// headerReusableViewFromXib
/// @param collectionView UICollectionView
/// @param indexPath indexPath NSIndexPath
+ (instancetype)headerReusableViewFromXibWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath;
/// headerReusableViewFromClass
/// @param collectionView UICollectionView
/// @param indexPath indexPath NSIndexPath
+ (instancetype)headerReusableViewFromClassWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath;
/// footerReusableViewFromXib
/// @param collectionView UICollectionView
/// @param indexPath indexPath NSIndexPath
+ (instancetype)footerReusableViewFromXibWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath;
/// footerReusableViewFromClass
/// @param collectionView UICollectionView
/// @param indexPath indexPath NSIndexPath
+ (instancetype)footerReusableViewFromClassWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath;
@end
NS_ASSUME_NONNULL_END
//分类.m文件
#import "UICollectionReusableView+BNAdd.h"
@implementation UICollectionReusableView (BNAdd)
#pragma mark - ----------------Public Methods----------------
/// headerReusableViewFromXib
/// @param collectionView UICollectionView
/// @param indexPath indexPath NSIndexPath
+ (instancetype)headerReusableViewFromXibWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath {
return [self reusableSupplementaryViewFromXibOfKind:UICollectionElementKindSectionHeader collectionView:collectionView forIndexPath:indexPath];
}
/// headerReusableViewFromClass
/// @param collectionView UICollectionView
/// @param indexPath indexPath NSIndexPath
+ (instancetype)headerReusableViewFromClassWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath {
return [self reusableSupplementaryViewFromClassOfKind:UICollectionElementKindSectionHeader collectionView:collectionView forIndexPath:indexPath];
}
/// footerReusableViewFromXib
/// @param collectionView UICollectionView
/// @param indexPath indexPath NSIndexPath
+ (instancetype)footerReusableViewFromXibWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath {
return [self reusableSupplementaryViewFromXibOfKind:UICollectionElementKindSectionFooter collectionView:collectionView forIndexPath:indexPath];
}
/// footerReusableViewFromClass
/// @param collectionView UICollectionView
/// @param indexPath indexPath NSIndexPath
+ (instancetype)footerReusableViewFromClassWithCollectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath {
return [self reusableSupplementaryViewFromClassOfKind:UICollectionElementKindSectionFooter collectionView:collectionView forIndexPath:indexPath];
}
#pragma mark - ----------------Private Methods----------------
+ (instancetype)reusableSupplementaryViewFromXibOfKind:(NSString *)elementKind collectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = [self.reusedId stringByAppendingString:elementKind];
NSMutableSet *identifierSet = [self setReusableSupplementaryViewIdentifierSetForCollectionView:collectionView];
if (![identifierSet containsObject:identifier]) {
NSLog(@"register nib supplementary view");
[collectionView registerNib:[UINib nibWithNibName:self.reusedId bundle:nil] forSupplementaryViewOfKind:elementKind withReuseIdentifier:identifier];
[identifierSet addObject:identifier];
}
return [collectionView dequeueReusableSupplementaryViewOfKind:elementKind withReuseIdentifier:identifier forIndexPath:indexPath];
}
+ (instancetype)reusableSupplementaryViewFromClassOfKind:(NSString *)elementKind collectionView:(UICollectionView *)collectionView forIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = [self.reusedId stringByAppendingString:elementKind];;
NSMutableSet *identifierSet = [self setReusableSupplementaryViewIdentifierSetForCollectionView:collectionView];
if (![identifierSet containsObject:identifier]) {
NSLog(@"register class supplementary view");
[collectionView registerClass:[self class] forSupplementaryViewOfKind:elementKind withReuseIdentifier:identifier];
[identifierSet addObject:identifier];
}
return [collectionView dequeueReusableSupplementaryViewOfKind:elementKind withReuseIdentifier:identifier forIndexPath:indexPath];
}
/** 关联 IdentifierSet*/
+ (NSMutableSet *)setReusableSupplementaryViewIdentifierSetForCollectionView:(UICollectionView *)collectionView {
if (![collectionView getAssociatedValueForKey:_cmd]) {
NSMutableSet *identifierSet = [[NSMutableSet alloc] init];
[collectionView setAssociateValue:identifierSet withKey:_cmd];
return identifierSet;
}
return [collectionView getAssociatedValueForKey:_cmd];
}
@end
复制代码
UIView
对UICollectionView
列表基类的封装
//.h文件
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class BNBaseCollectionListView;
@protocol BNBaseCollectionListDelegate <NSObject>
@optional
- (void)collectionListView:(BNBaseCollectionListView *)listView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface BNBaseCollectionListView : UIView<UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
/** collection view*/
@property (nonatomic, strong) UICollectionView *collectionView;
/** flow layout*/
@property (nonatomic, strong) UICollectionViewFlowLayout *flowLayout;
/** dataSource*/
@property (nonatomic, strong) NSArray *dataSource;
/** delegate*/
@property (nonatomic, weak) id<BNBaseCollectionListDelegate>delegate;
/** Select item at indexPath action handler*/
@property(nonatomic, copy) void(^didSelectItemAtIndexPathHandler)(NSIndexPath *indexPath);
#pragma mark - RefreshUI
- (void)refreshUI;
@end
NS_ASSUME_NONNULL_END
//.m文件
#import "BNBaseCollectionListView.h"
@implementation BNBaseCollectionListView
- (instancetype)initWithFrame:(CGRect)frame {
if ([super initWithFrame:frame]) {
[self setupUI];
}
return self;
}
#pragma mark - ----------------Public Methods----------------
#pragma mark - ----------------RefreshUI----------------
- (void)refreshUI {
[self.collectionView reloadData];
}
#pragma mark - ----------------Private Methods----------------
#pragma mark - setupUI
- (void)setupUI{
self.backgroundColor = [UIColor whiteColor];
[self addSubview:self.collectionView];
[self addLayouts];
}
#pragma mark - ----------------AddLayouts----------------
- (void)addLayouts {
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_offset(0);
}];
}
#pragma mark - -------------UICollectionViewDataSource----------------
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 0;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
return [UICollectionViewCell cellFromClassWithCollectionView:collectionView forIndexPath:indexPath];
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
return nil;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
return CGSizeZero;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
return CGSizeZero;
}
#pragma mark - -------------UICollectionViewDelegate----------------
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
!self.didSelectItemAtIndexPathHandler?:self.didSelectItemAtIndexPathHandler(indexPath);
if ([self.delegate respondsToSelector:@selector(collectionListView:didSelectItemAtIndexPath:)]) {
[self.delegate collectionListView:self didSelectItemAtIndexPath:indexPath];
}
}
#pragma mark - ----------------Getter & Setter----------------
- (UICollectionViewFlowLayout *)flowLayout {
if (!_flowLayout) {
_flowLayout = [UICollectionViewFlowLayout new];
_flowLayout.sectionInset = UIEdgeInsetsZero;
_flowLayout.itemSize = CGSizeMake(UIScreen.width, UIScreen.height);
_flowLayout.minimumLineSpacing = 0.0;
_flowLayout.minimumInteritemSpacing = 0.0;
}
return _flowLayout;
}
- (UICollectionView *)collectionView {
if (!_collectionView) {
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:self.flowLayout];
_collectionView.backgroundColor = [UIColor whiteColor];
_collectionView.dataSource = self;
_collectionView.delegate = self;
}
return _collectionView;
}
@end
复制代码
- 以上就是对列表视图基类(
UITableView
,UICollectionView
)的封装了,下面我看看具体如何使用。
UITableView
基类的使用
页面效果如下:
- ViewController代码(
共91行
)
#import "BNHomeDetailController.h"
#import "BNHomeDetailListView.h" //list view
#import "BNHomeDetailViewModel.h" //view model
@interface BNHomeDetailController ()<BNBaseTableListViewDelegate>
/** table list view*/
@property (nonatomic, strong) BNHomeDetailListView *listView;
/** view model*/
@property (nonatomic, strong) BNHomeDetailViewModel *viewModel;
@end
@implementation BNHomeDetailController
- (void)dealloc
{
NSLog(@"%s", __func__);
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
[self requestData];
}
#pragma mark - setupUI
- (void)setupUI {
self.title = @"home-detail";
self.view.backgroundColor = [UIColor randomColor];
[self.view addSubview:self.listView];
[self addLayouts];
}
#pragma mark - ----------------AddLayouts----------------
- (void)addLayouts {
[self.listView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_offset(0);
}];
}
#pragma mark - ----------------Request----------------
- (void)requestData {
__weak typeof(self) weakSelf = self;
[self.viewModel requestDataWithCompletion:^(BOOL succeed, NSString *errorMsg) {
__strong typeof(self) strongSelf = weakSelf;
[strongSelf refreshUI];
}];
}
#pragma mark - ----------------RefreshUI----------------
- (void)refreshUI {
self.listView.dataSource = self.viewModel.listDatas;
[self.listView refreshUI];
}
#pragma mark - ----------------BNBaseTableListViewDelegate----------------
- (void)tableListView:(BNBaseTableListView *)listView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"%s", __func__);
}
#pragma mark - ----------------Getter & Setter----------------
- (BNHomeDetailListView *)listView {
if (!_listView) {
_listView = [[BNHomeDetailListView alloc] initWithFrame:CGRectZero tableViewStyle:UITableViewStyleGrouped];
_listView.tableView.backgroundColor = [UIColor lightGrayColor];
_listView.delegate = self;
}
return _listView;
}
- (BNHomeDetailViewModel *)viewModel {
if (!_viewModel) {
_viewModel = [BNHomeDetailViewModel new];
}
return _viewModel;
}
@end
复制代码
- 列表BNHomeDetailListView(继承自BNBaseTableListView基类)代码(
共41行
)
#import "BNHomeDetailListView.h"
#import "BNHomeDetailTableViewCell.h" //cell
#import "BNHomeDetailSectionHeaderView.h" //seation header
@implementation BNHomeDetailListView
#pragma mark - -------------UICollectionViewDataSource----------------
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.dataSource.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
BNHomeDetailTableViewCell *cell = [BNHomeDetailTableViewCell cellFromClassWithTableView:tableView];
cell.text = self.dataSource[indexPath.row];
return cell;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
BNHomeDetailSectionHeaderView *header = [BNHomeDetailSectionHeaderView headerFooterViewFromXibWithTableView:tableView];
header.titleLabel.text = [NSString stringWithFormat:@"section-%ld",section];
return header;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 60;
}
@end
复制代码
UICollectionView
基类的使用
效果如下
- ViewController代码(共77行)
#import "BNMineController.h"
#import "BNMineCollectionListView.h"
@interface BNMineController ()<BNBaseCollectionListDelegate>
/** collection list view*/
@property (nonatomic, strong) BNMineCollectionListView *collectionListView;
@end
@implementation BNMineController
- (void)dealloc
{
NSLog(@"%s", __func__);
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
[self requestData];
}
#pragma mark - setupUI
- (void)setupUI{
self.fd_prefersNavigationBarHidden = YES;
self.view.backgroundColor = [UIColor randomColor];
[self.view addSubview:self.collectionListView];
[self addLayouts];
}
#pragma mark - ----------------AddLayouts----------------
- (void)addLayouts {
[self.collectionListView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_offset(0);
}];
}
#pragma mark - ----------------Request----------------
- (void)requestData {
//fetch data
[self refreshUI];
}
#pragma mark - ----------------RefreshUI----------------
- (void)refreshUI {
self.collectionListView.dataSource = @[];
[self.collectionListView refreshUI];
}
#pragma mark - ----------------BNBaseCollectionListDelegate----------------
- (void)collectionListView:(BNBaseCollectionListView *)listView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"%s", __func__);
}
#pragma mark - ----------------Getter & Setter----------------
- (BNMineCollectionListView *)collectionListView {
if (!_collectionListView) {
_collectionListView = [[BNMineCollectionListView alloc] initWithFrame:CGRectZero];
CGFloat width = floor(UIScreen.width * 0.5);
_collectionListView.flowLayout.itemSize = CGSizeMake(width, width);
_collectionListView.delegate = self;
}
return _collectionListView;
}
@end
复制代码
CollectionView
列表视图(继承自BNBaseCollectionListView
)(共56行
)
#import "BNMineCollectionListView.h"
//cell
#import "BNMineNormalCell.h"
#import "BMineImageCell.h"
//header footer
#import "BNMineHeaaderFooterReusableView.h"
@implementation BNMineCollectionListView
#pragma mark - -------------UICollectionViewDataSource----------------
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 50;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 2;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section % 2 == 0) {
BNMineNormalCell *cell = [BNMineNormalCell cellFromClassWithCollectionView:collectionView forIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor randomColor];
cell.titleLabel.text = [NSString stringWithFormat:@"%ld - %ld",indexPath.section, indexPath.row];
return cell;
} else {
BMineImageCell *cell = [BMineImageCell cellFromXibWithCollectionView:collectionView forIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor randomColor];
return cell;
}
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
BNMineHeaaderFooterReusableView *headerFooter = [BNMineHeaaderFooterReusableView headerReusableViewFromXibWithCollectionView:collectionView forIndexPath:indexPath];
headerFooter.titleLabel.text = [kind isEqualToString:UICollectionElementKindSectionHeader]?@"Header":@"Footer";
**headerFooter**.backgroundColor = [UIColor randomColor];
return headerFooter;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
return CGSizeMake(UIScreen.width, 50);
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
return CGSizeMake(UIScreen.width, 50);
}
@end
复制代码
总结
-
继承及封装大大提升了编码效率。
-
因为我们不需要每个页面都需要去创建一个
UITableView
或者UICollectionView
,只要继承自基类,重写使用到的代理方法即可。 -
同时免去了注册cell的过程,仅需要在使用到cell的地方,调用创建cell统一接口即可。
-
大大提升了代码的可复用性及可维护性。
-
ViewController
变得更加简洁,整体代码逻辑也不会显得太臃肿。 -
最后附上
Demo
地址,欢迎大家前来拍砖~~~~~