文档章节

iOS中的UITableView自定义Cell(模仿新浪微博)

D
 Dumplings
发布于 2016/05/23 17:49
字数 1773
阅读 139
收藏 0
点赞 2
评论 0

 

 

定义一个KCStatusTableViewCell实现UITableViewCell,一般实现自定义UITableViewCell需要分为两步:第一初始化控件;第二设置数据,重新设置控件frame。原因就是自定义Cell一般无法固定高度,很多时候高度需要随着内容改变。此外由于在单元格内部是无法控制单元格高度的,因此一般会定义一个高度属性用于在UITableView的代理事件中设置每个单元格高度。

首先看一下微博模型KCStatus,这个模型主要的方法就是根据plist字典内容生成微博对象:

KCStatus.h

#import <Foundation/Foundation.h>

//微博模型KCStatus,这个模型主要的方法就是根据plist字典内容生成微博对象:

@interface KCStatus : NSObject

#pragma mark - 属性
@property (nonatomic,assign) long long Id;//微博ID
@property (nonatomic,copy) NSString *profileImageUrl;//用户头像
@property (nonatomic,copy) NSString *userName;//用户名称
@property (nonatomic,copy) NSString *mbtype;//会员类型
@property (nonatomic,copy) NSString *createdAt;//创建时间
@property (nonatomic,copy) NSString *source;//设备来源
@property (nonatomic,copy) NSString *text;//微博内容

#pragma mark - 方法
#pragma mark 根据字典初始化微博对象
-(KCStatus *)initWithDictionary:(NSDictionary *)dic;

#pragma mark 初始化微博对象(静态方法)
+(KCStatus *)statusWithDictionary:(NSDictionary *)dic;

@end

 

 

KCStatus.m

#import "KCStatus.h"

@implementation KCStatus

#pragma mark 根据字典初始化微博对象
-(KCStatus *)initWithDictionary:(NSDictionary *)dic{
    
    if (self = [super init]) {
        
        self.Id = [dic[@"id"] longLongValue];
        self.profileImageUrl = dic[@"profileImageUrl"];
        self.userName = dic[@"userName"];
        self.mbtype = dic[@"mbtype"];
        self.createdAt = dic[@"createdAt"];
        self.source = dic[@"source"];
        self.text = dic[@"text"];
        
    }
    
    return self;

}


#pragma mark 初始化微博对象(静态方法)
+(KCStatus *)statusWithDictionary:(NSDictionary *)dic{
    
    KCStatus *status = [[KCStatus alloc]initWithDictionary:dic];
    
    return status;
}


//使用 stringWithFormat 拼接设备来源
-(NSString *)source{
    return [NSString stringWithFormat:@"来自 %@", _source];
}


@end

 

 

然后看一下自定义的Cell

KCStatusTableViewCell.h

#import <UIKit/UIKit.h>
//#import "KCStatus.h"

// import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你。
@class KCStatus;


//自定义的cell
@interface KCStatusTableViewCell : UITableViewCell

#pragma mark 微博对象
@property (nonatomic, strong) KCStatus *status;

#pragma mark 单元格高度
@property (assign, nonatomic) CGFloat height;


@end

 

KCStatusTableViewCell.m

#import "KCStatusTableViewCell.h"
#import "KCStatus.h"

#define KCColor(r,g,b) [UIColor colorWithHue:r/255.0 saturation:g/255.0 brightness:b/255.0 alpha:1] //颜色宏定义
#define kStatusTableViewCellControlSpacing 10 //控件间距
#define kStatusTableViewCellBackgroundColor KCColor(251,251,251)
#define kStatusGrayColor KCColor(50,50,50)
#define kStatusLightGrayColor KCColor(120,120,120)

#define kStatusTableViewCellAvatarWidth 40 //头像宽度
#define kStatusTableViewCellAvatarHeight kStatusTableViewCellAvatarWidth
#define kStatusTableViewCellUserNameFontSize 14
#define kStatusTableViewCellMbTypeWidth 13 //会员图标宽度
#define kStatusTableViewCellMbTypeHeight kStatusTableViewCellMbTypeWidth
#define kStatusTableViewCellCreateAtFontSize 12
#define kStatusTableViewCellSourceFontSize 12
#define kStatusTableViewCellTextFontSize 14



