ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局

简介:

一、实现效果

二、使用纯代码自定义一个tableview的步骤

1.新建一个继承自UITableViewCell的类

2.重写initWithStyle:reuseIdentifier:方法

添加所有需要显示的子控件(不需要设置子控件的数据和frame, 子控件要添加到contentView中)

进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体\固定的图片)

3.提供2个模型

数据模型: 存放文字数据\图片数据

frame模型: 存放数据模型\所有子控件的frame\cell的高度

4.cell拥有一个frame模型(不要直接拥有数据模型)

5.重写frame模型属性的setter方法: 在这个方法中设置子控件的显示数据和frame

6.frame模型数据的初始化已经采取懒加载的方式(每一个cell对应的frame模型数据只加载一次)

三、文件结构和实现代码

1.文件结构

2.实现代码:

NJWeibo.h文件

复制代码
 1 #import <Foundation/Foundation.h>
 2  3 @interface NJWeibo : NSObject
 4 @property (nonatomic, copy) NSString *text; // 内容  5 @property (nonatomic, copy) NSString *icon; // 头像  6 @property (nonatomic, copy) NSString *name; // 昵称  7 @property (nonatomic, copy) NSString *picture; // 配图  8 @property (nonatomic, assign) BOOL vip;
 9 10 - (id)initWithDict:(NSDictionary *)dict;
11 + (id)weiboWithDict:(NSDictionary *)dict;
12 @end
复制代码

NJWeibo.m文件

复制代码
 1 #import "NJWeibo.h"  2  3 @implementation NJWeibo
 4  5 - (id)initWithDict:(NSDictionary *)dict
 6 {
 7 if (self = [super init]) {
 8  [self setValuesForKeysWithDictionary:dict];
 9  }
10 return self;
11 }
12 13 + (id)weiboWithDict:(NSDictionary *)dict
14 {
15 return [[self alloc] initWithDict:dict];
16 }
17 18 @end
复制代码

NJWeiboCell.h文件

复制代码
 1 #import <UIKit/UIKit.h>
 2 @class NJWeiboFrame;
 3  4 @interface NJWeiboCell : UITableViewCell
 5 /**
 6  * 接收外界传入的模型
 7 */  8 //@property (nonatomic, strong) NJWeibo *weibo;  9 10 @property (nonatomic, strong) NJWeiboFrame *weiboFrame;
11 12 + (instancetype)cellWithTableView:(UITableView *)tableView;
13 @end
复制代码

NJWeiboCell.m文件

