使用代码自定义UIView注意一二三

本文介绍如何正确地在自定义UIView中添加子控件并布局,包括重写initWithFrame方法、避免在构造方法中直接获取视图尺寸以及使用layoutSubviews方法进行布局。

这一块由两个东西组成:一个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的宽高就可以

内容概要:本文档是一份关于交换路由配置的学习笔记,系统地介绍了网络设备的远程管理、交换机与路由器的核心配置技术。内容涵盖Telnet、SSH、Console三种远程控制方式的配置方法;详细讲解了VLAN划分原理及Access、Trunk、Hybrid端口的工作机制,以及端口镜像、端口汇聚、端口隔离等交换技术;深入解析了STP、MSTP、RSTP生成树协议的作用与配置步骤;在路由部分,涵盖了IP地址配置、DHCP服务部署(接口池与全局池)、NAT转换(静态与动态)、静态路由、RIP与OSPF动态路由协议的配置,并介绍了策略路由和ACL访问控制列表的应用;最后简要说明了华为防火墙的安全区域划分与基本安全策略配置。; 适合人群:具备一定网络基础知识,从事网络工程、运维或相关技术岗位1-3年的技术人员,以及准备参加HCIA/CCNA等认证考试的学习者。; 使用场景及目标:①掌握企业网络中常见的交换与路由配置技能,提升实际操作能力;②理解VLAN、STP、OSPF、NAT、ACL等核心技术原理并能独立完成中小型网络搭建与调试;③通过命令示例熟悉华为设备CLI配置逻辑,为项目实施和故障排查提供参考。; 阅读建议:此笔记以实用配置为主,建议结合模拟器(如eNSP或Packet Tracer)动手实践每一条命令,对照拓扑理解数据流向,重点关注VLAN间通信、路由选择机制、安全策略控制等关键环节,并注意不同设备型号间的命令差异。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值