iOS 11 UIStackView 填充按比例分布导致奇怪的视图加载动画
iOS 11 UIStackView fill proportionally distribution causes weird view loading animation
如果我设置:
stackView.distributon = .fillProportionally
然后在 iOS 11 加载包含此堆栈视图的视图时,我得到一个非常奇怪的动画(所有子视图 - 不仅仅是堆栈视图 - 从屏幕的顶部或底部飞行)。在较低的 iOS 版本上一切正常。如果我将堆栈视图的分布设置为其他任何内容,一切也都正常。
有谁知道这个问题的原因是什么?
谢谢。
今天早上我在使用 GM 种子时遇到了同样的问题。我最终使用 UIView.performWithoutAnimation {
块在暂时不需要动画的地方进行任何 UIStackView
修改。
我想我找到了解决方法 - 在 animations
块中调用 self.view.layoutIfNeeded()
。
这是我的复制品:
import UIKit
class ViewController: UIViewController {
var showB = true
weak var viewB: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let viewA = UIView()
viewA.backgroundColor = UIColor.green
let toggleViewBButtonAnimated = UIButton(frame: CGRect(x: 50, y: 150, width: 200, height: 40))
toggleViewBButtonAnimated.backgroundColor = UIColor.cyan
toggleViewBButtonAnimated.setTitle("Toggle B (animated)", for: .normal)
viewA.addSubview(toggleViewBButtonAnimated)
toggleViewBButtonAnimated.addTarget(self, action: #selector(toggleBButtonTappedAnimated), for: .touchUpInside)
let viewB = UIView()
viewB.backgroundColor = UIColor.orange
let viewBHeightConstraint = viewB.heightAnchor.constraint(equalToConstant: 200)
viewBHeightConstraint.priority = 999
viewBHeightConstraint.isActive = true
self.viewB = viewB
let stackView = UIStackView(arrangedSubviews: [viewA, viewB])
stackView.axis = .vertical
stackView.alignment = .fill
stackView.distribution = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(stackView)
stackView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
}
@IBAction func toggleBButtonTappedAnimated() {
self.showB = !self.showB
UIView.animate(withDuration: 0.3,
animations: { self.viewB.isHidden = !self.showB; self.view.layoutIfNeeded() }
)
}
}
此控制器设置了一个 UIStackView
,它有两个垂直视图,绿色视图 (A) 和橙色视图 (B)。点击按钮 hides/unhides 查看 B.
如果我 not 在 animations
块中有 self.view.layoutIfNeeded()
,那么,当显示视图 B 时,它从顶部飞入屏幕。 (当视图 B 被隐藏时,它会正常隐藏 - 从屏幕底部向下移动。)
当我将 self.view.layoutIfNeeded()
添加到 animations
块时,视图 B 按预期显示 - 它从屏幕底部出现。
感谢@g3rv4 的回答为我指明了这个方向!
对我来说,问题是 iOS11 中引入的行为回归,与 UIStackView 分布类型无关。我尝试了几个基于代码的解决方案无济于事:首先,在容器层次结构上调用 layoutIfNeeded;其次,(如对类似问题的另一个答案所示)调整视图的 contentMode。
我的 hacky 解决方案如下:
在 UIStackView 的一侧添加一个新的零宽度 UIView 占位符,其中显示动画错误地将项目从屏幕边缘引入。
如果我设置:
stackView.distributon = .fillProportionally
然后在 iOS 11 加载包含此堆栈视图的视图时,我得到一个非常奇怪的动画(所有子视图 - 不仅仅是堆栈视图 - 从屏幕的顶部或底部飞行)。在较低的 iOS 版本上一切正常。如果我将堆栈视图的分布设置为其他任何内容,一切也都正常。
有谁知道这个问题的原因是什么?
谢谢。
今天早上我在使用 GM 种子时遇到了同样的问题。我最终使用 UIView.performWithoutAnimation {
块在暂时不需要动画的地方进行任何 UIStackView
修改。
我想我找到了解决方法 - 在 animations
块中调用 self.view.layoutIfNeeded()
。
这是我的复制品:
import UIKit
class ViewController: UIViewController {
var showB = true
weak var viewB: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let viewA = UIView()
viewA.backgroundColor = UIColor.green
let toggleViewBButtonAnimated = UIButton(frame: CGRect(x: 50, y: 150, width: 200, height: 40))
toggleViewBButtonAnimated.backgroundColor = UIColor.cyan
toggleViewBButtonAnimated.setTitle("Toggle B (animated)", for: .normal)
viewA.addSubview(toggleViewBButtonAnimated)
toggleViewBButtonAnimated.addTarget(self, action: #selector(toggleBButtonTappedAnimated), for: .touchUpInside)
let viewB = UIView()
viewB.backgroundColor = UIColor.orange
let viewBHeightConstraint = viewB.heightAnchor.constraint(equalToConstant: 200)
viewBHeightConstraint.priority = 999
viewBHeightConstraint.isActive = true
self.viewB = viewB
let stackView = UIStackView(arrangedSubviews: [viewA, viewB])
stackView.axis = .vertical
stackView.alignment = .fill
stackView.distribution = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(stackView)
stackView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
}
@IBAction func toggleBButtonTappedAnimated() {
self.showB = !self.showB
UIView.animate(withDuration: 0.3,
animations: { self.viewB.isHidden = !self.showB; self.view.layoutIfNeeded() }
)
}
}
此控制器设置了一个 UIStackView
,它有两个垂直视图,绿色视图 (A) 和橙色视图 (B)。点击按钮 hides/unhides 查看 B.
如果我 not 在 animations
块中有 self.view.layoutIfNeeded()
,那么,当显示视图 B 时,它从顶部飞入屏幕。 (当视图 B 被隐藏时,它会正常隐藏 - 从屏幕底部向下移动。)
当我将 self.view.layoutIfNeeded()
添加到 animations
块时,视图 B 按预期显示 - 它从屏幕底部出现。
感谢@g3rv4 的回答为我指明了这个方向!
对我来说,问题是 iOS11 中引入的行为回归,与 UIStackView 分布类型无关。我尝试了几个基于代码的解决方案无济于事:首先,在容器层次结构上调用 layoutIfNeeded;其次,(如对类似问题的另一个答案所示)调整视图的 contentMode。
我的 hacky 解决方案如下:
在 UIStackView 的一侧添加一个新的零宽度 UIView 占位符,其中显示动画错误地将项目从屏幕边缘引入。