复制代码
 1 #import "NJWeiboCell.h"  2 #import "NJWeibo.h"  3 #import "NJWeiboFrame.h"  4  5 #define NJNameFont [UIFont systemFontOfSize:15]
 6 #define NJTextFont [UIFont systemFontOfSize:16]
 7  8 @interface NJWeiboCell ()
 9 /**
 10  * 头像
 11 */  12 @property (nonatomic, weak) UIImageView *iconView;
 13 /**
 14  * vip
 15 */  16 @property (nonatomic, weak) UIImageView *vipView;
 17 /**
 18  * 配图
 19 */  20 @property (nonatomic, weak) UIImageView *pictureView;
 21 /**
 22  * 昵称
 23 */  24 @property (nonatomic, weak) UILabel *nameLabel;
 25 /**
 26  * 正文
 27 */  28 @property (nonatomic, weak) UILabel *introLabel;
 29 @end  30  31 @implementation NJWeiboCell
 32  33 + (instancetype)cellWithTableView:(UITableView *)tableView
 34 {
 35 // NSLog(@"cellForRowAtIndexPath");  36 static NSString *identifier = @"status";
 37 // 1.缓存中取  38 NJWeiboCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
 39 // 2.创建  40 if (cell == nil) {
 41 cell = [[NJWeiboCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
 42  }
 43 return cell;
 44 }
 45  46  47 /**
 48  * 构造方法(在初始化对象的时候会调用)
 49  * 一般在这个方法中添加需要显示的子控件
 50 */  51 - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
 52 {
 53 self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
 54 if (self) {
 55 // 让自定义Cell和系统的cell一样, 一创建出来就拥有一些子控件提供给我们使用
 56 // 1.创建头像  57 UIImageView *iconView = [[UIImageView alloc] init];
 58  [self.contentView addSubview:iconView];
 59 self.iconView = iconView;
 60  61 // 2.创建昵称  62 UILabel *nameLabel = [[UILabel alloc] init];
 63 nameLabel.font = NJNameFont;
 64 // nameLabel.backgroundColor = [UIColor redColor];  65  [self.contentView addSubview:nameLabel];
 66 self.nameLabel = nameLabel;
 67  68 // 3.创建vip  69 UIImageView *vipView = [[UIImageView alloc] init];
 70 vipView.image = [UIImage imageNamed:@"vip"];
 71  [self.contentView addSubview:vipView];
 72 self.vipView = vipView;
 73  74 // 4.创建正文  75 UILabel *introLabel = [[UILabel alloc] init];
 76 introLabel.font = NJTextFont;
 77 introLabel.numberOfLines = 0;
 78 // introLabel.backgroundColor = [UIColor greenColor];  79  [self.contentView addSubview:introLabel];
 80 self.introLabel = introLabel;
 81  82 // 5.创建配图  83 UIImageView *pictureView = [[UIImageView alloc] init];
 84  [self.contentView addSubview:pictureView];
 85 self.pictureView = pictureView;
 86  87  }
 88 return self;
 89 }
 90  91  92 - (void)setWeiboFrame:(NJWeiboFrame *)weiboFrame
 93 {
 94 _weiboFrame = weiboFrame;
 95  96 // 1.给子控件赋值数据  97  [self settingData];
 98 // 2.设置frame  99  [self settingFrame];
100 }
101 102 103 /**
104  * 设置子控件的数据
105 */ 106 - (void)settingData
107 {
108 NJWeibo *weibo = self.weiboFrame.weibo;
109 110 // 设置头像 111 self.iconView.image = [UIImage imageNamed:weibo.icon];
112 // 设置昵称 113 self.nameLabel.text = weibo.name;
114 // 设置vip 115 if (weibo.vip) {
116 self.vipView.hidden = NO;
117 self.nameLabel.textColor = [UIColor redColor];
118 }else 119  {
120 self.vipView.hidden = YES;
121 self.nameLabel.textColor = [UIColor blackColor];
122  }
123 // 设置内容 124 self.introLabel.text = weibo.text;
125 126 // 设置配图 127 if (weibo.picture) {// 有配图 128 self.pictureView.image = [UIImage imageNamed:weibo.picture];
129 self.pictureView.hidden = NO;
130 }else 131  {
132 self.pictureView.hidden = YES;
133  }
134 }
135 /**
136  * 设置子控件的frame
137 */ 138 - (void)settingFrame
139 {
140 141 // 设置头像的frame 142 self.iconView.frame = self.weiboFrame.iconF;
143 144 // 设置昵称的frame 145 self.nameLabel.frame = self.weiboFrame.nameF;
146 147 // 设置vip的frame 148 self.vipView.frame = self.weiboFrame.vipF;
149 150 // 设置正文的frame 151 self.introLabel.frame = self.weiboFrame.introF;
152 153 // 设置配图的frame 154 155 if (self.weiboFrame.weibo.picture) {// 有配图 156 self.pictureView.frame = self.weiboFrame.pictrueF;
157  }
158 }
159 160 /**
161  * 计算文本的宽高
162  *
163  * @param str 需要计算的文本
164  * @param font 文本显示的字体
165  * @param maxSize 文本显示的范围
166  *
167  * @return 文本占用的真实宽高
168 */ 169 - (CGSize)sizeWithString:(NSString *)str font:(UIFont *)font maxSize:(CGSize)maxSize
170 {
171 NSDictionary *dict = @{NSFontAttributeName : font};
172 // 如果将来计算的文字的范围超出了指定的范围,返回的就是指定的范围
173 // 如果将来计算的文字的范围小于指定的范围, 返回的就是真实的范围 174 CGSize size = [str boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:dict context:nil].size;
175 return size;
176 }
177 178 @end
复制代码

NJWeiboFrame.h文件

复制代码
 1 // 专门用来保存每一行数据的frame, 计算frame  2  3 #import <Foundation/Foundation.h>
 4 @class NJWeibo;
 5 @interface NJWeiboFrame : NSObject
 6 /**
 7  * 头像的frame
 8 */  9 @property (nonatomic, assign) CGRect iconF;
10 /**
11  * 昵称的frame
12 */ 13 @property (nonatomic, assign) CGRect nameF;
14 /**
15  * vip的frame
16 */ 17 @property (nonatomic, assign) CGRect vipF;
18 /**
19  * 正文的frame
20 */ 21 @property (nonatomic, assign) CGRect introF;
22 /**
23  * 配图的frame
24 */ 25 @property (nonatomic, assign) CGRect pictrueF;
26 /**
27  * 行高
28 */ 29 @property (nonatomic, assign) CGFloat cellHeight;
30 31 /**
32  * 模型数据
33 */ 34 @property (nonatomic, strong) NJWeibo *weibo;
35 @end
复制代码

NJWeiboFrame.m文件

