我真的很惊讶在做 iphone 应用程序的时候让你的代码保持良好的结构和可读性是多么困难......但这可能是因为我做错了什么。
我有一个注册页面,其中包含各种可在线编辑的数据:生日、性别、姓名、密码、电话号码。我将页面制作为自定义单元格的表格 View ,其中每个单元格都是 UITableViewCell 子类的实例,并从其自己的 nib 文件中读取。这是因为我认为我以后可以在其他表格 View 页面中重用这些不同类型的单元格。
不过,将不同的自定义单元格封装在各自位置的方法效果不佳:
谁将成为 GenderCell 中的性别选择器等的控制者?
当我必须将 SignUpController 作为单元格 nib 文件的文件所有者时,我实际上如何在不同的 TableView Controller 中重用单元格?
我不知道除了我自己是否有人理解我刚刚写的东西,但如果是的话,我将非常感谢任何关于如何以不同方式构建我的代码的建议。
非常感谢,
斯坦
为了让事情更清楚(?!)让我在这里粘贴一些我的代码:
可编辑标签.h
@interface EditableLabel : UILabel {
UIView *inputView, *inputAccessoryView;
}
@property (nonatomic, retain) UIView *inputView, *inputAccessoryView;
- (void) setInputView:(UIView *)aView andToolbar:(UIToolbar *)aToolbar;
@end
EditableLabel.m
@implementation EditableLabel
@synthesize inputView, inputAccessoryView;
- (void) dealloc {
[inputView release];
[inputAccessoryView release];
[super dealloc];
}
- (void) setInputView:(UIView *)aView andToolbar:(UIToolbar *)aToolbar {
self.inputAccessoryView = aToolbar;
self.inputView = aView;
}
- (BOOL) canBecomeFirstResponder {
return YES;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self becomeFirstResponder];
}
@end
EditableCell.h
typedef enum {
USERNAME, PASSWORD, MOBILE, BIRTHDAY, GENDER, DESCRIPTION, CATEGORY
} CellTag;
@interface EditableCell : UITableViewCell {
CellTag tag;
UIView *editPoint;
IBOutlet UILabel *headerLabel;
}
- (void) setTag:(CellTag)aTag andHeader:(NSString *)aHeader andEditPoint:(UIView *)aView;
@property (nonatomic) CellTag tag;
@property (nonatomic, retain) UIView *editPoint;
@property (nonatomic, retain) UILabel *headerLabel;
- (IBAction) editingDone:(id)sender;
- (void) showInputView;
- (void) hideInputView;
@end
EditableCell.m
@implementation EditableCell
@synthesize tag, editPoint, headerLabel;
- (void) dealloc {
[editPoint release];
[headerLabel release];
[super dealloc];
}
- (void) setTag:(CellTag)aTag andHeader:(NSString *)aHeader andEditPoint:(UIView *)aView {
self.tag = aTag;
self.headerLabel.text = aHeader;
self.editPoint = aView;
}
- (IBAction) editingDone:(id)sender {
[self hideInputView];
}
- (void) showInputView {
[self.editPoint becomeFirstResponder];
}
- (void) hideInputView {
[self.editPoint resignFirstResponder];
}
@end
EditableLabelCell.h
@interface EditableLabelCell : EditableCell {
IBOutlet UILabel *placeHolderLabel;
IBOutlet EditableLabel *editableLabel;
}
@property (nonatomic, retain) UILabel *placeHolderLabel;
@property (nonatomic, retain) EditableLabel *editableLabel;
- (void) setTag:(CellTag)aTag
andHeader:(NSString *)aHeader
andPlaceHolder:(NSString *)aPlaceHolder
andInputView:(UIView *)aView
andToolbar:(UIToolbar *)aToolbar;
- (void) setValue:(NSString *)aValue;
@end
EditableLabelCell.m
@implementation EditableLabelCell
@synthesize placeHolderLabel, editableLabel;
- (void) dealloc {
[placeHolderLabel release];
[editableLabel release];
[super dealloc];
}
- (void) setTag:(CellTag)aTag andHeader:(NSString *)aHeader andPlaceHolder:(NSString *)aPlaceHolder andInputView:(UIView *)aView andToolbar:(UIToolbar *)aToolbar {
[super setTag:aTag andHeader:aHeader andEditPoint:self.editableLabel];
self.placeHolderLabel.text = aPlaceHolder;
[self.editableLabel setInputView:aView andToolbar:aToolbar];
}
- (void) setValue:(NSString *)aValue {
if (aValue && aValue != @"") {
self.placeHolderLabel.hidden = YES;
self.editableLabel.text = aValue;
} else {
self.editableLabel.text = nil;
self.placeHolderLabel.hidden = NO;
}
}
@end
EditableGenderCell.h
@protocol EditableGenderCellDelegate <NSObject>
@required
- (NSString *) getTextForGender:(Gender)aGender;
- (void) genderChangedTo:(Gender)aGender forTag:(CellTag)aTag;
@end
@interface EditableGenderCell : EditableLabelCell <UITableViewDataSource, UITableViewDelegate> {
id<EditableGenderCellDelegate> delegate;
Gender gender;
IBOutlet UITableView *genderTable;
IBOutlet UIToolbar *doneBar;
}
- (void) setTag:(CellTag)aTag
andDelegate:(id<EditableGenderCellDelegate>)aDelegate
andHeader:(NSString *)aHeader
andGender:(Gender)aGender
andPlaceHolder:(NSString *)aPlaceHolder;
@property (nonatomic, retain) id<EditableGenderCellDelegate> delegate;
@property (nonatomic) Gender gender;
@property (nonatomic, retain) UITableView *genderTable;
@property (nonatomic, retain) UIToolbar *doneBar;
@end
EditableGenderCell.m
@implementation EditableGenderCell
@synthesize delegate, gender, genderTable, doneBar;
- (void) dealloc {
[delegate release];
[genderTable release];
[doneBar release];
[super dealloc];
}
- (void) setTag:(CellTag)aTag andDelegate:(id<EditableGenderCellDelegate>)aDelegate andHeader:(NSString *)aHeader andGender:(Gender)aGender andPlaceHolder:(NSString *)aPlaceHolder {
[super setTag:aTag andHeader:aHeader andPlaceHolder:aPlaceHolder andInputView:self.genderTable andToolbar:self.doneBar];
self.delegate = aDelegate;
self.gender = aGender;
[super setValue:[self.delegate getTextForGender:aGender]];
}
#pragma mark - Table view data source
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 2;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
switch (indexPath.row) {
case MALE:
switch (self.gender) {
case MALE:
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
default:
cell.accessoryType = UITableViewCellAccessoryNone;
}
break;
case FEMALE:
switch (self.gender) {
case FEMALE:
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
default:
cell.accessoryType = UITableViewCellAccessoryNone;
}
break;
}
cell.textLabel.text = [self.delegate getTextForGender:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
#pragma mark - Table view delegate
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.gender = indexPath.row;
[super setValue:[self.delegate getTextForGender:self.gender]];
[self.delegate genderChangedTo:self.gender forTag:self.tag];
[tableView reloadData];
}
@end
最佳答案
看看我对 How to make a UITableViewCell with different subviews reusable? 的回答.
您应该使用表示您的单元格的自定义类来备份您的自定义 tableviewcell nib 文件,并将逻辑封装在其中,例如您的性别选择器。如果您需要将性别告知某些外部 Controller ,您可以使用委托(delegate)模式。
TableViewCell 中的自定义性别选择器
好的,让我们从 nib 文件开始,如下所示:
查看层次结构,不要设置文件的所有者...
...改为设置自定义类的 TableView 单元格的类:
自定义类
如您所见,该类几乎是空的,仅提供分段控件作为属性
GenderPickerTableViewCell.h
@interface GenderPickerTableViewCell : UITableViewCell
{
UISegmentedControl *genderPickerSegmentedControl;
}
@property (nonatomic, retain) IBOutlet UISegmentedControl *genderPickerSegmentedControl;
@end
GenderPickerTableViewCell.m
#import "GenderPickerTableViewCell.h"
@implementation GenderPickerTableViewCell
@synthesize genderPickerSegmentedControl;
#pragma mark -
#pragma mark memory management
- (void)dealloc
{
[genderPickerSegmentedControl release];
[super dealloc];
}
#pragma mark -
#pragma mark initialization
- (void)awakeFromNib
{
// initialization goes here, for example preselect a specific gender
}
@end
使用新单元格的表格 View
我将只提供必要的方法来完成这项工作。 TableViewCellFactory 类只是一个 nib 加载器,就像我在 referenced answer 中发布的那样多于。 genderPickerTableViewCellWithTableView 只是一个方便的类方法,无需太多样板代码即可返回那种特殊类型的单元格
要注意的最后一件重要事情是单元格的配置,这很简单,我只是直接访问分段控件并向其添加一个目标,该目标通知此 View Controller 有关更改。
#pragma mark -
#pragma mark view lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
tableView.rowHeight = 100.0;
tableView.dataSource = self;
tableView.delegate = self;
}
#pragma mark -
#pragma mark UITableView methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *) tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)anIndexPath
{
GenderPickerTableViewCell *cell = [TableViewCellFactory genderPickerTableViewCellWithTableView:aTableView];
[cell.genderPickerSegmentedControl addTarget:self
action:@selector(genderPicked:)
forControlEvents:UIControlEventValueChanged];
return cell;
}
#pragma mark -
#pragma mark UISegmentedControl action
- (void)genderPicked:(id)sender
{
UISegmentedControl *segmentedControl = (UISegmentedControl *)sender;
NSLog(@"selected index: %d", [segmentedControl selectedSegmentIndex]);
}
我希望这对开始有所帮助。
关于iphone - 自定义 UITableViewCells,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6017299/