UIView自定义

资料参考

UIView中与AutoLayout相关的几个方法对比: 详细介绍了UIView约束布局相关调用顺序,好好理解有助于子空间布局和约束更新。

UIView在AutoLayout下的布局过程

iOS UIkit 提供简单的基本控件,但是有时候为了需求往往需要将多个控件整合到一个View控件中,此时就是自定义View

两种方式:

1.大神:纯代码(代码创建控件、约束布局)

2.小懒神:xib (控件创建与约束) + 代码(对象化管理)

步骤

1.公共初始化方法(保证代码初始化和xib初始化一致,使用者代码和xib都调用来初始),如果是使用xib自定义,代码使用控件时一定要保证控件已经加载。

2.保证UIView的两个初始化方法都可以进行相同的初始化(通过代码创建自定义视图和在IB中穿创建),因为两种方式(如下a.b)调用的初始化方法不一致,你需要在重写两个初始化中保证同样的初始操作(小技巧:创建一个commonInit然后调用)

a.代码:init(frame:CGRect)

b.IB/xib:init(coder aDecoder:NSCoder)

3.布局约束

需要保证获取正确的frame,

对象控件.setNeedsLayout()   //需要更新标志对象控件.layoutIfNeeded()   // 更新操作// 之后就可以获取到布局后的正确frame
// 注意不可以在layoutSubviews中执行 self.这两个方法,否则会循环

一、利用xib实现自定义视图

注意:此方法仅可以用于基于UIView和其部分子类的自定义。

1、创建和设置xib文件

1.创建一个空的View(两个选一个都可以,如果选择Empty则需要自己拖一个view到画布),命名为MyView,如下图:

2.默认的空View和手机页面大小一致的,为了可以改变视图的大小,在属性检查器中设置size为freeform,将topBar也设置为none,如下图:

3.选择view上方的file Owner,将其Custom class设置为MyView(这里需要先继承UIview,生成一个MyView的类文件),这样才可以保证将自定义控件添加到类中。

注意:设置custom class的时候一定不能选择View,让它默认为UIView

4.在View中添加子控件,并设置约束

2、创建基于UIView的子类

为了能够让自定义控件的一些属性像系统控件一样可以在检查其中直接设置(可视化设置)并且同步显示,需要使用@IBDesignable【OC:IB_DESIGNABLE】 和@IBInspectable[OC:IBInspectable](具体用法见代码)

1.生成一个和xib文件名一样的继承UIview的子类(MyView)

2.将xib文件的控件添加链接到类中,包括最底层的View【重点】

3.做可视化属性的设置

4.定义初始化器(注意还需要从xib文件中加载视图放在其中)

Swift示例代码如下:

可视化控件import UIKit
import Foundation
@IBDesignable         //可视化的关键字
class MyView: UIView {@IBOutlet var contentView: UIView!//xib中最低层的View@IBOutlet weak var l2: UILabel!@IBOutlet weak var l1: UILabel!@IBInspectable     //属性可是化设置的关键字var l1Text:String = "标签1"{didSet{//设置属性观察器,保证实时改变l1.text = l1Text}}@IBInspectablevar l2Text:String = "标签2"{didSet{l2.text = l2Text}}@IBInspectablevar l1TextColor:UIColor = .black{didSet{l1.textColor  = l1TextColor}}
    //MARK:实现初始化构造器//使用代码构造此自定义视图时调用override init(frame: CGRect) {       //每一步都必须super.init(frame: frame)         //实现父初始化contentView = loadViewFromNib()  //从xib中加载视图contentView.frame = bounds       //设置约束或者布局addSubview(contentView)          //将其添加到自身中}//可视化IB初始化调用required init?(coder aDecoder: NSCoder) {super.init(coder: aDecoder)contentView = loadViewFromNib()contentView.frame = boundsaddSubview(contentView)}//MARK:自定义方法func loadViewFromNib() -> UIView {//重点注意,否则使用的时候不会同步显示在IB中,只会在运行中才显示。//注意下面的nib加载方式直接影响是否可视化,如果bundle不确切(为nil或者为main)则看不到实时可视化let nib = UINib(nibName:String(describing: MyView.self), bundle: Bundle(for:MyView.self))//【????】怎么将类名变为字符串:String(describing: MyView.self) Bundle的参数为type(of: self)也可以。let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIViewreturn view}
}