复制代码
 1 #import "NJWeiboFrame.h"  2 #import "NJWeibo.h"  3 #define NJNameFont [UIFont systemFontOfSize:15]
 4 #define NJTextFont [UIFont systemFontOfSize:16]
 5  6  7 @implementation NJWeiboFrame
 8  9 10 - (void)setWeibo:(NJWeibo *)weibo
11 {
12 _weibo = weibo;
13 14 // 间隙 15 CGFloat padding = 10;
16 17 // 设置头像的frame 18 CGFloat iconViewX = padding;
19 CGFloat iconViewY = padding;
20 CGFloat iconViewW = 30;
21 CGFloat iconViewH = 30;
22 self.iconF = CGRectMake(iconViewX, iconViewY, iconViewW, iconViewH);
23 24 // 设置昵称的frame
25 // 昵称的x = 头像最大的x + 间隙 26 CGFloat nameLabelX = CGRectGetMaxX(self.iconF) + padding;
27 // 计算文字的宽高 28 CGSize nameSize = [self sizeWithString:_weibo.name font:NJNameFont maxSize:CGSizeMake(MAXFLOAT, MAXFLOAT)];
29 30 CGFloat nameLabelH = nameSize.height;
31 CGFloat nameLabelW = nameSize.width;
32 CGFloat nameLabelY = iconViewY + (iconViewH - nameLabelH) * 0.5;
33 self.nameF = CGRectMake(nameLabelX, nameLabelY, nameLabelW, nameLabelH);
34 35 // 设置vip的frame 36 CGFloat vipViewX = CGRectGetMaxX(self.nameF) + padding;
37 CGFloat vipViewY = nameLabelY;
38 CGFloat vipViewW = 14;
39 CGFloat vipViewH = 14;
40 self.vipF = CGRectMake(vipViewX, vipViewY, vipViewW, vipViewH);
41 42 // 设置正文的frame 43 CGFloat introLabelX = iconViewX;
44 CGFloat introLabelY = CGRectGetMaxY(self.iconF) + padding;
45 CGSize textSize = [self sizeWithString:_weibo.text font:NJTextFont maxSize:CGSizeMake(300, MAXFLOAT)];
46 47 CGFloat introLabelW = textSize.width;
48 CGFloat introLabelH = textSize.height;
49 50 self.introF = CGRectMake(introLabelX, introLabelY, introLabelW, introLabelH);
51 52 // 设置配图的frame 53 CGFloat cellHeight = 0;
54 if (_weibo.picture) {// 有配图 55 CGFloat pictureViewX = iconViewX;
56 CGFloat pictureViewY = CGRectGetMaxY(self.introF) + padding;
57 CGFloat pictureViewW = 100;
58 CGFloat pictureViewH = 100;
59 self.pictrueF = CGRectMake(pictureViewX, pictureViewY, pictureViewW, pictureViewH);
60 61 // 计算行高 62 self.cellHeight = CGRectGetMaxY(self.pictrueF) + padding;
63 }else 64  {
65 // 没有配图情况下的行高 66 self.cellHeight = CGRectGetMaxY(self.introF) + padding;
67  }
68 69 }
70 71 /**
72  * 计算文本的宽高
73  *
74  * @param str 需要计算的文本
75  * @param font 文本显示的字体
76  * @param maxSize 文本显示的范围
77  *
78  * @return 文本占用的真实宽高
79 */ 80 - (CGSize)sizeWithString:(NSString *)str font:(UIFont *)font maxSize:(CGSize)maxSize
81 {
82 NSDictionary *dict = @{NSFontAttributeName : font};
83 // 如果将来计算的文字的范围超出了指定的范围,返回的就是指定的范围
84 // 如果将来计算的文字的范围小于指定的范围, 返回的就是真实的范围 85 CGSize size = [str boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:dict context:nil].size;
86 return size;
87 }
88 @end
复制代码

主控制器

NJViewController.m文件

复制代码
 1 #import "NJViewController.h"  2 #import "NJWeibo.h"  3 #import "NJWeiboCell.h"  4 #import "NJWeiboFrame.h"  5  6 @interface NJViewController ()
 7 @property (nonatomic, strong) NSArray *statusFrames;
 8 @end  9 10 @implementation NJViewController
