在实际应用中UITableView的场景可谓是无处不在,下面的例子实现了一个UITableViewCell的自定义UISignal。先看下效果图
点击浏览或评论触发相应事件,为了响应这样的事件,通常的做法是在UITableViewCell中采用代理的方式,在ViewController中实现Cell的协议。
下面看下Bee的写法
// // ViewController.h // BeeFrameWorkTest // // Created by he songhang on 13-6-3. // Copyright (c) 2013年 he songhang. All rights reserved. // #import <UIKit/UIKit.h> #import <BeeFramework/Bee.h> @interface MyCell : UITableViewCell{ UILabel *lb_content; UIButton *btn_count; UIButton *btn_comment; } @property(nonatomic,retain) NSDictionary *data; AS_SIGNAL(COUNT) AS_SIGNAL(COMMENT) @end @interface ViewController : UITableViewController @end
// // ViewController.m // BeeFrameWorkTest // // Created by he songhang on 13-6-3. // Copyright (c) 2013年 he songhang. All rights reserved. // #import "ViewController.h" @implementation MyCell DEF_SIGNAL(COUNT) DEF_SIGNAL(COMMENT) - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; lb_content = [[UILabel alloc]init]; btn_count = [[UIButton alloc]init]; btn_comment = [[UIButton alloc]init]; [btn_count addTarget:self action:@selector(countBtnClicked) forControlEvents:UIControlEventTouchUpInside]; [btn_comment addTarget:self action:@selector(commentBtnClicked) forControlEvents:UIControlEventTouchUpInside]; [btn_count setTitleColor:[UIColor grayColor] forState:UIControlStateNormal]; btn_count.titleLabel.font = [UIFont systemFontOfSize:12]; [btn_comment setTitleColor:[UIColor grayColor] forState:UIControlStateNormal]; btn_comment.titleLabel.font = [UIFont systemFontOfSize:12]; [self.contentView addSubview:lb_content]; [self.contentView addSubview:btn_comment]; [self.contentView addSubview:btn_count]; return self; } -(void)layoutSubviews{ lb_content.frame = CGRectMake(10, 0, 300, 44); btn_count.frame = CGRectMake(200, 20, 50, 14); btn_comment.frame = CGRectMake(260, 20, 50, 14); } -(void)setData:(NSDictionary *)data{ _data = data; if (data) { lb_content.text = [data stringAtPath:@"content"]; [btn_count setTitle:[NSString stringWithFormat:@"浏览(%@)",[data stringAtPath:@"count"]] forState:UIControlStateNormal]; [btn_comment setTitle:[NSString stringWithFormat:@"评论(%@)",[data stringAtPath:@"comment"]] forState:UIControlStateNormal]; }else{ lb_content.text = nil; [btn_count setTitle:nil forState:UIControlStateNormal]; [btn_comment setTitle:nil forState:UIControlStateNormal]; } } -(void)countBtnClicked{ [self sendUISignal:MyCell.COUNT withObject:self.data]; } -(void)commentBtnClicked{ [self sendUISignal:MyCell.COMMENT withObject:self.data]; } @end @interface ViewController (){ NSArray *datas; } @end @implementation ViewController -(void)handleUISignal_MyCell:(BeeUISignal *)signal{ if ([signal is:MyCell.COUNT]) { NSDictionary *dict = (NSDictionary *)signal.object; CC(@"%@被点击",[dict stringAtPath:@"content"]); }else if ([signal is:MyCell.COMMENT]){ NSDictionary *dict = (NSDictionary *)signal.object; CC(@"%@被评论",[dict stringAtPath:@"content"]); } } - (id)initWithStyle:(UITableViewStyle)style { self = [super initWithStyle:style]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; NSDictionary *dict1 = [NSDictionary dictionaryWithObjectsAndKeys:@"测试数据1",@"content",@"20",@"count",@"3",@"comment", nil]; NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys:@"测试数据2",@"content",@"30",@"count",@"4",@"comment", nil]; NSDictionary *dict3 = [NSDictionary dictionaryWithObjectsAndKeys:@"测试数据3",@"content",@"10",@"count",@"2",@"comment", nil]; datas = [[NSArray alloc]initWithObjects:dict1,dict2,dict3, nil]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark -UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;{ return [datas count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;{ MyCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MYCELL"]; if (!cell) { cell = [[MyCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MYCELL"]; } cell.data = [datas objectAtIndex:indexPath.row]; return cell; } @end
在MYCell.h中通过AS_SIGNAL定义了两个静态的属性,用来自定义UISinal的名字,MYCell.m中的DEF_SIGNAL与.h中相对应。事实上,在Bee中还有很多这样类型的预定义方法,如:AS_MESSAGE 、AS_NOTIFICATION ,通过这些预定义方法,在一定程度上范规了方法的命名,通过这些预定义的属性就能知道对应的接口的调用方式。
在Cell中通过调用 [self sendUISignal:XXX withObject:self.data]实现了信号的传递过程。在ViewController实现规范命名的方法(见上篇),就能对信号进行响应。
实际上Bee已经为我们提供了一个方便布局的BeeUIGirdCell,它预定义了常见的一些方法,如数据的绑定,界面的布局等等。Bee中的BeeUITableBoard、BeeUIFlowBoard都采用GirdCell来定义布局,这里我们通过category为UITableView扩展使用BeeUIGirdCell的方法。
// // UITableView+BeeUIGirdCell.h // // Created by he songhang on 13-4-24. // Copyright (c) 2013年 he songhang. All rights reserved. // #if (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR) #import <Foundation/Foundation.h> #import "Bee_UIGridCell.h" @interface UITableViewCell (BeeUIGirdCell) @property(nonatomic,retain) BeeUIGridCell *gridCell; @end @interface UITableView (BeeUIGirdCell) -(UITableViewCell *) dequeueReusableCellWithBeeUIGirdCellClass:(Class) class; @end #endif
// // UITableView+BeeUIGirdCell.m // 618 // // Created by he songhang on 13-4-24. // Copyright (c) 2013年 he songhang. All rights reserved. // #import "UITableView+BeeUIGirdCell.h" #import "CGRect+BeeExtension.h" #import "Bee_Precompile.h" #include <objc/runtime.h> #import "Bee_Runtime.h" @implementation UITableViewCell(BeeUIGirdCell) @dynamic gridCell; - (void)setFrame:(CGRect)rc { [super setFrame:CGRectZeroNan(rc)]; [self.gridCell setFrame:self.bounds]; // [_gridCell layoutSubcells]; } - (void)setCenter:(CGPoint)pt { [super setCenter:pt]; [self.gridCell setFrame:self.bounds]; // [_gridCell layoutSubcells]; } -(void)setGridCell:(BeeUIGridCell *)gridCell{ if (!self.gridCell) { objc_setAssociatedObject( self, "UITableViewCell.gridCell", gridCell, OBJC_ASSOCIATION_RETAIN ); // self.gridCell.autoresizesSubviews = YES; // self.gridCell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; if ( gridCell.superview != self.contentView ) { [gridCell.superview removeFromSuperview]; } [self.contentView addSubview:gridCell]; }else{ if ( self.gridCell != gridCell ) { [self.gridCell release]; objc_setAssociatedObject( self, "UITableViewCell.gridCell", gridCell, OBJC_ASSOCIATION_RETAIN ); // self.gridCell.autoresizesSubviews = YES; // self.gridCell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; if ( gridCell.superview != self.contentView ) { [gridCell.superview removeFromSuperview]; } [self.contentView addSubview:gridCell]; } } } -(BeeUIGridCell *)gridCell{ NSObject * obj = objc_getAssociatedObject( self, "UITableViewCell.gridCell" ); if ( obj && [obj isKindOfClass:[BeeUIGridCell class]] ) return (BeeUIGridCell *)obj; return nil; } @end @implementation UITableView (BeeUIGirdCell) -(UITableViewCell *) dequeueReusableCellWithBeeUIGirdCellClass:(Class) clazz{ UITableViewCell *cell = [self dequeueReusableCellWithIdentifier:[clazz description]]; if (!cell) { cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[cell description]]autorelease]; cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.accessoryType = UITableViewCellAccessoryNone; cell.editingAccessoryType = UITableViewCellAccessoryNone; cell.showsReorderControl = NO; cell.shouldIndentWhileEditing = NO; cell.indentationLevel = 0; cell.indentationWidth = 0.0f; self.alpha = 1.0f; self.layer.masksToBounds = YES; self.layer.opaque = YES; cell.contentView.layer.masksToBounds = YES; cell.contentView.layer.opaque = YES; cell.contentView.autoresizesSubviews = YES; if ( [clazz isSubclassOfClass:[BeeUIGridCell class]] ) { cell.gridCell = [(BeeUIGridCell *)[[BeeRuntime allocByClass:clazz] init] autorelease]; } } return cell; } @end
为了下次重用这两个文件,把UITableView+BeeUIGirdCell.h和UITableView+BeeUIGirdCell.m放到Pods/BeeFramework/BeeFramework/MVC/View下,并在Pods/Headers下新建UITableView+BeeUIGirdCell.h的替身,
ln -s ../../BeeFramework/BeeFramework/MVC/View/UITableView+BeeUIGirdCell.h UITableView+BeeUIGirdCell.h
我们重新实现一下ViewController
// // ViewController1.h // BeeFrameWorkTest // // Created by he songhang on 13-6-4. // Copyright (c) 2013年 he songhang. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController1 : UITableViewController @end
// // ViewController1.m // BeeFrameWorkTest // // Created by he songhang on 13-6-4. // Copyright (c) 2013年 he songhang. All rights reserved. // #import "ViewController1.h" #import <BeeFramework/UITableView+BeeUIGirdCell.h> #import <BeeFramework/Bee.h> @interface MYGirdCell : BeeUIGridCell{ UILabel *lb_content; UIButton *btn_count; UIButton *btn_comment; } AS_SIGNAL(COUNT) AS_SIGNAL(COMMENT) @end @implementation MYGirdCell DEF_SIGNAL(COUNT) DEF_SIGNAL(COMMENT) //初始化 -(void)load{ lb_content = [[UILabel alloc]init]; btn_count = [[UIButton alloc]init]; btn_comment = [[UIButton alloc]init]; [btn_count addTarget:self action:@selector(countBtnClicked) forControlEvents:UIControlEventTouchUpInside]; [btn_comment addTarget:self action:@selector(commentBtnClicked) forControlEvents:UIControlEventTouchUpInside]; [btn_count setTitleColor:[UIColor grayColor] forState:UIControlStateNormal]; btn_count.titleLabel.font = [UIFont systemFontOfSize:12]; [btn_comment setTitleColor:[UIColor grayColor] forState:UIControlStateNormal]; btn_comment.titleLabel.font = [UIFont systemFontOfSize:12]; [self addSubview:lb_content]; [self addSubview:btn_comment]; [self addSubview:btn_count]; } //释放 -(void)unload{ } //数据变化时 - (void)dataDidChanged { if (self.cellData) { NSDictionary *data = _cellData; lb_content.text = [data stringAtPath:@"content"]; [btn_count setTitle:[NSString stringWithFormat:@"浏览(%@)",[data stringAtPath:@"count"]] forState:UIControlStateNormal]; [btn_comment setTitle:[NSString stringWithFormat:@"评论(%@)",[data stringAtPath:@"comment"]] forState:UIControlStateNormal]; }else{ lb_content.text = nil; [btn_count setTitle:nil forState:UIControlStateNormal]; [btn_comment setTitle:nil forState:UIControlStateNormal]; } } //用于计算高度,可实现动态高度 + (CGSize)sizeInBound:(CGSize)bound forData:(NSObject *)data { return bound; } //用于布局 - (void)layoutInBound:(CGSize)bound forCell:(BeeUIGridCell *)cell { lb_content.frame = CGRectMake(10, 0, 300, 44); btn_count.frame = CGRectMake(200, 20, 50, 14); btn_comment.frame = CGRectMake(260, 20, 50, 14); } -(void)countBtnClicked{ [self sendUISignal:MYGirdCell.COUNT]; } -(void)commentBtnClicked{ [self sendUISignal:MYGirdCell.COMMENT withObject:self.cellData]; } @end @interface ViewController1 (){ NSArray *datas; } @end @implementation ViewController1 -(void)handleUISignal_MYGirdCell:(BeeUISignal *)signal{ if ([signal is:MYGirdCell.COUNT]) { MYGirdCell *cell = signal.source; NSDictionary *dict = (NSDictionary *)cell.cellData; CC(@"%@被点击",[dict stringAtPath:@"content"]); }else if ([signal is:MYGirdCell.COMMENT]){ NSDictionary *dict = (NSDictionary *)signal.object; CC(@"%@被评论",[dict stringAtPath:@"content"]); } } - (id)initWithStyle:(UITableViewStyle)style { self = [super initWithStyle:style]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; NSDictionary *dict1 = [NSDictionary dictionaryWithObjectsAndKeys:@"测试数据1",@"content",@"20",@"count",@"3",@"comment", nil]; NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys:@"测试数据2",@"content",@"30",@"count",@"4",@"comment", nil]; NSDictionary *dict3 = [NSDictionary dictionaryWithObjectsAndKeys:@"测试数据3",@"content",@"10",@"count",@"2",@"comment", nil]; datas = [[NSArray alloc]initWithObjects:dict1,dict2,dict3, nil]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark -UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;{ return [datas count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;{ UITableViewCell *cell = [tableView dequeueReusableCellWithBeeUIGirdCellClass:[MYGirdCell class]]; cell.gridCell.cellData = [datas objectAtIndex:indexPath.row]; return cell; } @end
可以留意下MYGirdCell中的
-(void)countBtnClicked{ [self sendUISignal:MYGirdCell.COUNT]; } -(void)commentBtnClicked{ [self sendUISignal:MYGirdCell.COMMENT withObject:self.cellData]; }
对应于ViewController1中的
-(void)handleUISignal_MYGirdCell:(BeeUISignal *)signal{ if ([signal is:MYGirdCell.COUNT]) { MYGirdCell *cell = signal.source; NSDictionary *dict = (NSDictionary *)cell.cellData; CC(@"%@被点击",[dict stringAtPath:@"content"]); }else if ([signal is:MYGirdCell.COMMENT]){ NSDictionary *dict = (NSDictionary *)signal.object; CC(@"%@被评论",[dict stringAtPath:@"content"]); } }
本篇以UItableViewController演示了如何自定义UISignal,以及BeeUIGirdCell的用法。
以上代码下载地址: https://github.com/ilikeido/BeeFrameworkTest/tree/master/lesson3