我的 textView bottomAnchor 似乎不起作用?

My textView bottomAnchor does not seem to work?

我有一个 textView 和一条线,我设置了没有约束的线的框架,并设置了有约束的 textView 框架。只是我想要的是 textView 跟随该行,所以我将 bottomAnchor 放置到 textView 等于该行的 topAnchor。然而,当我为行设置动画时,textView 不跟随?我做错了什么?

    var button = UIButton()
    var testLine = UIView()
    let textView = UITextView()
    var textViewBottomAnchorConstraint: NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()

        testLine.backgroundColor = .black
        testLine.frame = CGRect(x: 0, y: 335, width: UIScreen.main.bounds.width, height: 10)
        view.addSubview(testLine)

        view.addSubview(textView)


        textView.frame = .zero//CGRect(x: CGFloat(integerLiteral: 16), y: CGFloat(integerLiteral: 300), width: CGFloat(integerLiteral: 282), height: CGFloat(integerLiteral: 35))
        textView.backgroundColor = UIColor.yellow
        textView.text = ""
        textView.font = UIFont(name: "Arial Rounded MT Bold", size: 15)
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.isHidden = false

        textView.translatesAutoresizingMaskIntoConstraints = false
//        textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 20).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -20).isActive = true
        textView.heightAnchor.constraint(equalToConstant: 40).isActive = true
        textViewBottomAnchorConstraint = textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0)
        textViewBottomAnchorConstraint?.isActive = true


        UIView.animate(withDuration: 2, delay: 2, options: .curveEaseIn, animations: {

            self.testLine.transform = CGAffineTransform.identity.translatedBy(x: 0, y: 30)

        }) { (true) in
            self.view.layoutIfNeeded()

        }
    }

锚点参考其他位置,意义。当您对其进行转换时,它仍被引用为 y = 355,而不是实际上 "move"。

我建议您不要混合使用 frame-based 布局和锚点/布局约束。

正如@Vollan 正确所说的动画 transform 属性 不是最佳选择。这里引用自 Apple documentation:"In iOS 8.0 and later, the transform property does not affect Auto Layout. Auto layout calculates a view’s alignment rectangle based on its untransformed frame." 因此 transform 属性 的动画不会改变 textView 的布局。我建议你制作动画 frame 属性 而不是 transform.

但是,如果您切换到 frame 动画,它并不能解决您的所有问题。如果您将动画保存在 viewDidLoad 方法中,您可能会遇到非常奇怪的行为。原因是在 viewDidLoad 中,视图本身尚未正确布局。在 viewDidLoad 内启动动画可能会导致无法预料的结果。

最后你需要调整你的动画块。 Apple 建议在 layoutIfNeeded inside 动画块中应用。或者至少他们曾经推荐它,然后引入了自动布局 - 观看 this WWDC video(从第 30 分钟开始)以了解更多详细信息。

如果您应用以上所有建议,您的代码应如下所示:

    var button = UIButton()
    var testLine = UIView()
    let textView = UITextView()
    var textViewBottomAnchorConstraint: NSLayoutConstraint?
    var triggeredAnimation = false

    override func viewDidLoad() {
        super.viewDidLoad()

        testLine.backgroundColor = .black
        testLine.frame = CGRect(x: 0, y: 335, width: UIScreen.main.bounds.width, height: 10)
        view.addSubview(testLine)

        view.addSubview(textView)


        textView.frame = .zero//CGRect(x: CGFloat(integerLiteral: 16), y: CGFloat(integerLiteral: 300), width: CGFloat(integerLiteral: 282), height: CGFloat(integerLiteral: 35))
        textView.backgroundColor = UIColor.yellow
        textView.text = ""
        textView.font = UIFont(name: "Arial Rounded MT Bold", size: 15)
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.isHidden = false

        textView.translatesAutoresizingMaskIntoConstraints = false
        //        textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 20).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -20).isActive = true
        textView.heightAnchor.constraint(equalToConstant: 40).isActive = true
        textViewBottomAnchorConstraint = textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0)
        textViewBottomAnchorConstraint?.isActive = true
    }

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

        // viewDidAppear may be called several times during view controller lifecycle
        // triggeredAnimation ensures that animation will be called just once
        if self.triggeredAnimation {
            return
        }
        self.triggeredAnimation = true

        let oldFrame = self.testLine.frame
        UIView.animate(withDuration: 2, delay: 2, options: .curveEaseIn, animations: {
            self.testLine.frame = CGRect(x: oldFrame.minX, y: oldFrame.minY + 30, width: oldFrame.width,
                                         height: oldFrame.height)
            self.view.layoutIfNeeded()
        })
    }