11 12 #pragma mark - 数据源方法
13 14 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
15 {
16 return self.statusFrames.count;
17 }
18 19 20 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
21 {
22 NJWeiboCell *cell = [NJWeiboCell cellWithTableView:tableView];
23 // 3.设置数据 24 cell.weiboFrame = self.statusFrames[indexPath.row];
25 26 // 4.返回 27 return cell;
28 }
29 #pragma mark - 懒加载
30 - (NSArray *)statusFrames
31 {
32 if (_statusFrames == nil) {
33 NSString *fullPath = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil];
34 NSArray *dictArray = [NSArray arrayWithContentsOfFile:fullPath];
35 NSMutableArray *models = [NSMutableArray arrayWithCapacity:dictArray.count];
36 for (NSDictionary *dict in dictArray) {
37 // 创建模型 38 NJWeibo *weibo = [NJWeibo weiboWithDict:dict];
39 // 根据模型数据创建frame模型 40 NJWeiboFrame *wbF = [[NJWeiboFrame alloc] init];
41 wbF.weibo = weibo;
42 43  [models addObject:wbF];
44  }
45 self.statusFrames = [models copy];
46  }
47 return _statusFrames;
48 }
49 50 #pragma mark - 代理方法
51 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
52 {
53 // NSLog(@"heightForRowAtIndexPath");
54 // 取出对应航的frame模型 55 NJWeiboFrame *wbF = self.statusFrames[indexPath.row];
56 NSLog(@"height = %f", wbF.cellHeight);
57 return wbF.cellHeight;
58 }
59 60 - (BOOL) prefersStatusBarHidden
61 {
62 return YES;
63 }
64 @end
复制代码

四、补充说明

由于系统提供的tableview可能并不能满足我们的开发需求,所以经常要求我们能够自定义tableview。

自定义tableview有两种方式,一种是使用xib创建,一种是使用纯代码的方式创建。

对于样式一样的tableview,通常使用xib进行创建,对于高度不一样,内容也不完全一致的通常使用纯代码进行自定义。

目录
相关文章
|
4天前
|
前端开发 编解码 数据格式
浅谈响应式编程在企业级前端应用 UI 开发中的实践
浅谈响应式编程在企业级前端应用 UI 开发中的实践
26 0
浅谈响应式编程在企业级前端应用 UI 开发中的实践
|
7月前
|
设计模式 测试技术 vr&ar
提升你的Android开发技能:从AR/VR沉浸到UI设计和故障排除(三)
提升你的Android开发技能:从AR/VR沉浸到UI设计和故障排除
|
4天前
|
iOS开发 UED
实现一个自定义的iOS动画效果
【4月更文挑战第9天】本文将详细介绍如何在iOS平台上实现一个自定义的动画效果。我们将通过使用Core Animation框架来实现这个动画效果,并展示如何在不同的场景中使用它。文章的目标是帮助读者理解如何使用Core Animation框架来创建自定义动画,并提供一个简单的示例代码。
19 1
|
3天前
|
Android开发 缓存 双11
android的基础ui组件,Android开发社招面试经验
android的基础ui组件,Android开发社招面试经验
android的基础ui组件,Android开发社招面试经验
|
4天前
UI开发第四篇——实现像handcent sms或者chomp sms那样的气泡
UI开发第四篇——实现像handcent sms或者chomp sms那样的气泡
|
4天前
|
前端开发 测试技术 持续交付
【Flutter 前端技术开发专栏】Flutter 中的 UI 测试与自动化测试
【4月更文挑战第30天】本文探讨了 Flutter 应用中UI测试和自动化测试的重要性,包括保障质量、提高效率和增强开发信心。Flutter提供`flutter_test`库进行Widget测试,以及`flutter_driver`进行集成测试。UI测试涵盖界面布局、交互和状态变化的验证,最佳实践建议尽早引入测试、保持用例简洁,并结合手动测试。未来,随着Flutter技术发展,UI测试和自动化测试将更加完善,助力开发高质量应用。
【Flutter 前端技术开发专栏】Flutter 中的 UI 测试与自动化测试
|
4天前
|
前端开发 搜索推荐 UED
【Flutter前端技术开发专栏】Flutter中的高级UI组件应用
【4月更文挑战第30天】探索Flutter的高级UI组件,如`TabBar`、`Drawer`、`BottomSheet`,提升应用体验和美观度。使用高级组件能节省开发时间,提供内置交互逻辑和优秀视觉效果。示例代码展示了如何实现底部导航栏、侧边导航和底部弹出菜单。同时,自定义组件允许个性化设计和功能扩展,但也带来性能优化和维护挑战。参考Flutter官方文档和教程,深入学习并有效利用这些组件。
【Flutter前端技术开发专栏】Flutter中的高级UI组件应用
|
4天前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。
|
4天前
element-ui中Form表单使用自定义验证规则
element-ui中Form表单使用自定义验证规则
12 0
QGS
|
4天前
|
前端开发 数据可视化 Java
手拉手JavaFX UI控件与springboot3+FX桌面开发(下)
手拉手JavaFX UI控件与springboot3+FX桌面开发
QGS
87 0