UI基础之------UITableView高级

一 自定义 cell

1.在实际编程的过程中,往往会根据不同的需求,设计出不同的界面样式,所以我们需要在系统提供的控件的基础上,自定义控件用来布局界面.

2.自定义cell 就是创建一个UITableViewCell的子类.

3.把 cell 上的控件创建都封装在子类中,简化UIViewController 中的代码

4.子视图控件添加到 cell的 contentView 上.

二 cell 中的控件显示 Model 中的信息

1.    cell 中声明了一个 Model 类型的属性,viewController 中获取到 Mode 对象后赋值给 cell的 Model 属性

2.    cell 中重写 Model 的 setter 方法,把 Model 对象中的内容重新赋值给各个控件

3.    M和 V不直接进行通信, C负责 M和 V之间进行通信

三 cell 中的自定义控件

1.    计算文本高度是所用的字体要和 label 显示时用的字体一致

2.    label 的宽度要和计算时使用的限定宽度一致

3.    这样才能保证文本显示在 label 中时, label 中时, label 高度恰巧够.

4.     tableView: heightForRowAtIndexPath: 方法要比 tableView:cellForRowAtIndexPath先执行

5.    所以要提前计算号每个文本cell 需要的高度

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *)indexPath{

需要一个 News对象, cellHeight是一个自定义的类方法,所有只能通过类进行调用

return [NewCellcellHeight:self:mArray[indexPath.row]];

}

6.    自定义计算文本高度的方法:

1>主要方法:

[summary boundingRectWithSize:size  options:

NSStringDrawingUsesLineFragmentOriginattributes:attributes context:nil]

  2>设置了 cell 的高度之后,还不能实现文本内容的自适应,需要将显示文本的 Lable 控件也设置为自适应高度,所以需要在对 Lable 赋值完成之后进行设置

 (因为不能在 frame 中对高度进行修改)所以需要先取出 frame 的值,进行修改,完成之后,再重新对 frame 进行赋值(修改的时候,使用[self class]调取类方法进行操作)

7.    使用自定义的 cell的时候,使用步骤:

1>  首先需要在根视图控制器文件中引入自定义的 cell 文件;

2>  然后在视图控制器的viewDidLoad 方法中进行注册;(可以注册多个自定义cell)

[self.tableViewregisterClass: [(自定义 cell控件名称) class] forCellReuseIdentifier:@”cell” ];

3>  第三步是在创建 cell 的方法中进行赋值(在tableview:cellForRowAtIndexPath:方法中进行赋值)

①  从数组中取出存储的Student对象

Student *stu =self.mArray[indexPath.row];

②  在重用池中查找是否存在带有步骤2中”cell”标记的自定义 cell

GrilTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@”cell”forIndexPath:indexPath];

③  将从数组中取出的数据对象赋值给自定义 cell. student 进行显示

cell.student = stu;

8.    从 plist 中读取数据,并将数据存放到数组中

1>  首先定义一个可变数组(为了方便操作,一般定义成私有属性)

@property (nonatomic,retain) NSMutableArray *mArray;

2>  从文件中读取数据

①  获取文件路径

NSString *filePath =[[NSBundle mainBundle]pathForResource:@”StudentList” ofType:@”plist”];

②  获取文件的数据(如果文件最外层是数组的话.就用数组获取;如果是字典,就使用字典获取)

NSArray *array =[NSArray arrayWithContentsOfFile:filePath];

在这里可以对读取的内容进行打印,以检测是否获取到文件的内容

NSLog(@”%@”,array);

③  初始化定义的数组,然后才能使用.

self.mArray =[NSMutableArray arrayWithCapacity:15];

④  遍历第二步创建的数组

for(NSDictionary *dicin array){

// 将字典中的数据封装成student对象

Student *student =[[Student alloc]init];

// 在字典中根据 key 值找到对应的 value 值并赋值给 student 对象对应的属性(是一个非常方便的方法)

[student setValuesForKeysWithDictionary:dic]

在使用上面方法的时候,问了防止取到的数据为空,而造成程序崩溃,需要在定义的 Model 文件中(也就是存储数据的文件)添加下面的方法:

// 防止没有定义 key 值时,还在为 key 的 Value 赋值造成的崩溃问题(方法内容可以不用实现)

-(void)setValue:(id)value forUndefinedKey: (NSString *)key{ }

⑤   将封装的对象添加到数组中

[self.mArrayaddObject:student];

         最后释放 student 对象

         [student release];

}

