您的位置:首页 > 产品设计 > UI/UE

IOS开发UI篇--UITableView的自定义布局==纯代码布局

2014-05-29 20:27 363 查看
UITableView中除了利用系统的UItableViewCell不能完成需求进行布局时,还可以进行自定义布局;

自定义布局分为两类:(1)利用代码进行创建

(2)利用xib进行实现;

下面对利用代码进行创建分析:

应用场景:像微博,等列表数据展示(由于微博的每个单元格的数据大小不一致,所以得计算每个单元格的大小)
分析:前提是获取列表数据,然后建立每个单元格的模型(建立单元格模型应继承UITableViewCell)复写
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
此方法即可,在此方法中添加单元格所需要的各个视图控件, 然后根据微博对象模型,确定每个控件的位置,并进行数据
的填充,
主要在此方法中几个重要的方法:(特别是方法的执行顺序)
1.-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
2.-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath


下面以一个例子进行说明:

由于本案例整个界面就是单独的一个UITableView,故而主控制器设置成UITableViewController;这样可以减少很多连线问题,

因为UITableViewController里面已进行关联,且内部也开放出来了tableview;可以直接使用

(1)下面是一个SLViewController.m文件

#import "SLViewController.h"

#import "SLWeiBo.h"
#import "SLWeiBoCell.h"
#import "SLWeiBoFrame.h"

@interface SLViewController ()

//定义数组,保存模型数据
@property (nonatomic,strong)NSArray *statusFrames;

@end

@implementation SLViewController

- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView ;
}

#pragma mark -懒加载
-(NSArray *)statusFrames
{
if (_statusFrames==nil) {
//加载plist数据文件
NSString *fullpath=[[NSBundle mainBundle] pathForResource:@"statuses" ofType:@"plist"];
NSArray *arr=[NSArray arrayWithContentsOfFile:fullpath];
NSMutableArray *mutearr=[NSMutableArray arrayWithCapacity:arr.count];
for (NSDictionary *dict in arr) {
//字典转模型,传进去一个字典,返回一个微博模型
SLWeiBo *weibo=[SLWeiBo weiBoWithDict:dict];
//计算每一个表格的高度并保存
SLWeiBoFrame *weiboframe=[[SLWeiBoFrame alloc] init];
weiboframe.weibo=weibo;
//把Frame模型保存到数组中
[mutearr addObject:weiboframe];
}

self.statusFrames=[mutearr mutableCopy];
}
return _statusFrames;
}

#pragma mark -实现数据源方法
/**
*  tableview中返回一共有多少组,有一组的话,可以省略不写
*
*  @param tableView
*
*  @return 返回有多少组
*/
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
/**
*  tableview返回一共有多少个单元格
*
*  @param tableView
*  @param section   第几组
*
*  @return 某组有多少单元格
*/
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.statusFrames.count;
}