@interface KCStatusTableViewCell(){
    
    UIImageView *cellAvatar;//用户头像
    UIImageView *cellMbType;//会员类型
    UILabel *cellUserName;//用户名称
    UILabel *cellCreateAt;//创建时间
    UILabel *cellSource;//设备来源
    UILabel *cellText;//微博内容

}

@end

@implementation KCStatusTableViewCell


-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self initSubView];
    }
    
    return self;

}


#pragma mark 初始化视图
-(void)initSubView{
    
    
    //头像控件
    cellAvatar = [[UIImageView alloc]init];
    [self.contentView addSubview:cellAvatar];
    
    //用户名
    cellUserName = [[UILabel alloc]init];
    cellUserName.textColor = kStatusGrayColor;
    cellUserName.font = [UIFont systemFontOfSize:kStatusTableViewCellUserNameFontSize];
    [self.contentView addSubview:cellUserName];
    
    //会员类型
    cellMbType = [[UIImageView alloc]init];
    [self.contentView addSubview:cellMbType];
    
    //日期
    cellCreateAt = [[UILabel alloc]init];
    cellCreateAt.textColor = kStatusLightGrayColor;
    cellCreateAt.font = [UIFont systemFontOfSize:kStatusTableViewCellCreateAtFontSize];
    [self.contentView addSubview:cellCreateAt];
    
    //设备
    cellSource = [[UILabel alloc]init];
    cellSource.textColor = kStatusLightGrayColor;
    cellSource.font = [UIFont systemFontOfSize:kStatusTableViewCellSourceFontSize];
    [self.contentView addSubview:cellSource];
    
    //内容
    cellText = [[UILabel alloc]init];
    cellText.textColor = kStatusGrayColor;
    cellText.font = [UIFont systemFontOfSize:kStatusTableViewCellTextFontSize];
    cellText.numberOfLines=0;
    //    cellText.lineBreakMode=NSLineBreakByWordWrapping;
    [self.contentView addSubview:cellText];

}


#pragma mark 设置微博
-(void)setStatus:(KCStatus *)status{
    
    //设置头像大小和位置
    CGFloat avatarX=10,avatarY=10;
    CGRect avatarRect=CGRectMake(avatarX, avatarY, kStatusTableViewCellAvatarWidth, kStatusTableViewCellAvatarHeight);
    cellAvatar.image=[UIImage imageNamed:status.profileImageUrl];
    cellAvatar.frame=avatarRect;
    
    
    //设置会员图标大小和位置
    CGFloat userNameX= CGRectGetMaxX(cellAvatar.frame)+kStatusTableViewCellControlSpacing ;
    CGFloat userNameY=avatarY;
    //根据文本内容取得文本占用空间大小
    CGSize userNameSize=[status.userName sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kStatusTableViewCellUserNameFontSize]}];
    CGRect userNameRect=CGRectMake(userNameX, userNameY, userNameSize.width,userNameSize.height);
    cellUserName.text=status.userName;
    cellUserName.frame=userNameRect;
    
    
    //设置会员图标大小和位置
    CGFloat mbTypeX=CGRectGetMaxX(cellUserName.frame)+kStatusTableViewCellControlSpacing;
    CGFloat mbTypeY=avatarY;
    CGRect mbTypeRect=CGRectMake(mbTypeX, mbTypeY, kStatusTableViewCellMbTypeWidth, kStatusTableViewCellMbTypeHeight);
    cellMbType.image=[UIImage imageNamed:status.mbtype];
    cellMbType.frame=mbTypeRect;
    
    
    //设置发布日期大小和位置
    CGSize createAtSize=[status.createdAt sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kStatusTableViewCellCreateAtFontSize]}];
    CGFloat createAtX=userNameX;
    CGFloat createAtY=CGRectGetMaxY(cellAvatar.frame)-createAtSize.height;
    CGRect createAtRect=CGRectMake(createAtX, createAtY, createAtSize.width, createAtSize.height);
    cellCreateAt.text=status.createdAt;
    cellCreateAt.frame=createAtRect;
    
    
    //设置设备信息大小和位置
    CGSize sourceSize=[status.source sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kStatusTableViewCellSourceFontSize]}];
    CGFloat sourceX=CGRectGetMaxX(cellCreateAt.frame)+kStatusTableViewCellControlSpacing;
    CGFloat sourceY=createAtY;
    CGRect sourceRect=CGRectMake(sourceX, sourceY, sourceSize.width,sourceSize.height);
    cellSource.text=status.source;
    cellSource.frame=sourceRect;
    
    
    //设置微博内容大小和位置
    CGFloat textX=avatarX;
    CGFloat textY=CGRectGetMaxY(cellAvatar.frame)+kStatusTableViewCellControlSpacing;
    CGFloat textWidth=self.frame.size.width-kStatusTableViewCellControlSpacing*2;
    CGSize textSize=[status.text boundingRectWithSize:CGSizeMake(textWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kStatusTableViewCellTextFontSize]} context:nil].size;
    CGRect textRect=CGRectMake(textX, textY, textSize.width, textSize.height);
    cellText.text=status.text;
    cellText.frame=textRect;
    
    _height=CGRectGetMaxY(cellText.frame)+kStatusTableViewCellControlSpacing;

    
}






