有一种需求,想必大家都遇到过..
简单的描述就是在 cell 上有个 button, 点击 button 出现勾选或者未勾选状态,但是如果不进行一些处理,就一定会出现重用的情况,所谓的重用也就是说由于 cell 的重用机制,导致 cell 上的 button 没办有办法正确的保存当前的点击状态,上网查了下,总结起来一共有三种方法,两种是和创建 cell 的方法有关,不过都比较消耗内存,还有一种好像是用数组进行记录(本人比较笨,至今未想明如何记录),在我看来这三种方法我都不太想去用,但是当我去研究数组记录这个方法时,我突然想到,由于现在基本都使用 MVC 模式开发,既然数据与模型已经分离,那为何不在数据里(model 里)记录,在模型上显示呢.... cell 上的 UI 是根据 model 进行排布的,这样的话就不会出现 cell 重用的情况了,而且一定能准确的记录点击状态
首先,大家准备个数据源,我这里的数据都是写在 plist (Student.plist)文件里了,然后就是相应的图片,都准备好了就可以往下看代码了
这里先创建个单利,用来取出 plist 文件中的数据(MyData)
//
// MyData.h
// UI_Custom
//
// Created by Amydom on 16/11/22.
// Copyright (c) 2016年 Amydom. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Student.h"
@interface MyData : NSObject
-(void)getAllStudentDic;
+(instancetype)shareMyDataHandle;
@property(nonatomic,retain)NSMutableDictionary *allStudentDic;
@property(nonatomic,retain)NSMutableArray *allKeysArray;
@end
//
// MyData.m
// UI_Custom
//
// Created by Amydom on 16/11/22.
// Copyright (c) 2016年 Amydom. All rights reserved.
//
#import "MyData.h"
@implementation MyData
+(instancetype)shareMyDataHandle
{
static MyData *myData = nil;
if (myData == nil) {
myData = [[MyData alloc] init];
[myData getAllStudentDic];
}
return myData;
}
-(void)getAllStudentDic
{
self.allStudentDic = [NSMutableDictionary dictionary];
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Student" ofType:@"plist"];
NSMutableDictionary *myDic = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
for (NSString *key in myDic.allKeys) {
NSMutableArray *array = [myDic objectForKey:key];
NSMutableArray *studentArray = [NSMutableArray array];
for (NSDictionary *dic in array) {
Student *stu = [[Student alloc] init];
[stu setValuesForKeysWithDictionary:dic];
[studentArray addObject:stu];
}
[self.allStudentDic setObject:studentArray forKey:key];
}
self.allKeysArray = [NSMutableArray arrayWithArray:self.allStudentDic.allKeys];
[self.allKeysArray sortUsingSelector:@selector(compare:)];
}
@end
接下来是 model(Student)
//
// Student.h
// UI_Custom
//
// Created by Amydom on 16/11/22.
// Copyright (c) 2016年 Amydom. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface Student : NSObject
@property(nonatomic,copy)NSString *studentName;
@property(nonatomic,copy)NSString *phoneNumber;
@property(nonatomic,copy)NSString *contents;
@property(nonatomic,copy)NSString *picName;
@property(nonatomic,assign)BOOL selected;
@end
//
// Student.m
// UI_Custom
//
// Created by Amydom on 16/11/22.
// Copyright (c) 2016年 Amydom. All rights reserved.
//
#import "Student.h"
@implementation Student
-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{
}
@end
有关于数据类型的类我们已经创建完成了,接下来是自定义 cell(MyTableViewCell)
//
// MyTableViewCell.h
// UI_Custom
//
// Created by Amydom on 16/11/22.
// Copyright (c) 2016年 Amydom. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "Student.h"
@protocol MyTableViewCellDelegate <NSObject>
-(void)studentInfo:(Student *)student;
@end
@interface MyTableViewCell : UITableViewCell
@property(nonatomic,retain)Student *stu;
@property(nonatomic,retain)UILabel *label;
@property(nonatomic,retain)UILabel *contentLable;
@property(nonatomic,retain)UIImageView *headImageView;
@property(nonatomic,retain)UIButton *button;
@property(nonatomic,assign)id<MyTableViewCellDelegate>MyCellDelegate;
+(CGFloat)heightForCell:(NSString *)content;
@end
//
// MyTableViewCell.m
// UI_Custom
//
// Created by Amydom on 16/11/22.
// Copyright (c) 2016年 Amydom. All rights reserved.
//
#import "MyTableViewCell.h"
@implementation MyTableViewCell
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self createSubviews];
}
return self;
}
-(void)createSubviews
{
self.label = [[UILabel alloc] initWithFrame:CGRectMake(70, 5, 200, 30)];
[self.contentView addSubview:self.label];
self.contentLable = [[UILabel alloc] initWithFrame:CGRectMake(70, 40, 300, 40)];
self.contentLable.font = [UIFont systemFontOfSize:15.0];
self.contentLable.numberOfLines = 0;
[self.contentView addSubview:self.contentLable];
self.headImageView = [[UIImageView alloc] initWithFrame:CGRectMake(5, 10, 60, 60)];
[self.contentView addSubview:self.headImageView];
self.button = [UIButton buttonWithType:UIButtonTypeCustom];
self.button.frame = CGRectMake(330, 10, 24, 24);
[self.button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:self.button];
}
-(void)buttonAction:(UIButton *)button
{
if (self.stu.selected) {
//2.点击按钮的时候加判断
[self.button setBackgroundImage:[UIImage imageNamed:@"check.png"] forState:UIControlStateNormal];
self.headImageView.hidden = NO;
}else
{
[self.button setBackgroundImage:[UIImage imageNamed:@"checked.png"] forState:UIControlStateNormal];
self.headImageView.hidden = YES;
}
self.stu.selected = !self.stu.selected;
[self.MyCellDelegate studentInfo:self.stu];
}
-(void)setStu:(Student *)stu
{
if (_stu != stu) {
_stu = stu;
}
//赋值
self.label.text = _stu.studentName;
self.contentLable.text = _stu.contents;
CGRect frame = self.contentLable.frame;
//计算高度
frame.size.height = [[self class] heightForCell:_stu.contents];
self.contentLable.frame = frame;
UIImage *image = [UIImage imageNamed:_stu.picName];
self.headImageView.image = image;
//1.上拉下拉cell会重用cell,所以需要在赋值的时候加判断
[self.button setBackgroundImage:[UIImage imageNamed:@"check.png"] forState:UIControlStateNormal];
self.headImageView.hidden = NO;
if (_stu.selected) {
[self.button setBackgroundImage:[UIImage imageNamed:@"checked.png"] forState:UIControlStateNormal];
self.headImageView.hidden = YES;
}
}
#pragma mark - cell 自适应高度
+(CGFloat)heightForCell:(NSString *)content
{
CGSize size = CGSizeMake(300, 2000);
NSDictionary *dic = [NSDictionary dictionaryWithObject:[UIFont systemFontOfSize:15.0] forKey:NSFontAttributeName];
CGRect frame = [content boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:dic context:nil];
return frame.size.height;
}
- (void)awakeFromNib {
// Initialization code
NSLog(@"aaaaa");
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
NSLog(@"bbbbbbbbbbbb");
}
@end
到这里为止我们的 cell 重用已经解决了,之后就是在Controller 里使用了
//
// RootViewController.h
// UI_Custom
//
// Created by Amydom on 16/11/22.
// Copyright (c) 2016年 Amydom. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "MyData.h"
#import "MyTableViewCell.h"
@interface RootViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,MyTableViewCellDelegate>
@property(nonatomic,retain)UITableView *myTableView;
@end
//
// RootViewController.m
// UI_Custom
//
// Created by Amydom on 16/11/22.
// Copyright (c) 2016年 Amydom. All rights reserved.
//
#import "RootViewController.h"
@interface RootViewController ()
@end
@implementation RootViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
self.myTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds] style:UITableViewStylePlain];
[self.view addSubview:self.myTableView];
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [[MyData shareMyDataHandle].allKeysArray objectAtIndex:section];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *key = [[MyData shareMyDataHandle].allKeysArray objectAtIndex:section];
NSMutableArray *array = [[MyData shareMyDataHandle].allStudentDic objectForKey:key];
return array.count;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [MyData shareMyDataHandle].allKeysArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"cell";
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
NSString *key = [[MyData shareMyDataHandle].allKeysArray objectAtIndex:indexPath.section];
NSArray *array = [[MyData shareMyDataHandle].allStudentDic objectForKey:key];
Student *stu = [array objectAtIndex:indexPath.row];
cell.stu = stu;
cell.MyCellDelegate = self;
return cell;
}
-(void)studentInfo:(Student *)student
{
NSLog(@"name = %@ contents = %@",student.studentName, student.contents);
}
//cell 高度
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *key = [[MyData shareMyDataHandle].allKeysArray objectAtIndex:indexPath.section];
NSMutableArray *array = [[MyData shareMyDataHandle].allStudentDic objectForKey:key];
Student *stu = [array objectAtIndex:indexPath.row];
CGFloat height = [MyTableViewCell heightForCell:stu.contents];
return height + 60;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end