/**
*  tableView返回每个单元格的对象
*
*  @param tableView
*  @param indexPath 保存有该对象是第几组,第几个单元格
*
*  @return 返回每个单元格对象
*/
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//1.从缓存中取数据
static NSString *identifier=@"status";
SLWeiBoCell *cell=[tableView dequeueReusableCellWithIdentifier:identifier];
//2创建表格
if (cell==nil) {
cell=[[SLWeiBoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
//3设置数据
SLWeiBoFrame *frame=self.statusFrames[indexPath.row];
cell.itemframe=frame;
return cell;
}
#pragma mark -实现高度的代理方法
/**
*  计算每个单元格的高度
*
*  @param tableView
*  @param indexPath 该单元格是某组某行的单元格
*
*  @return 返回该单元格的高度
*/
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
SLWeiBoFrame *frame=self.statusFrames[indexPath.row];
return frame.cellHeight;
}
/**
*  设置是否显示状态栏
*
*  @return 返回YES,不显示,返回NO,显示
*/
-(BOOL)prefersStatusBarHidden
{
return NO;
}
@end


(2)这个SLWeiBo.H与SLWeiBo.m Global.h文件

第一个文件是定义一些基本属性,用来进行字典转换模型;并定义了两个方法,一个是类方法,一个实例方法,在第二个文件中进行实现

第三个文件是对第一个和第二个文件的定义方法进行的抽取,方便重用,第三个文件利用定义宏进行代码抽取,

#import "Global.h"
/**
*  创建一个微博对象,保存模型数据
*/
@interface SLWeiBo : NSObject

@property (nonatomic,copy) NSString *text;//内容
@property (nonatomic,copy) NSString *icon;//头像
@property (nonatomic,copy) NSString *name;//昵称
@property (nonatomic,copy) NSString *picture;//配图
//是否是vip
@property (nonatomic,assign) BOOL vip;

initWeiBo(weiBo)
////进行转换的实例方法
//-(instancetype)initWithWeiBo:(NSDictionary *)dict;
//// 进行转换的类方法
//+(instancetype)weiBoWithDict:(NSDictionary *)dict;

@end


#import "SLWeiBo.h"

@implementation SLWeiBo

//分别对类方法和实例方法进行实现
weiBoInitDict(weiBo);
//-(instancetype)initWithWeiBo:(NSDictionary *)dict;
//{
//    if (self=[super init]) {
//        [self setValuesForKeysWithDictionary:dict];
//    }
//    return self;
//}
//
//+(instancetype)weiBoWithDict:(NSDictionary *)dict
//{
//    return [[self alloc] initWithWeiBo:dict];
//}

@end


#ifndef ___Global_h
#define ___Global_h

#define initWeiBo(name)\
-(instancetype) initWithWeiBo:(NSDictionary *)dict;\
+(instancetype) name##WithDict:(NSDictionary *)dict;

#define weiBoInitDict(name)\
-(instancetype) initWithWeiBo:(NSDictionary *)dict;\
{\
if (self=[super init]) {\
[self setValuesForKeysWithDictionary:dict];\
}\
return self;\
}\
+(instancetype) name##WithDict:(NSDictionary *)dict\
{\
return [[self alloc] initWithWeiBo:dict];\
}
#endif


(3)SLWeiBoCell.h和SLWeiBoCell.m文件是继承自UITableViewCell的,是对UITableViewCell进行的重写,已到达所需要的要求界面,

  并设置数据,与设置位置。

#import <UIKit/UIKit.h>
@class SLWeiBoFrame;

@interface SLWeiBoCell : UITableViewCell
//导入SLweiboFrame对象,保存着一个单元格里面每个控件的位置,及weibo对象
@property (nonatomic,strong) SLWeiBoFrame *itemframe;

@end


#import "SLWeiBoCell.h"

#import "SLWeiBoFrame.h"

#define SLFontNiCheng [UIFont systemFontOfSize:15]
#define SLFontZhengWen [UIFont systemFontOfSize:16]
@interface SLWeiBoCell()
//头部头像
@property (nonatomic,weak) UIImageView *iconheader;
//昵称
@property (nonatomic,weak) UILabel *nicheng;
//是否是vip
@property (nonatomic,weak) UIImageView *vip;
//正文显示
@property (nonatomic,weak) UILabel *zhengwen;
//配图显示
@property (nonatomic,weak) UIImageView *peitu;

@end

@implementation SLWeiBoCell

//复写此方法,以达到重写UITableViewCell的目的
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// 让自定义cell和系统的cell一样,创建出来就拥有一些子控件提供给我们使用
//1.创建头像
UIImageView *iconheader=[[UIImageView alloc] init];
[self.contentView addSubview:iconheader];
self.iconheader=iconheader;
//2.创建昵称
UILabel *nicheng=[[UILabel alloc] init];
nicheng.font=SLFontNiCheng;
[self.contentView addSubview:nicheng];
self.nicheng=nicheng;
//3.创建vip
UIImageView *vip=[[UIImageView alloc] init];
vip.image=[UIImage imageNamed:@"vip"];
[self.contentView addSubview:vip];
self.vip=vip;
//4创建正文
UILabel *zhengwen=[[UILabel alloc] init];
//让正文进行多行显示
zhengwen.numberOfLines=0;
//设置正文的字体,此时的字体应该在和计算该正文的字体长宽所用字体一致,
zhengwen.font=SLFontZhengWen;
[self.contentView addSubview:zhengwen];

self.zhengwen=zhengwen;
//5创建配图
UIImageView *peitu=[[UIImageView alloc] init];
[self.contentView addSubview:peitu];
self.peitu=peitu;
}
return self;
}
-(void)setItemframe:(SLWeiBoFrame *)itemframe
{
_itemframe=itemframe;
//设置数据
[self settingData];
//设置frame
[self settingFrame];
}

-(void)settingData
{
//设置头像
SLWeiBo *weibof=self.itemframe.weibo;
self.iconheader.image=[UIImage imageNamed:weibof.icon];
//设置昵称
self.nicheng.text=weibof.name;
//设置vip
if (weibof.vip) {
self.nicheng.textColor=[UIColor redColor];
self.vip.hidden=NO;
}else{
self.nicheng.textColor=[UIColor blackColor];
self.vip.hidden=YES;
}
//设置内容
self.zhengwen.text=weibof.text;
//设置配图
if (weibof.picture) {
self.peitu.image=[UIImage imageNamed:weibof.picture];
self.peitu.hidden=NO;
}else{
self.peitu.hidden=YES;
}
}

-(void)settingFrame
{
//1设置头像的frame
self.iconheader.frame=self.itemframe.iconF;
//2设置昵称的frame
self.nicheng.frame=self.itemframe.nichengF;
//3设置vip的frame
self.vip.frame=self.itemframe.vipF;
//4设置正文的frame
self.zhengwen.frame=self.itemframe.zhengwenF;
//5设置配图的frame
if (self.itemframe.weibo.picture) {
self.peitu.frame=self.itemframe.peituF;
}
}
@end