- (void)awakeFromNib {
    // Initialization code
}



#pragma mark 重写选择事件,取消选中
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

@end

这是我们自定义Cell这个例子的核心,自定义Cell分为两个步骤:首先要进行各种控件的初始化工作,这个过程中只要将控件放到Cell的View中同时设置控件显示内容的格式(字体大小、颜色等)即可;然后在数据对象设置方法中进行各个控件的布局(大小、位置)。在代码中有几点需要重点提示大家:

  • 对于单行文本数据的显示调用- (CGSize)sizeWithAttributes:(NSDictionary *)attrs;方法来得到文本宽度和高度。 
  • 对于多行文本数据的显示调用- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context ;方法来得到文本宽度和高度;同时注意在此之前需要设置文本控件的numberOfLines属性为0。 
  • 通常我们会在自定义Cell中设置一个高度属性,用于外界方法调用,因为Cell内部设置Cell的高度是没有用的,UITableViewCell在初始化时会重新设置高度。

 

 

最后我们看一下自定义Cell的使用过程:

KCStatusViewController.h

#import <UIKit/UIKit.h>

@interface KCStatusViewController : UIViewController

@end

 

KCStatusViewController.m

#import "KCStatusViewController.h"
#import "KCStatus.h"
#import "KCStatusTableViewCell.h"



@interface KCStatusViewController ()<UITableViewDelegate,UITableViewDataSource,UIAlertViewDelegate>{
    
    UITableView *myTableView;
    NSMutableArray *statusArray;
    NSMutableArray *statusCellsArray;//存储cell,用于计算高度
 
}

@end

@implementation KCStatusViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    

    //初始化数据
    [self initData];
    
    //创建一个分组样式的UITableView
    myTableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
    
    //设置数据源,注意实现UITableViewDataSource协议
    myTableView.dataSource = self;
    //设置代理
    myTableView.delegate = self;

    [self.view addSubview:myTableView];
    
    
}


#pragma mark 加载数据
-(void)initData{
    
    NSString *path = [[NSBundle mainBundle] pathForResource:@"StatusInfo" ofType:@"plist"];
    NSArray *array = [NSArray arrayWithContentsOfFile:path];
    
    statusArray = [[NSMutableArray alloc]init];
    statusCellsArray = [[NSMutableArray alloc]init];
    
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        [statusArray addObject:[KCStatus statusWithDictionary:obj]];
        KCStatusTableViewCell *cell = [[KCStatusTableViewCell alloc]init];
        [statusCellsArray addObject:cell];
    
    }];
  
}


