【问题标题】:ViewController slide animationViewController 滑动动画
【发布时间】:2018-12-31 03:09:20
【问题描述】:

我想创建一个类似于 iOS app facebook at tabswitch[1] 的动画。我已经尝试开发某种动画,出现的问题是旧视图控制器直接在开关上变得不可见,而不是在新控制器快速滑入时缓慢淡出。

我发现了这个 SO 问题How to animate Tab bar tab switch with a CrossDissolve slide transition?,但标记为正确的解决方案对我来说并不适用(它不是幻灯片,而是淡入淡出过渡)。我还想获得的是向左或向右滑动以切换标签的功能。就像在旧版本的 facebook 上一样。

到目前为止,我得到的是这样的:

extension TabBarController: UITabBarControllerDelegate  {
    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        guard let fromView = selectedViewController?.view,
              let toView = viewController.view else { return false }
        if fromView != toView {
            toView.transform = CGAffineTransform(translationX: -90, y: 0)
            UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: {
                toView.transform = CGAffineTransform(translationX: 0, y: 0)
            })
        }; return true
    }
}

class TabBarController: UITabBarController {
    override func viewDidLoad() {
        super.viewDidLoad()
        delegate = self
    }
}

如何解决这个问题?


[1] 我非常想从 Facebook 应用程序中添加一个 gif。问题是我不想审查视频而只是透露太多我的数据。 (即使 fb 已经有它们)。同样在 youtube 上,我没有找到合适的录音。请在 iOS 的 fb 应用中自行尝试。

【问题讨论】:

标签: swift facebook animation uiviewcontroller tabbar


【解决方案1】:

你可以使用如下思路:https://samwize.com/2016/04/27/making-tab-bar-slide-when-selected/

另外,这是更新到 Swift 4.1 的代码,我还删除了强制展开:

import UIKit

class MyTabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()

        delegate = self
    }
}

extension MyTabBarController: UITabBarControllerDelegate  {
    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        guard let tabViewControllers = tabBarController.viewControllers, let toIndex = tabViewControllers.index(of: viewController) else {
            return false
        }
        animateToTab(toIndex: toIndex)
        return true
    }

    func animateToTab(toIndex: Int) {
        guard let tabViewControllers = viewControllers,
            let selectedVC = selectedViewController else { return }

        guard let fromView = selectedVC.view,
            let toView = tabViewControllers[toIndex].view,
            let fromIndex = tabViewControllers.index(of: selectedVC),
            fromIndex != toIndex else { return }


        // Add the toView to the tab bar view
        fromView.superview?.addSubview(toView)

        // Position toView off screen (to the left/right of fromView)
        let screenWidth = UIScreen.main.bounds.size.width
        let scrollRight = toIndex > fromIndex
        let offset = (scrollRight ? screenWidth : -screenWidth)
        toView.center = CGPoint(x: fromView.center.x + offset, y: toView.center.y)

        // Disable interaction during animation
        view.isUserInteractionEnabled = false

        UIView.animate(withDuration: 0.3,
                       delay: 0.0,
                       usingSpringWithDamping: 1,
                       initialSpringVelocity: 0,
                       options: .curveEaseOut,
                       animations: {
                        // Slide the views by -offset
                        fromView.center = CGPoint(x: fromView.center.x - offset, y: fromView.center.y)
                        toView.center = CGPoint(x: toView.center.x - offset, y: toView.center.y)

        }, completion: { finished in
            // Remove the old view from the tabbar view.
            fromView.removeFromSuperview()
            self.selectedIndex = toIndex
            self.view.isUserInteractionEnabled = true
        })
    }
}

因此,您需要继承 UITabBarController 并且还必须编写动画部分,您可以调整动画选项(延迟、持续时间等)。

希望对你有帮助,干杯!

【讨论】:

  • 没问题。
  • 哦,是的,我正在阅读其他内容。不知道从我的角度来看,这是否是一个好的 UI/UX,您从 Facebook 应用程序的功能开始,Facebook 应用程序中不存在滑动手势。您应该发布一个新问题,您要求动画...
  • 当过渡发生时,控制器的顶部栏颜色会发生变化,并导致令人讨厌的闪光效果。如何解决?请查看视频drive.google.com/file/d/15mlR9NfV_1C8gwi-4vfpV4CxpXbG5BUm/view
  • @UtkuDalmaz 你可以在 github 或其他地方发布你的代码示例吗?如果我能重现它,我可以调查你的问题。
  • 我已经发布了我的代码。我正在使用您的代码,但后来我将其更改为类似的代码,这里stackoverflow.com/questions/62343102/…您能帮我吗?
【解决方案2】:

我从未见过 Facebook,所以我不知道动画是什么。但是,当标签栏控制器更改其标签(子视图控制器)时,您可以拥有任何您喜欢的动画,连贯并且没有任何黑客,使用 Apple 的内置机制提供将自定义动画添加到视图控制器之间的转换。它被称为自定义过渡动画

Apple 在 2013 年首次引入了这种机制。下面是他们的视频链接:https://developer.apple.com/videos/play/wwdc2013/218/

我立即在我的应用中采用了这一点,我认为这让它们看起来更漂亮。这是我喜欢的标签栏控制器自定义转换的演示:

真正酷的是,一旦你决定了你想要什么动画,让过渡交互式(即用手势而不是点击按钮来驱动它)很容易:

现在,您可能会说:好的,但这并不是我所想的动画。没问题!一旦掌握了自定义过渡架构的窍门,将动画更改为您喜欢的任何内容都很容易。在这个变体中,我只是注释掉了一行,这样“旧”视图控制器就不会滑开:

所以,尽情发挥你的想象力吧!采用 iOS 想要的方式自定义过渡动画。

【讨论】:

【解决方案3】:

如果你想要 pushViewController 导航的东西,你可以试试这个。

但是,在 TabBarController 上的选项卡之间切换时,这将不起作用。为此,我会选择@mihai-erős 的解决方案

根据您的喜好更改动画持续时间,并将此类分配给您的导航 segues,以获得幻灯片动画。

class CustomPushSegue: UIStoryboardSegue {

    override func perform() {
        // first get the source and destination view controllers as UIviews so that they can placed in navigation stack

        let sourceVCView = self.source.view as UIView!
        let destinationVCView = self.destination.view as UIView!
        let screenWidth = UIScreen.main.bounds.size.width

        //create the destination view's rectangular frame i.e starting at 0,0 and equal to screenwidth by screenheight
        destinationVCView?.transform = CGAffineTransform(translationX: screenWidth, y: 0)

        //the destinationview needs to be placed on top(aboveSubView) of source view in the app window stack before being accessed by nav stack
        // get the window and insert destination View
        let window = UIApplication.shared.keyWindow
        window?.insertSubview(destinationVCView!, aboveSubview: sourceVCView!)


        // the animation: first remove the source out of screen by moving it at the left side of it and at the same time place the destination to source's position
        // Animate the transition.
        UIView.animate(withDuration: 0.3, animations: { () -> Void in
            sourceVCView?.transform = CGAffineTransform(translationX: -screenWidth,y: 0)
            destinationVCView?.transform = CGAffineTransform.identity

        }, completion: { (Finished) -> Void in
            self.source.present(self.destination, animated: false, completion: nil)
        }) 
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-26
    • 1970-01-01
    • 2012-03-05
    • 2014-03-05
    • 2012-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多