IOS-自定义cell与控件布局
2015-10-23 21:03
861 查看
需要解决的问题:
1. 根据文字判断CGsize.
2. 根据最后一个控件的高度判断cell的高度.
3. 对整体模块化实现.
==============================
关于尺寸问题,补充下. 控件的位置描述是一个frame控制的,它包含两个结构体, 一个origin控制水平位置和垂直位置; 一个size控制宽度,和高度;
当我们计算文字的CGsize时候, 就是计算文字的宽度, 高度.
他们都是结构体,但是我们一般 不直接使用结构的语法进行赋值, 而是使用已有的方法, 比如对frame赋值使用CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height);
对CGsize赋值使用CGSizeMake(w, h);
计算文字的CGsize方法
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context
===============================
当我们做一个tableView的时候, 只需要按照步骤走即可.
1. tableView的组数,默认是1.
2.tableView分组中的行数(cell).
3.每一个cell的具体显示, 包括内容和位置两部分
4.一些附加的控制属性, 行高, 响应事件等等....
我们只要按照这个思路去完成就可以了...
================================================
关于数据模型方面, 以前我们使用的是xib直接布局的,不存在太多的布局.这次我们没有使用xib, 每一个cell都需要我们布局, 我们可以把cell所需要的信息放到一个类中.
这个类包括cell的内容信息和frame信息.
其他关于数据转模型的就不细说了 ,但是要说一点,这次模拟放到内存中的数组就不仅仅是数据了,还需要frame,所以应该是一个描述cell类的类型数组.
====================================
类封装:
cell内容类
@interface AMMicroBlog : NSObject @property (nonatomic, copy) NSString * text; @property (nonatomic, copy) NSString * icon; @property (nonatomic, copy) NSString * name; @property (nonatomic, copy) NSString * picture; @property (nonatomic, assign, getter = isVip) BOOL vip; - (instancetype) initWithDic : (NSDictionary *) dic; + (instancetype) microBlogWithDic : (NSDictionary *) dic; + (NSArray *) microBlogsList; @end
cell的frame类(包含一个AMMicroBlog对象)
这个类就可以完整的描述cell所需要的所有信息.
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @class AMMicroBlog; @interface AMMicroBlogFrame : NSObject @property (nonatomic, strong) AMMicroBlog * microBlog; /*=======核心语句========*/ @property (nonatomic, assign, readonly) CGRect iconFrame; <span style="white-space:pre"> </span>/*====通过microBlog的setter方法,完成对所有属性的据算, 赋值*====/ @property (nonatomic, assign, readonly) CGRect nameFrame; @property (nonatomic, assign, readonly) CGRect vipFrame; @property (nonatomic, assign, readonly) CGRect textFrame; @property (nonatomic, assign, readonly) CGRect pictureFrame; @property (nonatomic, assign, readonly) CGFloat rowHeight; @end
自定义cell类
该类通过一个AMMicroBlogFrame对象将以上两个类封装起来.
#import <UIKit/UIKit.h> @class AMMicroBlogFrame; @interface AMMicroBlogCell : UITableViewCell @property (nonatomic, strong) AMMicroBlogFrame * microBlogFrame; /*=======核心语句======*/ +(instancetype) microBlogCellWithTableView : (UITableView *) tableView; @end
===============================
对于frame的计算时机,最早可以在从外部取的数据的时候就可以计算出frame, 因为只有文字的尺度是动态计算的.
在给内存中的模拟数组取值的时候就计算....
@property (nonatomic, strong) NSArray * microBlogFrames;
- (NSArray *)microBlogFrames{ if (!_microBlogFrames) { NSArray * microBlogs = [AMMicroBlog microBlogsList]; NSMutableArray * frames = [NSMutableArray array]; for (AMMicroBlog * blog in microBlogs) { AMMicroBlogFrame * frame = [[AMMicroBlogFrame alloc] init]; frame.microBlog = blog; //micrBlog的setter方法中,根据内容计算出frame [frames addObject: frame]; } _microBlogFrames = frames; } return _microBlogFrames; }
AMMicroBlogFrame * frame = [[AMMicroBlogFrame alloc] init]; frame.microBlog = blog; //micrBlog的setter方法中,根据内容计算出frame
AMMicroBlogFrame类中有一个AMMicroBlog类的microBlog属性,我们重写则个属性额setter方法, 在该方法中计算出AMMicroBlogFrame类中frame属性值.
@implementation AMMicroBlogFrame
- (void)setMicroBlog:(AMMicroBlog *)microBlog{ _microBlog = microBlog; CGFloat margin = 10; //头像 CGFloat iconW = 30; CGFloat iconH = 30; CGFloat iconX = margin; CGFloat iconY = margin; _iconFrame = CGRectMake(iconX, iconY, iconW, iconH); //名字 CGSize nameSize = [self sizeWithText: self.microBlog.name maxSize: CGSizeMake(MAXFLOAT, MAXFLOAT) fontSize: 15]; CGFloat nameX = CGRectGetMaxX(_iconFrame) + margin; CGFloat nameY = iconY + (iconH - nameSize.height) / 2; _nameFrame = CGRectMake(nameX, nameY, nameSize.width, nameSize.height); //VIP CGFloat vipW = 14; CGFloat vipH = 14; CGFloat vipY = nameY; CGFloat vipX = CGRectGetMaxX(_nameFrame) + margin; _vipFrame = CGRectMake(vipX, vipY, vipW, vipH); //内容 CGSize textSize = [self sizeWithText: self.microBlog.text maxSize: CGSizeMake(355, MAXFLOAT) fontSize: 14]; CGFloat textX = iconX; CGFloat textY = CGRectGetMaxY(_iconFrame) + margin; _textFrame = CGRectMake(textX, textY, textSize.width, textSize.height); //图片 if (self.microBlog.picture) { CGFloat pictureW = 100; CGFloat pictureH = 100; CGFloat pictureX = margin; CGFloat pictureY = margin + CGRectGetMaxY(_textFrame); _pictureFrame = CGRectMake(pictureX, pictureY, pictureW, pictureH); _rowHeight = CGRectGetMaxY(_pictureFrame) + margin; }else{ _rowHeight = CGRectGetMaxY(_textFrame) + margin; } } - (CGSize) sizeWithText : (NSString *) text maxSize : (CGSize) maxSize fontSize: (CGFloat) fontSize{ // CGSize maxSize = CGSizeMake(MAXFLOAT, MAXFLOAT); CGSize nameSize = [text boundingRectWithSize:maxSize options: NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize: fontSize]} context: nil].size; return nameSize; }
到此cell所需要的数据都已经完整了......
=================================
下面就是按照tableView生成的一般过程就OK了.
分组---行数---cell内容
在tableView的创建过程中,对于行高的控制,如果行高都是一样的可以直接用rowHeight属性, 但是往往行高不一致,那就需要使用代理方法控制
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
AMMicroBlogFrame * frame = self.microBlogFrames[indexPath.row];
return frame.rowHeight;
}
通过我们调试 发现, 这个代理方法的执行是在 cell内容之前的, 也就是执行
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
然后在执行
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
这一点很重要, 如果我们没有在最开始的时候就求的了 cell的所有frame数据, 那么让我们执行行高方法的时候, 很可能无法拿到行高的数值.
==================================
分组----行数
我们就此省略, 直接写cell内容方法..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AMMicroBlogCell * cell = [AMMicroBlogCell microBlogCellWithTableView: tableView];
AMMicroBlogFrame * microBlog = self.microBlogFrames[indexPath.row];
cell.microBlogFrame = microBlog; /*****核心语句******/
return cell;
}
当执行到
cell.microBlogFrame = microBlog; /*****核心语句******/这条语句的时候, AMMicroBlogFrame类中的microBlogFrame属性的setter方法会完成一系列的 cell赋值-------内容和frame.
microBlogFrame的setter方法:
- (void)setMicroBlogFrame:(AMMicroBlogFrame *)microBlogFrame{
_microBlogFrame = microBlogFrame;<span style="white-space:pre"> </span> //只需也要拿到一个 AMMicroBLogFrame对象就可以完成内容和frame的设置, 参详AMMicroBlogFrame类定义
[self setSubViewsContent]; //内容
[self setSubViewsFrame];<span style="white-space:pre"> </span>//frame
}
- (void) setSubViewsContent{
AMMicroBlog * microBlog = self.microBlogFrame.microBlog;
self.iconView.image = [UIImage imageNamed: microBlog.icon];
self.nameView.text = microBlog.name;
self.vipView.image = [UIImage imageNamed: @"vip"];
if(! microBlog.isVip){
self.vipView.hidden = YES;
self.nameView.textColor = [UIColor blackColor]; //因为cell的复用所以考虑对控件的属性设置,不然复用时候会出现问题
}else{
self.vipView.hidden = NO;
self.nameView.textColor = [UIColor redColor];
}
self.textView.text = microBlog.text;
if(microBlog.picture){
self.pictureView.image = [UIImage imageNamed: microBlog.picture];
}
}
- (void) setSubViewsFrame{
self.iconView.frame = self.microBlogFrame.iconFrame;
self.nameView.frame = self.microBlogFrame.nameFrame;
self.vipView.frame = self.microBlogFrame.vipFrame;
self.textView.frame = self.microBlogFrame.textFrame;
self.pictureView.frame = self.microBlogFrame.pictureFrame;
}
Done
===========================
代码很简答, 但是其中的 处理问题的思想 很重要....再钓到鱼的同时 还 要学到如何做一个 渔者!
封装总结, 首先创建源数据类模型, AMMicroBLog, 然后在AMMicoBlogFrame中封装AMMicroBlog, 最后在AMMicroBlogCell中封装AMMicoBlogFrame...
AMMicroBlog----------->AMMicroBlogFrame------------>AMMicroBlogCell
还有一个重要的对setter和geterr方法的使用..............OC中这个语法, 确实不错!
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- 讲解iOS开发中基本的定位功能实现
- js判断客户端是iOS还是Android等移动终端的方法
- IOS开发环境windows化攻略
- 检测iOS设备是否越狱的方法
- .net平台推送ios消息的实现方法
- 探讨Android与iOS,我们将何去何从?
- Android、iOS和Windows Phone中的推送技术详解
- IOS 改变键盘颜色代码
- 举例详解iOS开发过程中的沙盒机制与文件
- Android和IOS的浏览器中检测是否安装某个客户端的方法
- javascript实现阻止iOS APP中的链接打开Safari浏览器
- IOS开发第三方语音-微信语音
- 解析iOS开发中的FirstResponder第一响应对象