(4)SLWeiBoFrame.h和SLWeiBoFrame.m 文件是为了求行高而进行的数据抽取,即先计算出行的高,并且保存每行中控件的位置;

方便传给cell进行利用;

#import "SLWeiBo.h"
@interface SLWeiBoFrame : NSObject

/**
头像的frame
*/
@property (nonatomic,assign) CGRect iconF;
/**
昵称的frame
*/
@property (nonatomic,assign) CGRect nichengF;
/**
vip的frame
*/
@property (nonatomic,assign) CGRect vipF;
/**
正文的frame
*/
@property (nonatomic,assign) CGRect zhengwenF;
/**
配图的frame
*/
@property (nonatomic,assign) CGRect peituF;
/**
行高
*/
@property (nonatomic,assign) CGFloat cellHeight;
@property (nonatomic,strong) SLWeiBo *weibo;

@end


#import "SLWeiBoFrame.h"
#import "SLWeiBo.h"
#define SLFontNiCheng [UIFont systemFontOfSize:15]
#define SLFontZhengWen [UIFont systemFontOfSize:16]
@implementation SLWeiBoFrame

-(void)setWeibo:(SLWeiBo *)weibo
{

_weibo=weibo;
//间隙
CGFloat padding=10;
//1设置头像的frame
CGFloat iconViewX=padding;
CGFloat iconViewY=padding;
CGFloat iconViewW=30;
CGFloat iconViewH=30;
self.iconF=CGRectMake(iconViewX, iconViewY, iconViewW, iconViewH);

//2设置昵称的frame
CGFloat nichengX=CGRectGetMaxX(self.iconF)+padding;
/**
* attributes 告诉系统文字的大小
*/
// NSDictionary *dict=@{NSFontAttributeName:[UIFont systemFontOfSize:15]};

// 如果将来计算的文字的范围超出了指定的范围,就返回的就是指定的范围
//如果将来的文字范围小于指定的范围,就返回实际的范围
CGSize maxsize=CGSizeMake(MAXFLOAT, MAXFLOAT);
CGSize namesize=[self  sizeWithString:_weibo.name font:SLFontNiCheng maxSize:maxsize];
//    CGRect namesize= [_weibo.name boundingRectWithSize:maxsize options:NSStringDrawingUsesLineFragmentOrigin attributes:dict context:nil];

CGFloat nichengH=namesize.height;
CGFloat nichengW=namesize.width;

CGFloat nichengY=(self.iconF.size.height-nichengH)*0.5+iconViewY;
self.nichengF=CGRectMake(nichengX , nichengY, nichengW,nichengH);

//3设置vip的frame
CGFloat vipViewX=CGRectGetMaxX(self.nichengF)+padding;
CGFloat vipViewY=nichengY;
CGFloat vipViewW=14;
CGFloat vipViewH=14;
self.vipF=CGRectMake(vipViewX, vipViewY, vipViewW, vipViewH);

//4设置正文的frame

CGFloat zhengwenX=iconViewX;
CGFloat zhengwenY=CGRectGetMaxY(self.iconF)+padding;

CGSize maxsize1=CGSizeMake(300, MAXFLOAT);
CGSize zhengwensize=[self sizeWithString:_weibo.text font:SLFontZhengWen maxSize:maxsize1];
CGFloat zhengwenW=zhengwensize.width;
CGFloat zhengwenH=zhengwensize.height;

self.zhengwenF=CGRectMake(zhengwenX, zhengwenY, zhengwenW, zhengwenH);
//5设置配图的frame
//   CGFloat cellHeight=0;
if (_weibo.picture) {
CGFloat peituX=iconViewX;
CGFloat peituY=CGRectGetMaxY(self.zhengwenF)+padding;
CGFloat peituW=100;
CGFloat peituH=100;
self.peituF=CGRectMake(peituX, peituY, peituW, peituH);
self.cellHeight=CGRectGetMaxY(self.peituF)+padding;
}else
{
//无配图的情况下的行高
self.cellHeight=CGRectGetMaxY(self.zhengwenF)+padding;
}
}

/**
*  计算文本的宽高
*
*  @param str     文本显示
*  @param font    文本显示的字体
*  @param maxSize 文本显示的此存
*
*  @return
*/
-(CGSize)sizeWithString:(NSString *)str font:(UIFont *)font maxSize:(CGSize)maxSize
{
NSDictionary *dict=@{NSFontAttributeName: font};
CGSize  nasize=[str boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:dict context:nil].size;
return nasize;
}

@end


最终实现效果图如下:



以上方法,即是利用代码进行对UITableViewCell进行的重写,下一讲讲解关于

利用xib创建重用的单元格对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