在上一篇文章的最後有說到在cell中帶有UITextField的時候,在cell的複用機制下會有一些問題。關於這個問題的解決其實我們可以參照cell的複用機制。說的有點繞哈。。。
解決複用帶來的問題,還是用複用的機制,確實挺饒人的。下面來詳細說一下。
上一篇文章中的代碼和文字已經介紹了複用機制,在tableView中的cell都有一個id作爲表示,在tableView中展示出來的cell也都有一個唯一的表示,那就是:indexPath。展示出來的每一個cell都有一個indexPath,所以我們的解決辦法就是利用這個indexPath。原理和複用池很像,下面說原理:
我們可以設計一個數據模型(model)類,用於存放我們每一個cell中textField中輸入的文字,這個model類中設置一個屬性爲:indexPath,這個屬性和cell的indexPath對應,每一個cell上的indexPath和textField輸入的文字就可以作爲一個model類的對象存入一個數組中。這樣就可以將數組中model類的每一個對象和cell一一對應。當滾動時就不會出現已經輸入的文字消失的問題了。
仔細想一想上面的這個model數組,是不是和複用池有點相似。下面我們就代碼實現以下。
首先創建一個model類
CustomerModel.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface CustomerModel : NSObject
@property (nonatomic, strong) NSString *text;
@property (nonatomic, strong) NSIndexPath *index;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
NS_ASSUME_NONNULL_END
CustomerModel.m
#import "CustomerModel.h"
@implementation CustomerModel
- (instancetype)initWithDict:(NSDictionary *)dict {
self = [super init];
if (self) {
_text = dict[@"text"];
_index = dict[@"index"];
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {}
@end
然後自定義cell
CustomerCell.h
#import <UIKit/UIKit.h>
#import "CustomerModel.h"
NS_ASSUME_NONNULL_BEGIN
//設置一個代理,用於將textField中d輸入的值傳遞到Ccontroller中去處理
@protocol CustomerCellDelegate <NSObject>
@optional
- (void)textFieldCellText:(NSString *)text index:(NSIndexPath *)index;
@end
@interface CustomerCell : UITableViewCell
//創建model對象
@property (nonatomic, strong)CustomerModel *model;
//聲明代理
@property (nonatomic, weak) id<CustomerCellDelegate> delegate;
@end
NS_ASSUME_NONNULL_END
CustomerCell.m
#import "CustomerCell.h"
@interface CustomerCell()<UITextFieldDelegate>
{
//聲明兩個視圖
UITextField *textField;
}
@end
@implementation CustomerCell
//重寫init方法
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
//調用父類init方法創建
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.backgroundColor = [UIColor yellowColor];
//創建成功則給cell添加需要的子視圖
textField = [[UITextField alloc] init];
textField.delegate = self;
textField.backgroundColor = [UIColor whiteColor];
textField.borderStyle = UITextBorderStyleLine;
[self.contentView addSubview:textField];
}
return self;
}
//重寫layoutSubviews方法,給視圖設置位置大小
- (void)layoutSubviews{
textField.frame = CGRectMake(20, 5, 200, 30);
}
//代理方法
- (void)textFieldDidEndEditing:(UITextField *)textField{
if ([self.delegate respondsToSelector:@selector(textFieldCellText:index:)]) {
//這裏講textField中輸入的內容和model中存儲的index傳遞到controller
[self.delegate textFieldCellText:textField.text index:_model.index];
}
}
//model對象賦值
- (void)setModel:(CustomerModel *)model{
_model = model;
textField.text = model.text;
}
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
在controller中調用
#import "ViewController.h"
#import "CustomerCell.h"
#import "CustomerModel.h"
@interface ViewController ()<UITableViewDelegate, UITableViewDataSource, CustomerCellDelegate>//添加協議
{
//聲明tableView和數據源
UITableView *table;
NSMutableArray *dataSource;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self createDataSource];
[self createTableView];
}
//創建數據源
- (void)createDataSource{
//初始化數據源數組
dataSource = [NSMutableArray arrayWithCapacity:0];
//循環創建model,s初始設置text爲空,並編號index
for (int i = 0; i < 20; i++) {
CustomerModel *model = [[CustomerModel alloc] init];
model.text = @"";
NSIndexPath *index = [NSIndexPath indexPathForRow:i inSection:0];
model.index = index;
[dataSource addObject:model];
}
}
//創建tableView視圖
- (void)createTableView{
//創建並設置位置大小和風格形式
table = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
//設置代理
table.delegate = self;
table.dataSource = self;
//設置縱橫滑塊不顯示
table.showsVerticalScrollIndicator = NO;
table.showsHorizontalScrollIndicator = NO;
[self.view addSubview:table];
}
#define mark --UITableViewDelegate
//設置列表中每個元素的行高,在非動態行高的情況下設置固定值。動態行高的情況需要計算。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 64;
}
//設置列表中元素的個數 一般設置爲數據源中元素的個數
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return dataSource.count;
}
//創建tableView中的每一個cell,這裏使用複用機制。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CustomerCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[CustomerCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}
cell.model = dataSource[indexPath.row];
cell.delegate = self;
return cell;
}
//代理回調,比對indexPath將對應的text進行修改保存
- (void)textFieldCellText:(NSString *)text index:(NSIndexPath *)index{
for (int i = 0; i < dataSource.count; i++) {
CustomerModel *model = dataSource[i];
if (index == model.index) {
model.text = text;
}
}
}
//收起鍵盤
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[self.view endEditing:YES];
}
//收起鍵盤
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
}
@end
上面的代碼就足以解決cell中有textField時因爲cell複用二產生的問題,當然還有別的方法可以解決這個問題,這裏就不多說了。