#pragma mark - 数据源方法

#pragma mark 返回分组数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    
    return 1;
}


#pragma mark 返回每组行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    
    return statusArray.count;

}

#pragma mark 返回每行的单元格(cell上面展示的内容)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    static NSString *cellIdentifier = @"UITableViewCellIdentifierKey1";
    KCStatusTableViewCell *cell;
    cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    
    if (!cell) {
        
        cell = [[KCStatusTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];

    }
    
    
    
    /**
     *  这个类中需要重点强调一下:Cell的高度需要重新设置(前面说过无论Cell内部设置多高都没有用,需要重新设置),这里采用的方法是首先创建对应的Cell,然后在- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;方法中设置微博数据计算高度通知UITableView。
     */
    
    
    //在此设置微博,以便重新布局
    KCStatus *status = statusArray[indexPath.row];
    cell.status = status;
    return cell;
    
}


#pragma mark - 代理方法

#pragma mark 重新设置单元格高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    
//    KCStatusTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    KCStatusTableViewCell *cell = statusCellsArray[indexPath.row];
    cell.status = statusArray[indexPath.row];
    
    
    return cell.height;
  
}


#pragma mark 重写状态样式方法
-(UIStatusBarStyle)preferredStatusBarStyle{
    
    return UIStatusBarStyleLightContent;
    
}






