使用代码自定义UIView注意一二三
原文链接:http://www.jianshu.com/p/68b383b129f9
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
当一撮样式一样的视图在工程中被多次使用的时候,为了方便使用,我们会想把他们抽成一个单独的类,进行视图的自定义.
比如我们要做一个这样的东西:
这一块由两个东西组成:一个imageView和一个label。首先我们新建一个继承自UIView的类MyView.
在MyView的.m文件里,你可以根据自己的意愿将两个子控件设置成MyView的属性或者成员变量,这里我们设置为属性。
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UILabel *label;
那接下来,就是要向自定义的view里面添加控件咯。
通常的思路是重写UIView的构造方法。那么这里要说第一个注意了:
1.要重写UIView的initWithFrame:方法而不是init方法
为什么呢?因为当外部调用init的方法的时候,其内部也会默默地调用initWithFrame:方法,你不能保证别的同事在调用你的类的时候不会直接调用initWithFrame:方法,这时如果你仅重写了init方法,那么两个子控件便无从创建.
于是我们写成这样:
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
/* 添加子控件的代码*/
}
return self;
}
接下开始添加子控件,不知道还会不会有小伙伴是这样写的:
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.imageView = [[UIImageView alloc]init];
self.imageView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.width);
[self addSubview:self.imageView];
}
return self;
}
这样有什么问题吗?如果全部写好运行起来,能看到imageView吗?答案是不确定的.问题出现在给imageView的frame赋值那里.
imageView的宽和高直接用self.frame.size.width,但这个时候self.frame可能是没有值的.
上面我们说过,如果外部调用了MyView的init方法,也会执行到这里,这时候frame还没有赋值.
所以第二个注意:
2.不要在构造方法里面直接取自身(self,或者说本视图)的宽高,这时候取到的宽高是不准的.
我想初学自定义tableViewCell的小伙伴都遇到过类似这样的问题:
重写cell的初始化方法向cell内添加子控件时
(假设cell的高度设为100,想要添加一个label在cell的底部),
于是这样写:
label.frame = CGRectMake(0,self.frame.size.height - 20, 100, 20),
运行出来却发现添加的label并不在我们期望的位置(底部),
而是在cell比较偏上的位置(实际y的值是44-20而不是100-20).
然后在debug的时候发现:虽然cell的高度已经设定成为100,但在初始化方法里面取到的cell的高度仍然是默认的44.
这其实也是刚才说的原因导致的:我们不能在控件的构造方法里面取其frame或者bounds,这时候取值是不准确的.
所以在重新构造方法的时候,我们只需要把控件放进去,暂时先不用考虑他们在什么位置:
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.imageView = [[UIImageView alloc]init];
[self addSubview:self.imageView];
self.label = [[UILabel alloc]init];
self.label.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.label];
}
return self;
}
那么在什么时候设置子控件的frame呢?
第三个注意:
3.在layoutSubViews方法里面布局子控件
如下:
- (void)layoutSubviews {
// 一定要调用super的方法
[super layoutSubviews];
// 确定子控件的frame(这里得到的self的frame/bounds才是准确的)
CGFloat width = self.bounds.size.width;
CGFloat height = self.bounds.size.height;
self.imageView.frame = CGRectMake(0, 0, width, width);
self.label.frame = CGRectMake(0, width, width, height - width);
}
这里要注意的就是需要在布局之前一定要先调用父类的layoutSubviews方法.
由于在这个方法里可以获取MyView准确的宽和高,我们直接取它的宽高来设置imageView和label的宽高就可以
当然,子控件的创建不一定要写在MyView的构造方法里面,既然声明成为属性,使用懒加载(重写属性的get方法)也是一个不错的选择.
使用代码自定义UIView注意一二三的更多相关文章
- IOS xib和代码自定义UIView
https://www.jianshu.com/p/1bcc29653085 总结的比较好 iOS开发中,我们常常将一块View封装起来,以便于统一管理内部的子控件. 下面就来说说自定义View的封装 ...
- iOS开发小技巧--纯代码自定义cell
纯代码自定义cell 自定义cell的步骤(每个cell的高度不一样,每个cell里面显示的内容也不一样) 1.新建一个继承自UITableViewCell的子类 2.在initWithStyle:方 ...
- IOS自定义UIView
IOS中一般会用到几种方式自定义UIView 1.继承之UIView的存代码的自定义View 2.使用xib和代码一起使用的自定义View 3.存xib的自定义View(不需要业务处理的那种) 本文主 ...
- 代码自定义双色title的按钮
所图所示,通过代码自定义这样的按钮. .h文件 // // CustomButtom.h // testPlus // // Created by 鹰眼 on 14/10/20. // Copyrig ...
- ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局
本文转自 :http://www.cnblogs.com/wendingding/p/3761730.html ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布 ...
- 通过代码自定义cell 新浪微博页面显示
通过代码自定义cell(cell的高度不一致)(如果高度一致的cell 用xib实现) 1.新建一个集成自UItableVIewCell的类 2.重写initWithStle :方法 - (insta ...
- [iOS基础控件 - 6.7] 微博展示 使用代码自定义TableCell(动态尺寸)
A.需求 1.类似于微博内容的展示 2.头像 3.名字 4.会员标志 5.内容 6.分割线 7.配图(可选,可有可无) code source: https://github.com/hellov ...
- 使用Java代码自定义Ribbon配置
很多场景下,需要实现不同的微服务采用不同的策略,例如修改Ribbon的负载均衡规则等.Spring Cloud允许使用Java代码自定义Ribbon的配置. 在Spring Cloud中,Ribbon ...
- 0404-服务注册与发现-客户端负载均衡-两种自定义方式-Ribbon通过代码自定义配置、使用配置文件自定义Ribbon Client
一.官方文档解读 官方地址:https://cloud.spring.io/spring-cloud-static/Edgware.SR3/single/spring-cloud.html#_cust ...
随机推荐
- lua 加密
项目要求对lua脚本进行加密,查了一下相关的资料 ,得知lua本身可以使用luac将脚本编译为字节码(bytecode)从而实现加密,试了一下,确实可行.下面是使用原生的lua解释器编译字节码:1.新 ...
- Qt之加密算法
在写这篇文章之前,我曾反复思量关于加密的叫法是否准确,更为严格来说,应该是密码散列-将数据(如中英文字母.特殊字符)通过复杂的算法转换为另一种固定长度的值. QCryptographi ...
- 获取scrollTop兼容各浏览器的方法,以及body和documentElement
1.各浏览器下 scrollTop的差异 IE6/7/8: 对于没有doctype声明的页面里可以使用 document.body.scrollTop 来获取 scrollTop高度 : 对于有do ...
- 统计"面"要素中"点"要素的个数.
步骤 1,创建字段 IFields /// <summary> /// 创建:"面"-"点数"的字段. /// </summary> / ...
- .net ADF 中 Ajax 的调用过程.
图示是 .net ADF Ajax调用过程的简略过程: 1,2)当页面初始化之后, 浏览器一旦触发回调事件, 脚本函数负责处理回调信息, 并调用 ASP.NET 2.0/3.5 中的 WebForm_ ...
- Spring整合Quartz实现动态定时器
一.版本说明 spring3.1以下的版本必须使用quartz1.x系列,3.1以上的版本才支持quartz 2.x,不然会出错. 原因:spring对于quartz的支持实现,org.springf ...
- [Mugeda HTML5技术教程之9]使用元件
元件是一个可以在舞台上实例化和再利用的预先生成的独立动画.一个元件有它自己的时间轴(层,单位等),可以独立显示的动画.元件提高了动画的重用性和灵活性,是个强大的存在.元件可用于创建复杂的动画效果. 所 ...
- PHP面向对象的构造方法与析构方法
构造方法与析构方法是对象中的两个特殊方法,它们都与对象的生命周期有关.构造方法时对象创建完成后第一个被对象自动调用的方法,这是我们在对象中使用构造方法的原因.而析构方法时对象在销毁之前最后一个被对象自 ...
- WCF消息
1. MessageContract 序列化一个对象并生成消息的时候,希望将部分数据成员作为SOAP的报头,部分作为消息的主体.比如说,我们有一个服务操作采用流的方式进行文件的上载,除了以流的方式传输 ...
- Responder一点也不神秘————iOS用户响应者链完全剖析
一.事件分类 对于IOS设备用户来说,他们操作设备的方式主要有三种:触摸屏幕.晃动设备.通过遥控设施控制设备.对应的事件类型有以下三种: 1.触屏事件(Touch Event) 2.运动事件(Moti ...