iOS 自动布局:UITextView 在 UIScrollView 中的奇怪展开动画
iOS Autolayout: Oddly expand-animation of UITextView inside an UIScrollView
我正在尝试为 UIScrollView 中的 UITextView 的高度约束设置动画。当用户点击 "toggle" 按钮时,文本应该以动画形式从上到下显示。但不知何故,UIKit 在完整视图中消失了。
为了确保 "dynamic" 高度取决于内在内容大小,我停用了设置为零的高度限制。
@IBAction func toggle() {
layoutIfNeeded()
UIView.animate(withDuration: 0.6, animations: { [weak self] in
guard let self = self else {
return
}
if self.expanded {
NSLayoutConstraint.activate([self.height].compactMap { [=11=] })
} else {
NSLayoutConstraint.deactivate([self.height].compactMap { [=11=] })
}
self.layoutIfNeeded()
})
expanded.toggle()
}
此示例的完整代码可在我的 GitHub 存储库中找到:ScrollAnimationExample
正在审查您的 GitHub 存储库...
此问题是由于动画 view
引起的。您想要 运行 .animate()
在层次结构中的 "top-most" 视图上。
为此,您可以创建 ExpandableView
的新 属性,例如:
var topMostView: UIView?
然后从您的视图控制器设置 属性,或者...
为了保持您的 class 封装,让它找到最顶层的视图。将您的 toggle()
函数替换为:
@IBAction func toggle() {
// we need to run .animate() on the "top" superview
// make sure we have a superview
guard self.superview != nil else {
return
}
// find the top-most superview
var mv: UIView = self
while let s = mv.superview {
mv = s
}
// UITextView has subviews, one of which is a _UITextContainerView,
// which also has a _UITextCanvasView subview.
// If scrolling is disabled, and the TextView's height is animated to Zero,
// the CanvasView's height is instantly set to Zero -- so it disappears instead of animating.
// So, when the view is "expanded" we need to first enable scrolling,
// and then animate the height (to Zero)
// When the view is NOT expanded, we first disable scrolling
// and then animate the height (to its intrinsic content height)
if expanded {
textView.isScrollEnabled = true
NSLayoutConstraint.activate([height].compactMap { [=11=] })
} else {
textView.isScrollEnabled = false
NSLayoutConstraint.deactivate([height].compactMap { [=11=] })
}
UIView.animate(withDuration: 0.6, animations: {
mv.layoutIfNeeded()
})
expanded.toggle()
}
我正在尝试为 UIScrollView 中的 UITextView 的高度约束设置动画。当用户点击 "toggle" 按钮时,文本应该以动画形式从上到下显示。但不知何故,UIKit 在完整视图中消失了。
为了确保 "dynamic" 高度取决于内在内容大小,我停用了设置为零的高度限制。
@IBAction func toggle() {
layoutIfNeeded()
UIView.animate(withDuration: 0.6, animations: { [weak self] in
guard let self = self else {
return
}
if self.expanded {
NSLayoutConstraint.activate([self.height].compactMap { [=11=] })
} else {
NSLayoutConstraint.deactivate([self.height].compactMap { [=11=] })
}
self.layoutIfNeeded()
})
expanded.toggle()
}
此示例的完整代码可在我的 GitHub 存储库中找到:ScrollAnimationExample
正在审查您的 GitHub 存储库...
此问题是由于动画 view
引起的。您想要 运行 .animate()
在层次结构中的 "top-most" 视图上。
为此,您可以创建 ExpandableView
的新 属性,例如:
var topMostView: UIView?
然后从您的视图控制器设置 属性,或者...
为了保持您的 class 封装,让它找到最顶层的视图。将您的 toggle()
函数替换为:
@IBAction func toggle() {
// we need to run .animate() on the "top" superview
// make sure we have a superview
guard self.superview != nil else {
return
}
// find the top-most superview
var mv: UIView = self
while let s = mv.superview {
mv = s
}
// UITextView has subviews, one of which is a _UITextContainerView,
// which also has a _UITextCanvasView subview.
// If scrolling is disabled, and the TextView's height is animated to Zero,
// the CanvasView's height is instantly set to Zero -- so it disappears instead of animating.
// So, when the view is "expanded" we need to first enable scrolling,
// and then animate the height (to Zero)
// When the view is NOT expanded, we first disable scrolling
// and then animate the height (to its intrinsic content height)
if expanded {
textView.isScrollEnabled = true
NSLayoutConstraint.activate([height].compactMap { [=11=] })
} else {
textView.isScrollEnabled = false
NSLayoutConstraint.deactivate([height].compactMap { [=11=] })
}
UIView.animate(withDuration: 0.6, animations: {
mv.layoutIfNeeded()
})
expanded.toggle()
}