用适配器模式处理复杂的UITableView中cell的业务逻辑
适配器是用来隔离数据源对cell布局影响而使用的,cell只接受适配器的数据,而不会与外部数据源进行交互.
源码:
ModelCell.h 与 ModelCell.m
//// ModelCell.h// Adapter//// Created by XianMingYou on 15/2/10.// Copyright (c) 2015年 XianMingYou. All rights reserved.//#import#define NAME_FRAME CGRectMake(15, 15, 290, 20)#define NAME_FONT [UIFont boldSystemFontOfSize:18.f]#define ADDRESS_FRAME CGRectMake(15, 15 + 30, 290, 20)#define ADDRESS_FONT [UIFont systemFontOfSize:14.f]#define DESCRIBE_FRAME CGRectMake(15, 15 + 60, 290, 20)#define DESCRIBE_FONT [UIFont italicSystemFontOfSize:14.f]@interface ModelCell : UITableViewCell/** * 适配器处理逻辑的地方 * * @param adapter 适配器 */- (void)accessModelAdapter:(id)adapter;@end
//// ModelCell.m// Adapter//// Created by XianMingYou on 15/2/10.// Copyright (c) 2015年 XianMingYou. All rights reserved.//#import "ModelCell.h"#import "ModelAdapter.h"#import "UIView+SetRect.h"@interface ModelCell ()@property (nonatomic, strong) UILabel *name; // 名字@property (nonatomic, strong) UILabel *address; // 地址@property (nonatomic, strong) UILabel *describeInfo; // 描述信息@end@implementation ModelCell- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { [self createView]; } return self;}- (void)createView { self.name = [[UILabel alloc] initWithFrame:NAME_FRAME]; self.name.font = NAME_FONT; self.name.numberOfLines = 0.f; self.name.textColor = [UIColor redColor]; [self addSubview:self.name]; self.address = [[UILabel alloc] initWithFrame:ADDRESS_FRAME]; self.address.font = ADDRESS_FONT; self.address.numberOfLines = 0.f; [self addSubview:self.address]; self.describeInfo = [[UILabel alloc] initWithFrame:DESCRIBE_FRAME]; self.describeInfo.font = DESCRIBE_FONT; self.describeInfo.numberOfLines = 0.f; self.describeInfo.textColor = [UIColor grayColor]; self.describeInfo.textAlignment = NSTextAlignmentRight; [self addSubview:self.describeInfo];}- (void)accessModelAdapter:(id)adapter { ModelAdapter *dataAdapter = adapter; self.name.text = dataAdapter.name; self.name.frame = NAME_FRAME; [self.name sizeToFit]; self.address.text = dataAdapter.address; self.address.frame = ADDRESS_FRAME; [self.address sizeToFit]; self.describeInfo.text = dataAdapter.describeInfo; self.describeInfo.frame = DESCRIBE_FRAME; [self.describeInfo sizeToFit]; self.describeInfo.x = 320 - self.describeInfo.width - 10; self.address.y = NAME_FRAME.origin.y + dataAdapter.nameHeight; self.describeInfo.y = self.address.y + dataAdapter.addressHeight;}@end
ModelAdapter.h 与 ModelAdapter.m
//// ModelAdapter.h// Adapter//// Created by XianMingYou on 15/2/10.// Copyright (c) 2015年 XianMingYou. All rights reserved.//#import#import @interface ModelAdapter : NSObject@property (nonatomic, strong) NSString *name;@property (nonatomic, strong) NSString *address;@property (nonatomic, strong) NSString *describeInfo;// 初始化适配器- (instancetype)initWithData:(id)data;#pragma mark 只读属性@property (nonatomic, readonly) CGFloat nameHeight;@property (nonatomic, readonly) CGFloat addressHeight;@property (nonatomic, readonly) CGFloat describeInfoHeight;@property (nonatomic, readonly) CGFloat totalHeight;@end
设置frame值用的类
UIView+SetRect.h 与 UIView+SetRect.m
//// UIView+SetRect.h// TestPch//// Created by YouXianMing on 14-12-26.// Copyright (c) 2014年 YouXianMing. All rights reserved.//#import@interface UIView (SetRect)// Frame@property (nonatomic) CGPoint viewOrigin;@property (nonatomic) CGSize viewSize;// Frame Origin@property (nonatomic) CGFloat x;@property (nonatomic) CGFloat y;// Frame Size@property (nonatomic) CGFloat width;@property (nonatomic) CGFloat height;// Frame Borders@property (nonatomic) CGFloat top;@property (nonatomic) CGFloat left;@property (nonatomic) CGFloat bottom;@property (nonatomic) CGFloat right;// Center Point#if !IS_IOS_DEVICE@property (nonatomic) CGPoint center;#endif@property (nonatomic) CGFloat centerX;@property (nonatomic) CGFloat centerY;// Middle Point@property (nonatomic, readonly) CGPoint middlePoint;@property (nonatomic, readonly) CGFloat middleX;@property (nonatomic, readonly) CGFloat middleY;@property (nonatomic, assign) CGFloat cornerRadius ;@property (nonatomic ,assign) BOOL round ;@end
//// UIView+SetRect.m// TestPch//// Created by YouXianMing on 14-12-26.// Copyright (c) 2014年 YouXianMing. All rights reserved.//#import "UIView+SetRect.h"@implementation UIView (SetRect)#pragma mark Frame- (CGPoint)viewOrigin{ return self.frame.origin;}- (void)setViewOrigin:(CGPoint)newOrigin{ CGRect newFrame = self.frame; newFrame.origin = newOrigin; self.frame = newFrame;}- (CGSize)viewSize{ return self.frame.size;}- (void)setViewSize:(CGSize)newSize{ CGRect newFrame = self.frame; newFrame.size = newSize; self.frame = newFrame;}#pragma mark Frame Origin- (CGFloat)x{ return self.frame.origin.x;}- (void)setX:(CGFloat)newX{ CGRect newFrame = self.frame; newFrame.origin.x = newX; self.frame = newFrame;}- (CGFloat)y{ return self.frame.origin.y;}- (void)setY:(CGFloat)newY{ CGRect newFrame = self.frame; newFrame.origin.y = newY; self.frame = newFrame;}#pragma mark Frame Size- (CGFloat)height{ return self.frame.size.height;}- (void)setHeight:(CGFloat)newHeight{ CGRect newFrame = self.frame; newFrame.size.height = newHeight; self.frame = newFrame;}- (CGFloat)width{ return self.frame.size.width;}- (void)setWidth:(CGFloat)newWidth{ CGRect newFrame = self.frame; newFrame.size.width = newWidth; self.frame = newFrame;}#pragma mark Frame Borders- (CGFloat)left{ return self.x;}- (void)setLeft:(CGFloat)left{ self.x = left;}- (CGFloat)right{ return self.frame.origin.x + self.frame.size.width;}- (void)setRight:(CGFloat)right{ self.x = right - self.width;}- (CGFloat)top{ return self.y;}- (void)setTop:(CGFloat)top{ self.y = top;}- (CGFloat)bottom{ return self.frame.origin.y + self.frame.size.height;}- (void)setBottom:(CGFloat)bottom{ self.y = bottom - self.height;}#pragma mark Center Point#if !IS_IOS_DEVICE- (CGPoint)center{ return CGPointMake(self.left + self.middleX, self.top + self.middleY);}- (void)setCenter:(CGPoint)newCenter{ self.left = newCenter.x - self.middleX; self.top = newCenter.y - self.middleY;}#endif- (CGFloat)centerX{ return self.center.x;}- (void)setCenterX:(CGFloat)newCenterX{ self.center = CGPointMake(newCenterX, self.center.y);}- (CGFloat)centerY{ return self.center.y;}- (void)setCenterY:(CGFloat)newCenterY{ self.center = CGPointMake(self.center.x, newCenterY);}#pragma mark Middle Point- (CGPoint)middlePoint{ return CGPointMake(self.middleX, self.middleY);}- (CGFloat)middleX{ return self.width / 2;}- (CGFloat)middleY{ return self.height / 2;}- (void)setCornerRadius:(CGFloat)cornerRadius{ self.layer.masksToBounds = YES ; self.layer.cornerRadius = cornerRadius ;}- (void)setRound:(BOOL)round{ [self setCornerRadius:self.height/2];}- (CGFloat)cornerRadius{ return self.layer.cornerRadius ;}- (BOOL)round{ return NO ;}@end
控制器源码:
//// ViewController.m// Adapter//// Created by XianMingYou on 15/2/10.// Copyright (c) 2015年 XianMingYou. All rights reserved.//#import "ViewController.h"#import "ModelCell.h"#import "ModelAdapter.h"#define REUSE_MODEL_CELL @"ModelCell"@interface ViewController ()@property (nonatomic, strong) UITableView *tableView;@property (nonatomic, strong) NSArray *dataArray;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // 创建数据源 [self createDataSource]; // 创建tableView [self createTableView];}#pragma mark - 数据源- (void)createDataSource { ModelAdapter *data1 = [[ModelAdapter alloc] initWithData:@{ @"name" : @"YouXianMing", @"address" : @"北京通州区果园地铁站附近", @"describeInfo" : @"iOS Developer"}]; ModelAdapter *data2 = [[ModelAdapter alloc] initWithData:@{ @"name" : @"QiuLiang", @"address" : @"上海浦东XXXX开发园区,德望路园丁小区福星楼7123左侧34桌", @"describeInfo" : @".Net Developer"}]; ModelAdapter *data3 = [[ModelAdapter alloc] initWithData:@{ @"name" : @"", @"address" : @"上海浦东XXXX开发园区,德望路园丁小区福星楼7123左侧34桌", @"describeInfo" : @".Net Developer"}]; ModelAdapter *data4 = [[ModelAdapter alloc] initWithData:@{ @"name" : @"YouXianMing", @"address" : @"", @"describeInfo" : @"C++ Developer"}]; self.dataArray = @[data1, data2, data3, data4];}#pragma mark - tableView相关- (void)createTableView { self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; self.tableView.delegate = self; self.tableView.dataSource = self; [self.tableView registerClass:[ModelCell class] forCellReuseIdentifier:REUSE_MODEL_CELL]; [self.view addSubview:self.tableView];}#pragma mark row的数目- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataArray.count;}#pragma mark 初始化cell- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ModelCell *cell = [tableView dequeueReusableCellWithIdentifier:REUSE_MODEL_CELL]; [cell accessModelAdapter:self.dataArray[indexPath.row]]; return cell;}#pragma mark cell高度- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { ModelAdapter *adapter = self.dataArray[indexPath.row]; return adapter.totalHeight;}@end
简单的分析:
1) 适配器与cell中的控件数据一一对应
2) 重写适配器中的只读属性实现懒加载
3) 适配器与cell共用一部分cell的控件属性,用以方便修改
4) 适配器可以随时切换数据类型
5) 用适配器处理业务逻辑