【发布时间】:2020-04-09 00:22:59
【问题描述】:
试图同时隐藏 TabBar 和 StatusBar 并在同一个动画块内,我遇到了一个难以理解的布局行为。开始使用 tabbar item viewcontroller 以通常的方式隐藏 TabBar:
import UIKit
class TestViewController: UIViewController {
var mainViewController: UITabBarController {
get {
return UIApplication.shared.windows.first {$0.rootViewController != nil}?.rootViewController as! UITabBarController
}
}
var offset: CGFloat!
override func viewDidLoad() {
super.viewDidLoad()
offset = mainViewController.tabBar.frame.height
}
@IBAction func HideMe(_ sender: Any) {
let tabBar = self.mainViewController.tabBar
let animator = UIViewPropertyAnimator(duration: 1, curve: .linear) {
tabBar.frame = tabBar.frame.offsetBy(dx: 0, dy: self.offset)
}
animator.startAnimation()
}
}
到目前为止一切顺利:
现在让我们为 StatusBar 添加动画:
import UIKit
class TestViewController: UIViewController {
var mainViewController: UITabBarController {
get {
return UIApplication.shared.windows.first {$0.rootViewController != nil}?.rootViewController as! UITabBarController
}
}
var isTabBarHidden = false {
didSet(newValue) {
setNeedsStatusBarAppearanceUpdate()
}
}
override var prefersStatusBarHidden: Bool {
get {
return isTabBarHidden
}
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
get {
return .slide
}
}
var offset: CGFloat!
override func viewDidLoad() {
super.viewDidLoad()
offset = mainViewController.tabBar.frame.height
}
@IBAction func HideMe(_ sender: Any) {
let tabBar = self.mainViewController.tabBar
let animator = UIViewPropertyAnimator(duration: 1, curve: .linear) {
tabBar.frame = tabBar.frame.offsetBy(dx: 0, dy: self.offset)
self.isTabBarHidden = true
}
animator.startAnimation()
}
}
现在 StatusBar 在滑动,bur TabBar 冻结(我不知道为什么):
任何使用 layoutIfNeeded()、setNeedsLayout() 等更新布局的尝试均不成功。现在让我们交换 TabBar 和 StatusBar 的动画:
@IBAction func HideMe(_ sender: Any) {
let tabBar = self.mainViewController.tabBar
let animator = UIViewPropertyAnimator(duration: 1, curve: .linear) {
self.isTabBarHidden = true
tabBar.frame = tabBar.frame.offsetBy(dx: 0, dy: self.offset)
}
animator.startAnimation()
}
现在两者都在滑动,但 TabBar 在动画开始时开始跳跃:
我发现在将 StatusBar 的指令添加到动画块时,会开始另外调用 ViewDidLayoutSubviews()。其实你可以在 ViewDidLayoutSubviews() 中固定 TabBar 的初始位置:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if isTabBarHidden {
let tabBar = self.mainViewController.tabBar
tabBar.frame = tabBar.frame.offsetBy(dx: 0, dy: self.offset)
}
}
这种方法的缺点是TabBar在移动的过程中会抽搐,这取决于移动的速度和其他因素。
另一种方式(不使用 ViewDidLayoutSubviews())与逻辑相反,但在实践中有效。也就是说,您可以将一个动画放在另一个动画的完成块中:
@IBAction func HideMe(_ sender: Any) {
let tabBar = self.mainViewController.tabBar
let animator1 = UIViewPropertyAnimator(duration: 1, curve: .linear) {
self.isTabBarHidden = !self.isTabBarHidden
}
animator1.addCompletion({_ in
let animator2 = UIViewPropertyAnimator(duration: 1, curve: .linear) {
tabBar.frame = tabBar.frame.offsetBy(dx: 0, dy: self.offset)
}
animator2.startAnimation()
})
animator1.startAnimation()
}
按照逻辑,我们有两个连续的动画。并且 TabBar 动画应该在 StatusBar 动画结束后开始。但是,在实践中:
这种方法的缺点是,如果你想反转动画(例如,用户在 TabBar 移动时点击了屏幕),变量 animator1.isRunning 将是 false,虽然在物理上StatusBar 仍然会在屏幕上移动(我也不知道为什么)。
期待阅读您的 cmets、建议、解释。
【问题讨论】:
标签: ios uitabbar statusbar uiviewanimation uiviewpropertyanimator