UIView

  • 在iOS中,所有的控件都有大小(size)、位置(frame、bounds、center)、颜色等...这些共有属性全部抽象在了UIView里面,所以几乎所有的控件(UIImageView、UILabel)都是继承自UIView。

  • 每个UIView都是一个容器,能够容纳其他容器,所以UIView有superView和subViews属性,也有addSubViews和removeFromSuperView等方法。

属性

基本属性

  • frame: frame是指控件矩形框在父控件中的位置和尺寸,其中位置是以父控件左上角为坐标原点。
  • bounds: bounds是值控件矩形框的位置和尺寸,其中位置是以自己的左上角为坐标原点。(一般控件的bounds的x,y分别为0,0)
  • center: center是指控件矩形框在父控件中心点的位置,以父控件左上角为原点。
  • superView:superView是本控件的直接父控件,对于一个控制器(UIViewController)来说,会有一个最顶层的UIView来管理其子空间
  • subViews:subViews指的是本控件下的直接子控件,本控件负责管理子控件。

基本方法

  • addSubView: 添加子控件
  • removeFromSuperView: 从父控件中移除
  • layoutSubViews: 布局子控件

构造方法

  • 由于UIView 既可以从xib加载也可以通过代码创建,所以有多种构造方法。
  1. init()无参构造方法 var aView = UIView()
  2. init(frame: CGrect) var bView = UIView(frame: CGrect)
  3. init?(coder aDecoder: NSCoder) var cView = UIView(coder: NSCoder)

区别

1.对于通过代码创建的自定义控件来说,一般有两种情况:

  • 第一种是先实例化控件,再设置控件位置
    var aView = UIView()
    aView.frame = CGRectMake(0,0,10,10)
  • 第二种就是在实例化控件的同时就指定控件的位置
    var bView = UIView(frame: CGRectMake(0,0,10,10))
  • 这两个方法区别在于如果是直接调用的无参构造方法,系统会再次调用init(frame:CGRect)方法,而如果我们调用的是UIView(frame: CGRect)方法,系统不会再去调用无参构造方法。

2.如果是通过xib去创建自定义控件来说,则会去调用init?(coder aDecoder:NSCoder)方法

  • 注意:如果是通过xib或者storyBoard自定义控件,并且重写 了init?(coder aDecoder: NSCoder)方法,在该方法里面对控件里面做一些初始化操作,如颜色、大小等,很可能会出问题。因为在调用该方法的时候,有些控件很可能还未创建出来,所以要进行初始化操作最好在另一个方法awakeFromNib中进行,用来辅助该方法进行一些初始化操作。

3.自定义控件最好的做法是

override init(frame: CGRect){
        super.init(frame: frame);
        prepareForView()
}

required init?(coder aDecoder: NSCoder){
    super.init(coder: aDecoder);
        prepareForView()
}

func prepareForView(){
    //初始化操作
}
  • 这样的话,无论是通过xib\storyBoard里面加载还是从代码加载,都能顺利地初始化自定义控件。

layoutSubViews调用

  • 我们通常会在layoutSubViews 这个方法中设置子控件的frame,让其跟随父控件的frame变化而变化,那么layoutSubViews方法在什么时候调用呢?
  • 来看看下面的场景,我有一个红色的父控件,让其紧靠控制器View的左上方,长宽都为100,首先来构造这个控件,假设为RedView,不重写其构造方法
import UIKit

class RedView: UIView {

    override func layoutSubviews() {

        super.layoutSubviews()

        pritn("call layoutSubVies method")

    }

}
  • 其实例化过程有一下两种方式:
import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {

        super.viewDidLoad()

        let redView = RedView() //方式1

        let redView = RedView(frame: CGRectMake(0, 0, 200, 200))//方式2

        view.addSubview(redView)

    }
}
  • 可以通过运行发现,对于方式1,"call layoutSubVies method"这句话不会被打印出来,而在方式2中则会打印出这句话
  • 通过对比不难发现,方式2设置了redView的frame,而我们只需要将方式1中控件的frame设置,自然会调用其内部的layoutSubView方法。

注意:

  • 实际只要父控件的frame有变化,layoutSubView就会被调用
  • 如果是这样实例化的 let redView = RedView(frame: CGRectZero) 或者 let redView = RedView(frame: CGRectMake(0,0,0,0,)),其layoutSubView方法不会被调用,因为他们的frame相当于没有设置或者说没有发生改变。
  • 在实例化的时候,如果将控件的frame连续改变,只会调用一次layoutSubView,例如:
    let redView = RedView(frame: CGRectMake(0,0,100,100))
    redView.frame = CGRectMake(10,10,50,50)
  • 这样操作的化,只会调一次layoutSubView,以最后一次的为准,这个原因好像是在一次循环机制(runloop)引起的。

你可能感兴趣的:(UIView)