- (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

 

 

大神地址:http://www.cnblogs.com/kenshincui/

© 著作权归作者所有

共有 人打赏支持
D
粉丝 0
博文 68
码字总数 36665
作品 0
西安
程序员
iOS开发笔记(八)---- 键盘、静态库、动画、Crash定位

前言 分享开发中遇到的问题,和相关的一些思考。 iOS11键盘问题 功能背景: 弹出键盘时,如果有输入框的话,需要输入框的位置跟随键盘大小而变动。 问题描述: 当快速切换键盘之后,容易出现...

落影loyinglin ⋅ 04/28 ⋅ 0

一个多UITableview的左右滑动简单解决方案

前言 本文源自实际开发中的需求,核心的要求有几个: 1、多个UITableview要支持左右滑动; 2、点击Tab也要有UITableview的滑动切换效果; 3、每个UITableview单独的下拉刷新和上拉加载; 效果...

落影loyinglin ⋅ 04/22 ⋅ 0

iOS逆向实战(微信自动抢红包下)

在前两篇文章中,我们详细介绍了如何反汇编、创建Tweak项目实现自动抢红包功能的思路。今天我们继续下篇,主要说两个事:添加一个开关控制自动抢红包,打包重签名安装到非越狱手机上。 添加抢...

LvesLi ⋅ 04/18 ⋅ 0

iOS UITableView获取特定位置的cell

一、tableView双级联动 以上两种效果比较类似,实现的关键在于都是需要获得在滑动过程中滑动到tableView顶部的cell的indexPath。 方案一:获得当前可见的所有cell,然后取可见cell数组中的第...

且行且珍惜_iOS ⋅ 05/23 ⋅ 0

Table View Programming Guide for iOS 官方文档翻译

About Table Views in iOS Apps( iOS应用程序中的Table View) Table views are versatile user interface objects frequently found in iOS apps. A table view presents data in a scrol......

zyq522376829 ⋅ 05/03 ⋅ 0

高性能聊天页面解决方案 - CDChatList

CDChatList 高性能的聊天页面解决方案 对聊天列表的高度封装,可灵活配置页面样式 聊天界面其实大同小异,所以这里封装了一个聊天的组件,使用CoreText和手动代码布局,尽量实现简单,通用,...

chdo002 ⋅ 04/26 ⋅ 0

2018 年过去了一半,iOS 工程师如何自我提高。上篇

如果从 13 年移动客户端大火开始算起,至今已经有五个年头了。现在移动端的形势也不需要太多的废话来描述,一句话总结就是:“浪潮退去,谁在裸泳一看就清楚。”我希望借助这篇文章来聊聊在我...

浪漫程序员 ⋅ 05/22 ⋅ 0

iOS打造属于自己的用户行为统计系统

打造一款符合自己公司需求的用户行为统计系统,相信是很多运营人员的梦想,也是开发人员对技术的的执着追求。下面我为大家分一享下自己为公司打造的用户行为统计系统。   用户行为统计(Us...

贝勒老爷 ⋅ 04/20 ⋅ 0

UITableView方法的执行顺序流畅性优化

(一)、UITableView的执行顺序 numberOfSectionsInTableView(确定有几组) -> numberOfRowsInSection(确定每组有多少的行) -> heightForRowAtIndexPath(确定每行cell的高度) 以上信息确定完毕...

朝雨晚风 ⋅ 2017/10/23 ⋅ 0

一样的iOS开发程序员为什么有人4k有人40k?

前言 移动开发真正火起来其实就是最近这几年,iOS 开发技术因为发展也就才这么几年,所以值得做的事情还有很多,这就造成了每年苹果的 WWDC 都会推出一堆新的特性和 API。整体上来说,这对业...

原来是泽镜啊 ⋅ 05/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

内核线程、轻量级进程、用户线程

线程与进程概念 在现代操作系统中,进程支持多线程。 进程是资源管理的最小单元; 线程是程序执行的最小单元。 即线程作为调度和分配的基本单位,进程作为资源分配的基本单位 一个进程的组成...

117 ⋅ 32分钟前 ⋅ 0

elasticsearch2.4.6升级为elasticsearch-5.5.0的经历

将elasticsearch-5.5.0 中的配置 path.data 指向原来的数据路径 即 path.data: /usr/local/src/elasticsearch-2.4.6/data 注意: elasticsearch-5.5.0 需要将jdk版本升级到1.8...

晨猫 ⋅ 32分钟前 ⋅ 1

lvm讲解 磁盘故障小案例

1

oschina130111 ⋅ 36分钟前 ⋅ 0

那些提升开发人员工作效率的在线工具

本文转载自公众号 Hollis 作为一个Java开发人员,经常要和各种各样的工具打交道,除了我们常用的IDE工具以外,其实还有很多工具是我们在日常开发及学习过程中要经常使用到的。 Hollis偏爱使用...

时刻在奔跑 ⋅ 49分钟前 ⋅ 0

restful风格 实现DELETE PUT请求 的web.xml的配置

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframe......

泉天下 ⋅ 54分钟前 ⋅ 0

Shell数组

Shell数组 Shell在编程方面比Windows批处理强大很多,无论是在循环、运算。 bash支持一维数组(不支持多维数组),并且没有限定数组的大小。类似与C语言,数组元素的下标由0开始编号。获取数...

蜗牛奔跑 ⋅ 今天 ⋅ 0

nmap为了开发方便 可以做简单的修改

因为nmap扫描是默认使用的是nse脚本,但是在开发的过程中需要修改后缀(主要是因为后缀为lua才能显示高亮,所以这里用一个取巧的办法) nse_main.lua文件中我们找到如下代码 local t, path = cn...

超级大黑猫 ⋅ 今天 ⋅ 0

springmvc获取axios数据为null情况

场景:前端用了vue没有用ajax与后台通信,用了axios,但是在代码运行过程中发现axios传递到后台的值接受到数据为null。 问题原因:此处的问题在与axios返回给后台的数据为json类型的,后台接...

王子城 ⋅ 今天 ⋅ 0

hadoop技术入门学习之发行版选择

经常会看到这样的问题:零基础学习hadoop难不难?有的人回答说:零基础学习hadoop,没有想象的那么难,也没有想象的那么容易。看到这样的答案不免觉得有些尴尬,这个问题算是白问了,因为这个...

左手的倒影 ⋅ 今天 ⋅ 0

806. Number of Lines To Write String - LeetCode

Question 806. Number of Lines To Write String Solution 思路:注意一点,如果a长度为4,当前行已经用了98个单元,要另起一行。 Java实现: public int[] numberOfLines(int[] widths, Str...

yysue ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部