3>  最后只需要在创建 cell的时候取出数组中的对象进行操作就可以了.

9.    在自定义 TableViewCell 的时候,需要重写 init 方法

-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier: (NSString *)reuseIdentifier{

self = [superinitWithStyle:style reuseIdentifier: reuseIdentifier];

   if(self){

   [self p_setUp];

   }

   return self;    }

10 .cell 中的控件显示 Model 中的信息

 1>cell 中声明了一个 Model 类型的属性, viewController 中获取到 Mode 对象后赋值给 cell Model 属性

 2>cell 中重写 Model setter 方法, Model 对象中的内容重新赋值给各个控件

重写 student 属性的 setter 方法,实现两步操作

-(void)setStudent: (Student *)student{

// 1.存储数据对象

if(_student != student){

[_student release];

_student = [student retain];

}

// 2.将传入的数据赋值到 cell 子视图上显示

self.nameLable.text = student.name;

self.ageLable.text = student.age;

}

 3>M V不直接进行通信, C负责 M V之间进行通信


主要代码:

1自定义 cell

#import "RootTableViewController.h"
#import "Student.h"
#import "BoyTableViewCell.h"
#import "GirlTableViewCell.h"
#define kBoyCell @"boyCell"
#define kGirlCell @"GirlCell"
@interface RootTableViewController ()
@property (nonatomic,retain) NSMutableArray *mArray;
@property (nonatomic,retain) NSMutableDictionary *mDic;
@end
@implementation RootTableViewController
-(void)dealloc{
    [_mDic release];
    [_mArray release];
    [super dealloc];
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [self configureNavigation];
    [self readDataFromPlist];
#warning 使用自定义 cell, 需要进行注册(可以注册对个自定义cell)
    [self.tableView registerClass:[BoyTableViewCell class] forCellReuseIdentifier:kBoyCell];
    
    [self.tableView registerClass:[GirlTableViewCell class] forCellReuseIdentifier:kGirlCell];
}
// 导航条添加标题
- (void)configureNavigation{
    self.navigationItem.title = @"通讯录";
}
//读取并存储文件
- (void)readDataFromPlist{
// 1.获取文件路径
    NSString *filePath = [[NSBundle mainBundle]pathForResource:@"StudentList" ofType:@"plist"];
    // 2.获取文件中的数据存放到字典中
    NSArray *array = [NSArray arrayWithContentsOfFile:filePath];
    //通过打印的方法,检查是否读取了数据
    NSLog(@"%@",array);
    // 3.初始化定义的可变数组
    self.mArray  = [NSMutableArray arrayWithCapacity:0];
    // 4.遍历存放数据的数组 array
    for (NSDictionary *dic in array) {
        // 5.创建学生对象
        Student *stu = [[Student alloc]init];
        // 6.将字典中的数据封装成 stu 对象(比较重要的方法)
        [stu setValuesForKeysWithDictionary:dic];
        // 7.将封装的对象添加到数组中
        [self.mArray addObject:stu];
        [stu release];
    }
}
#pragma mark - Table view data source
// 返回分区的个数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
// 放回每个分区的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.mArray.count;
}
// 添加cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
#warning 使用自定义 cell ,获取数据
    // 使用自定义数据创建 cell
    // 1.取出数据
    Student *stu = self.mArray[indexPath.row];
    // 2.根据性别选择不同的 cell
    if ([stu.gender isEqualToString:@"女"]) {
        GirlTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kGirlCell forIndexPath:indexPath];
        cell.student = stu;
        return cell;
    }else{
        BoyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kBoyCell forIndexPath:indexPath];
        cell.student = stu;
        return cell;
    }
}
// 返回自定义 cell 的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 130;
}

2.自定义 cell 代码:

