Fay*_*yer 2 uinavigationbar ios custom-transition swift
我想在具有不同UINavigationBar背景颜色的视图之间实现流畅的动画。嵌入的视图具有相同的背景颜色UINavigationBar,我想模仿推/弹出过渡动画,如:
我准备了自定义过渡:
class CustomTransition: NSObject, UIViewControllerAnimatedTransitioning {
private let duration: TimeInterval
private let isPresenting: Bool
init(duration: TimeInterval = 1.0, isPresenting: Bool) {
self.duration = duration
self.isPresenting = isPresenting
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let container = transitionContext.containerView
guard
let toVC = transitionContext.viewController(forKey: .to),
let fromVC = transitionContext.viewController(forKey: .from),
let toView = transitionContext.view(forKey: .to),
let fromView = transitionContext.view(forKey: .from)
else {
return
}
let rightTranslation = CGAffineTransform(translationX: container.frame.width, y: 0)
let leftTranslation = CGAffineTransform(translationX: -container.frame.width, y: 0)
toView.transform = isPresenting ? rightTranslation : leftTranslation
container.addSubview(toView)
container.addSubview(fromView)
fromVC.navigationController?.navigationBar.backgroundColor = .clear
fromVC.navigationController?.navigationBar.setBackgroundImage(UIImage.fromColor(color: .clear), for: .default)
UIView.animate(
withDuration: self.duration,
animations: {
fromVC.view.transform = self.isPresenting ? leftTranslation :rightTranslation
toVC.view.transform = .identity
},
completion: { _ in
fromView.transform = .identity
toVC.navigationController?.navigationBar.setBackgroundImage(
UIImage.fromColor(color: self.isPresenting ? .yellow : .lightGray),
for: .default
)
transitionContext.completeTransition(true)
}
)
}
}
Run Code Online (Sandbox Code Playgroud)
并在UINavigationControllerDelegate方法实现中返回它:
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return CustomTransition(isPresenting: operation == .push)
}
Run Code Online (Sandbox Code Playgroud)
虽然推送动画效果很好,但流行音乐却没有。
问题:
这是我在 GitHub 上的测试项目的链接。
编辑
这是展示所讨论问题的全貌和预期效果的 gif:
这些组件总是很难定制。我认为,Apple 希望系统组件在每个应用程序中的外观和行为都相同,因为它允许在整个 iOS 环境中保持共享的用户体验。
有时,从头开始实现自己的组件比尝试自定义系统组件更容易。定制通常可能很棘手,因为您不确定内部组件是如何设计的。因此,您必须处理许多边缘情况并处理不必要的副作用。
尽管如此,我相信我有解决您的情况的方法。我已经分叉了您的项目并实施了您所描述的行为。你可以在GitHub 上找到我的实现。见animation-implementation分行。
流行动画不能正常工作的根本原因是它UINavigationBar有自己的内部动画逻辑。当UINavigationController's堆栈改变时,UINavigationController告诉UINavigationBar改变UINavigationItems。因此,首先,我们需要禁用UINavigationItems. 它可以通过子类化来完成UINavigationBar:
class CustomNavigationBar: UINavigationBar {
override func pushItem(_ item: UINavigationItem, animated: Bool) {
return super.pushItem(item, animated: false)
}
override func popItem(animated: Bool) -> UINavigationItem? {
return super.popItem(animated: false)
}
}
Run Code Online (Sandbox Code Playgroud)
然后UINavigationController应该初始化为CustomNavigationBar:
let nc = UINavigationController(navigationBarClass: CustomNavigationBar.self, toolbarClass: nil)
Run Code Online (Sandbox Code Playgroud)
既然有需求,以保持平滑的动画之间的同步UINavigationBar,并提出UIViewController,我们需要创建自定义过渡动画对象UINavigationController,并使用CoreAnimation与CATransaction。
你对过渡动画的实现几乎完美,但在我看来,几乎没有遗漏细节。在自定义过渡动画一文中,您可以找到更多信息。另外,请注意UIViewControllerContextTransitioning协议中的方法注释。
所以,我的推送动画版本如下所示:
func animatePush(_ transitionContext: UIViewControllerContextTransitioning) {
let container = transitionContext.containerView
guard let toVC = transitionContext.viewController(forKey: .to),
let toView = transitionContext.view(forKey: .to) else {
return
}
let toViewFinalFrame = transitionContext.finalFrame(for: toVC)
toView.frame = toViewFinalFrame
container.addSubview(toView)
let viewTransition = CABasicAnimation(keyPath: "transform")
viewTransition.duration = CFTimeInterval(self.duration)
viewTransition.fromValue = CATransform3DTranslate(toView.layer.transform, container.layer.bounds.width, 0, 0)
viewTransition.toValue = CATransform3DIdentity
CATransaction.begin()
CATransaction.setAnimationDuration(CFTimeInterval(self.duration))
CATransaction.setCompletionBlock = {
let cancelled = transitionContext.transitionWasCancelled
if cancelled {
toView.removeFromSuperview()
}
transitionContext.completeTransition(cancelled == false)
}
toView.layer.add(viewTransition, forKey: nil)
CATransaction.commit()
}
Run Code Online (Sandbox Code Playgroud)
流行动画实现几乎相同。和属性CABasicAnimation值的唯一区别。fromValuetoValue
为了动画,UINavigationBar我们必须CATransition在UINavigationBar图层上添加动画:
let transition = CATransition()
transition.duration = CFTimeInterval(self.duration)
transition.type = kCATransitionPush
transition.subtype = self.isPresenting ? kCATransitionFromRight : kCATransitionFromLeft
toVC.navigationController?.navigationBar.layer.add(transition, forKey: nil)
Run Code Online (Sandbox Code Playgroud)
上面的代码将使整个UINavigationBar. 为了仅对 的背景进行动画处理,UINavigationBar我们需要从UINavigationBar. 这就是诀窍:UINavigationBaris _UIBarBackgroundview 的第一个子视图(可以使用 Xcode Debug View Hierarchy 对其进行探索)。在我们的例子中,确切的类并不重要,它是UIView. 最后,我们可以直接在_UIBarBackground的视图层上添加动画过渡:
let backgroundView = toVC.navigationController?.navigationBar.subviews[0]
backgroundView?.layer.add(transition, forKey: nil)
Run Code Online (Sandbox Code Playgroud)
我想指出,我们正在预测第一个子视图是背景视图。将来可能会更改视图层次结构,请记住这一点。
将两个动画合二为一很重要CATransaction,因为在这种情况下,这些动画将同时运行。
您可以UINavigationBar在viewWillAppear每个视图控制器的方法中设置背景颜色。
这是最终动画的样子:
我希望这有帮助。
| 归档时间: |
|
| 查看次数: |
2044 次 |
| 最近记录: |