3.在IB中使用

1.首先你需要在storyboard的ViewController的需要使用的地方拖入一个父视图(UIView),将父视图的class设置为创建的MyView,如图

当然也可能会遇到添加了自定义类后什么都没有,并且还有错误,但是可以运行,错误1如下:

IB Designables: Failed to update auto layout status: The agent raised a "NSInternalInconsistencyException" exception: Could not load NIB in bundle: 'NSBundle </Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Overlays> (loaded)' with name 'MyView1

和错误2

Main.storyboard: error: IB Designables: Failed to render and update auto layout status for MyTableViewController (yC2-JG-gpT): The agent threw an exception.

那么,恭喜你,懵逼啦,请将自定义类中加载UINib的方式更改啦。

我表示进过这个坑,将bundle设置为nil或者main都不行,人家要具体点,有人说另外一种加载nib的方式也不行,没试过。

原本你的加载nib方式可能为:UINib.init(nibName: String(describing:OrderStateView.self), bundle:nil )

修改为:UINib.init(nibName: String(describing:OrderStateView.self), bundle:Bundle(for: self.classForCoder)) //具体的bundle

另外,你还有可能陷入无限循环的crash中,那么一定是你的某个自定义类设置错啦!

扩展参考:

http://www.cocoachina.com/cms/wap.php?action=article&id=17279

二、完全通过代码自定义视图

示例:实现如下图所示自定义控件

1.重写UIView的初始化化方法

    //MARK: - initoverride init(frame: CGRect) {super.init(frame: frame)commonInit()}required init?(coder aDecoder: NSCoder) {super.init(coder: aDecoder)commonInit()}

2.定义公共初始化方法

    //MARK: - private method///公共初始化(只创建,不管位置,这里不要调用self的布局属性,是不准确的)fileprivate func commonInit() -> Void {self.containerView = UIView()self.containerView.backgroundColor = UIColor.cleartopLine = UIView()topLine.backgroundColor = lineColorself.containerView.addSubview(topLine)buttomLine = UIView()buttomLine.backgroundColor = lineColorself.containerView.addSubview(buttomLine)self.addSubview(containerView)let iconImages:[String] = ["tool_addImage","tool_addAlarm","tool_a_n","tool_list","tool_num","tool_indent","tool_noIndent"]buttonArr = [imageBtn,alarmBtn,fontBtn,listBtn,listNumBtn,indentBtn,noIndentBtn]for (index,imageNamed) in iconImages.enumerated(){var indexButton = buttonArr[index]indexButton = UIButton()indexButton.setImage(UIImage.init(named: iconImages[index]), for: .normal)if index == 2{ //字体修改indexButton.setImage(UIImage.init(named: "tool_a_s"), for: .selected)}containerView.addSubview(indexButton)buttonArr[index] = indexButton}}

3.重写layoutSubviews

     //一定要在这里布局 因为从xib初始化得到的父位置是不精准的override func layoutSubviews() {super.layoutSubviews()if isFirstLayout{ //保证只初始化布局一次containerView.frame = self.bounds  //这里的bounds是准确的topLine.frame = CGRect.init(x: 0, y: 0, width: self.bounds.width, height: 1)buttomLine.frame = CGRect.init(x: 0, y: self.bounds.height - 1 , width: self.bounds.width, height: 1)let itemWidth = (self.bounds.width - 30.0)/CGFloat.init(buttonArr.count)for (index,button) in buttonArr.enumerated(){let x = 15.0+(CGFloat.init(index))*itemWidthlet y = (self.bounds.height-itemWidth)/2button.frame = CGRect.init(x: x, y: y, width: itemWidth, height: itemWidth)}isFirstLayout = false}}

