我的 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()
})
}
我有一个 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()
})
}