无法在父视图

时间:2018-03-10 10:32:50

标签: ios swift swift4 swift4.1

我正在尝试为视图中的子视图的帧更改设置动画。在动画块中,我将子视图的大小设置为原始宽度和高度的一半。但是,当我运行代码时,子视图意外地以更大的尺寸开始并缩小到其原始大小,而不是原始大小的一半。我使用下面的代码:

我的自定义视图:

import UIKit

class TestView: UIView {

    var testSubview: UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)

        backgroundColor = UIColor.yellow

        testSubview = UIView(frame: .zero)
        testSubview.backgroundColor = UIColor.red
        addSubview(testSubview)

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        testSubview.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
    }

    func testAnimate() {

        UIView.animate(withDuration: 3, delay: 0, options: [], animations: { [unowned self] in

            self.testSubview.bounds.size = CGSize(width: 50, height: 50)

            }, completion: nil)

    }

}

我的视图控制器:

import UIKit

class TestViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }


    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let testView = TestView()
        view.addSubview(testView)

        testView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
        testView.center = view.center

        testView.layoutIfNeeded()

        testView.testAnimate()
    }

}

我做错了吗?

2 个答案:

答案 0 :(得分:1)

问题是您的视图布局了两次,您可以通过在layoutSubviews()中打印调试消息来检查。

我会建议像这样的东西,设置一个大小变量并在layoutSubviews()和testAnimate()中使用它:

class TestView: UIView {
    var testSubview: UIView!
    var mySize = CGSize(width: 100, height: 100)

    override init(frame: CGRect) {
        super.init(frame: frame)

        backgroundColor = UIColor.yellow

        testSubview = UIView(frame: .zero)
        testSubview.backgroundColor = UIColor.red
        addSubview(testSubview)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        testSubview.frame = CGRect(x: 0, y: 0, width: mySize.width, height: mySize.height)
    }

    func testAnimate() {
        UIView.animate(withDuration: 3, delay: 0, options: [], animations: { [unowned self] in
            self.mySize = CGSize(width: 50, height: 50)
            self.testSubview.bounds.size = self.mySize
            }, completion: nil)
    }
}

答案 1 :(得分:0)

编辑:重新制定我的整个答案,因为我觉得有很多事情应该在这里改变。

首先设置视图边界与框架之间的区别。

let view = UIView()
view.frame = CGRect(x: 0, y: 0, width: 200, height: 200) // This will set the position and size this view will take relative to it's future parents view
view.bounds = CGRect(x: 50, y: 50, width: 100, height: 100) // This will set position and size of it's own content (i.e. it's background) relative to it's own view

然后是你的testView类变量。除非您确定变量不会为零,否则不要使用UIView!作为输入,否则您最终会错过一些初始化程序,因此您的课程将无法一致地工作。

将init方法视为变量的默认值,然后您可以简单地更改它们。

import UIKit

class TestView: UIView {

    var testSubview: UIView

    override init(frame: CGRect) {
        // Initialise your variables before calling super
        testSubview = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        testSubview.backgroundColor = UIColor.red

        super.init(frame: frame)
        // Once super is called you can start using class methods or variable such as addSubview or backgroundColor
        backgroundColor = UIColor.yellow
        addSubview(testSubview)
    }

    required init?(coder aDecoder: NSCoder) {

        testSubview = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        testSubview.backgroundColor = UIColor.blue

        super.init(coder: aDecoder)

        backgroundColor = UIColor.yellow
        addSubview(testSubview)
    }

}

现在终于到了动画部分

import UIKit

class TestView: UIView {

    var testSubview: UIView

    func testAnimation() {
        UIView.animate(withDuration: 3, animations: {
            self.testSubview.transform = CGAffineTransform(scaleX: 0.5, y: 0.5) // Simply make the view half its size over 3 seconds
        }) { (_) in
            UIView.animate(withDuration: 3, animations: {
                self.testSubview.transform = CGAffineTransform(scaleX: 1, y: 1) // Upon completion, resize the view back to it's original size
            })
        }
    }
}

或者如果你真的想用CGRect在它的位置做动画

import UIKit

class TestView: UIView {

    var testSubview: UIView

    func testAnimation() {
        UIView.animate(withDuration: 3, animations: {
            self.testSubview.frame = CGRect(x: 0, y: 0, width: 50, height: 50) // use frame not bounds to resize and reposition the frame
        }) { (_) in
            UIView.animate(withDuration: 3, animations: {
                self.testSubview.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
            })
        }
    }
}

您可以测试更改bounds属性的效果

import UIKit

class ViewController: UIViewController {
    var testView: TestView!
    override func viewDidLoad() {
        testView = TestView(frame: CGRect(origin: .zero, size: CGSize(width: 200, height: 200)))
        testView.bounds = CGRect(x: 50, y: 50, width: 100, height: 100)
        testView.clipsToBounds = true
        view.addSubview(testView)
        super.viewDidLoad()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        testView.testAnimation()
    }


}

只需使用clipsToBoundstestView.boundstestView.subView.frametestView = TestView(frame: CGRect(x:y:width:height)即可查看所有内容