UIView

作者: PeterDywane | 来源:发表于2016-05-13 16:27 被阅读51次
    • 在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

        本文链接:https://www.haomeiwen.com/subject/rhhmrttx.html