#import "BoyTableViewCell.h"
#import "Student.h"
@implementation BoyTableViewCell
- (void)dealloc{
    [_phoneLable release];
    [_ageLable release];
    [_images release];
    [_nameLable release];
    [_student release];
    [super dealloc];
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self p_setUp];
    }
    return self;
}
- (void)p_setUp{
    self.nameLable = [[UILabel alloc]initWithFrame:CGRectMake(10, 5, 100, 40)];
    self.nameLable.backgroundColor = [UIColor clearColor];
    [self.contentView addSubview:self.nameLable];
    [self.nameLable release];
    
    self.ageLable = [[UILabel alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.nameLable.frame)  + 20, CGRectGetMinY(self.nameLable.frame), CGRectGetWidth(self.nameLable.frame) - 20, CGRectGetHeight(self.nameLable.frame))];
    self.ageLable.backgroundColor = [UIColor clearColor];
    [self.contentView addSubview:self.ageLable];
    [self.ageLable release];
    
    self.phoneLable = [[UILabel alloc]initWithFrame:CGRectMake(CGRectGetMinX(self.nameLable.frame),CGRectGetMaxY(self.nameLable.frame) + 40,CGRectGetWidth(self.nameLable.frame) * 2,CGRectGetHeight(self.nameLable.frame))];
    self.phoneLable.backgroundColor = [UIColor clearColor];
    [self.contentView addSubview:self.phoneLable];
    [self.phoneLable release];
    
    self.images = [[UIImageView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.ageLable.frame) + 20, CGRectGetMinY(self.nameLable.frame), CGRectGetWidth(self.ageLable.frame), CGRectGetHeight(self.nameLable.frame) * 3)];
    self.images.backgroundColor = [UIColor clearColor];
    [self.contentView addSubview:self.images];
    [self.images release];
}
// cell 使用 Model 展示数据,所以需要重写 setter 方法
- (void)setStudent:(Student *)student{
    // 1.存数数据对象
    if (_student != student) {
        [_student release];
        _student = [student retain];
    }
    // 2.将传入的数据赋值到 cell子视图上显示
    self.nameLable.text = student.name;
    self.ageLable.text = student.age;
    self.phoneLable.text = student.phone;
    self.images.image = [UIImage imageNamed:student.imageName];
}
@end

3.Model

Student.h

#import 

@interface Student : NSObject
// model 的属性要根据存储的数据类型合和个数来确定,属性名尽量拷贝
@property (nonatomic,retain) NSString *name;
@property (nonatomic,retain) NSString *gender;
@property (nonatomic,retain) NSString *age;
@property (nonatomic,retain) NSString *phone;
@property (nonatomic,retain) NSString *imageName;
@end

Student.m

#import "Student.h"

@implementation Student
- (void)dealloc{
    [_imageName release];
    [_phone release];
    [_gender release];
    [_age release];
    [_name release];
    [super dealloc];
}
// 防止没有定义 key 值时,还在为对应的 key 的 value 赋值 崩溃的问题
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{

}
@end
4.cell 文本自适应高度方法

// 重写 setter方法
- (void)setNews:(News *)news{
// 1.给属性赋值
    if (_news != news) {
        [_news release];
        _news = [news retain];
    }
   // 2.使用 news 给 cell 上的子视图赋值
    self.titleLable.text = news.title;
    self.textLable.text  = news.summary;
#warning 修改 textLable 的高度
    // 1.先取出 frame 的值
    CGRect textRect = self.textLable.frame;
    // 2.修改 frame 的高,在对象方法中,使用类的时候使用[self class]
    textRect.size.height = [[self class] summaryHeight:news.summary];
    // 3,重新为 frame 赋值
    self.textLable.frame = textRect;
}

#warning 计算文本自适应高度核心算法
+(CGFloat)cellHeigth:(News *)news{
    CGFloat summaryHeight = [self summaryHeight:news.summary];
    return 10 + 40 + 10 + 20 + summaryHeight;
}
// 计算文本的高度
+ (CGFloat)summaryHeight:(NSString *)summary{
//文本渲染时需要的矩形大小,按要求宽度要和文本大小的宽一样,必须是固定值(280),高度可以设置为(0或10000),最终文本高度大小是根据文本内容计算得到的
    CGSize size = CGSizeMake(280, 0);
    // 计算时设置的字体大小,必须要和我们显示文本设置字体大小保持一致
    NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:18.0]};
    CGRect summaryRect = [summary boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil];
    // 返回计算得到的高度即可
    return summaryRect.size.height;
}

// 代理方法在试图控制器文件实现
// delegate 返回 cell 的高度,这个方法要比 tableView: cellForRowAtIndexPath:方法提前执行
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return [NewsCell cellHeigth:self.mArray[indexPath.row]];
} 


你可能感兴趣的:(UI,UITableViewCell,自定义,cell,cell,文本自适应高度)