UIView自定义控件-Swfit相关推荐

  1. 01UI-day7-160105

    NSInteger与int有什么区别呢? 代码实现和vfl实现autolayout,都没有运行起来,模拟器没有反应啊 奇怪,但是用masonry就ok 01-封装分页控件以及存在的问题-41min ( ...

  2. 【iOS】自定义控件入门:可拖动的环形进度

    有时候UIKit的标准控件并不能满足我们的需求,因此我们可以通过自定义控件得到满足我们需求的控件,例如这篇文章将教你如何自定义一个圆形的进度条,并且用户可以通过拖动进度条上的手柄来改变进度值.主要参考 ...

  3. iOS开发-关于自定义控件很值得一看的文章(一)

    2019独角兽企业重金招聘Python工程师标准>>> 简介 本文将是一个关于Cocoa Touch中UIKit框架的自定义控件系列教程,我们将从基础开始,由浅入深,分析讲解自定义控 ...

  4. iOS-常用的自定义控件

    2019独角兽企业重金招聘Python工程师标准>>> 前言 项目中比较可能会用到的自定义控件,也会去参考别人的第三方,解读他们解决问题的思路并加上自己的逻辑,记录下来方便以后阅读: ...

  5. UIView的几个枚举定义

    UIView是iOS开发最基本的视图,很多控件都是继承它,掌握其中的几个基本枚举定义,有利益理解视图的加载和参数区别. 一.UIViewAnimationCurve UIView的基本动画变化规律 t ...

  6. iOS: 让自定义控件适应Autolayout注意的问题

    第一个是initWithCoder方法:因为开发者多在Storyboard中使用Autolayout,而Storyboard中的View初始化不是使用常见的initWithFrame方法的,而是使用i ...

  7. iOS 自定义控件 progressView(环形进度条)

    转帖:http://blog.csdn.net/xiangzhang321/article/details/42688133 之前做项目的时候有用到环形进度条,先是在网上找了一下第三方控件,发现好用是 ...

  8. Swift实现自定义控件之---UISwitch

    Swift实现自定义控件之---UISwitch 需求分析 实现自定义UISwich控件 1. 实现代码 2. 测试代码 需求分析 项目中有一个UI页面需要用到自定义UISwitch控件,页面如图: ...

  9. .NET MAUI 中自定义控件

    今天,我想谈谈并向您展示在.NET MAUI中完全自定义控件的方法.在查看 .NET MAUI 之前,让我们回到几年前,回到Xamarin.Forms时代.那时,我们有几种自定义控件的方法:Behav ...

最新文章

  1. StringUtils常用方法+StringUtils详细介绍
  2. 网站改版后确保无误才能上线!
  3. hdu1247 字典树或者hash
  4. 直观简洁,轻易吸睛!促销海报模板
  5. 第十五章,读取txt文件(C++)
  6. LSTM训练过程与参数解读
  7. 一个成功的Jsp程序员该怎样学习JSP呢?
  8. 第10章 评价分类结果 学习上
  9. paip.修复文件关联总结
  10. 数字信号处理(三)离散时间信号的Z变换
  11. [VB.NET]vb.net如何捕捉摄相头的视频
  12. Multi-Loss Weighting with Coefficient of Variations 多任务学习
  13. idear开发工具创建maven的相关配置
  14. Win10下安装Ubuntu双系统Ubuntu分区
  15. uniapp去掉返回键
  16. 小米9se用twrp刷机时,出现persist挂载失败,导致系统启动不了的解决方法
  17. 如何搭建一套在线网校系统?需要哪些功能?
  18. 软件开发的步骤和流程
  19. shell脚本之脚本案例
  20. Cloudera Manager部署StreamSets

热门文章

  1. Glossary in Turbulence
  2. SCCM2016 集成WSUS提供补丁服务(一)
  3. Python自动化开发学习13-堡垒机开发
  4. 老旧的金融机构,是时候赶赶云计算的时髦了
  5. MySQl数据库必会sql语句(提升版)
  6. 2015级C++第14周程序阅读 STL中的简单容器和迭代器
  7. vmware redhat5.4 磁盘阵列 RIDA
  8. 使用openpyxl去操作Excel表格
  9. 邪恶的三位一体:机器学习、黑暗网络和网络犯罪
  10. 数据库——MongoDB的安装