web-dev-qa-db-ja.com

ViewControllerスライドアニメーション

iOSアプリのfacebookのようなアニメーションをtabswitch で作成したい[1]。私はすでにある種のアニメーションを開発しようとしましたが、新しいコントローラーが速くスライドしている間にゆっくりとフェードアウトするのではなく、古いビューコントローラーがスイッチ上で直接非表示になるという問題が発生します。

私はこれを見つけましたSO質問 CrossDissolveスライド遷移でタブバータブスイッチをアニメーション化する方法? しかし、正しいとマークされたソリューションは実際には機能しません(それはスライドではなく、フェードトランジションです。また、スライドを左または右に移動してタブを切り替える機能も必要です。旧バージョンの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アプリでお試しください。

10
user3596335

次のアイデアを使用できます: 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をサブクラス化する必要があり、アニメーションパーツも記述する必要があります。アニメーションオプション(遅延、継続時間など)を微調整できます。

お役に立てば幸いです。

enter image description here

5
Mihai Erős

私はFacebookを見たことがないので、アニメーションが何であるかわかりません。しかし、タブバーコントローラーがそのタブ(子ビューコントローラー)を変更するときにanyアニメーションを好きなように作成できますcoherentlyハックなしで、組み込みメカニズムを使用して= Appleは、ビューコントローラ間のトランジションにカスタムアニメーションを追加できるようにします。これはカスタムトランジションアニメーションと呼ばれます。

Appleはこのメカニズムを2013年に初めて導入しました。これに関するビデオへのリンクは次のとおりです。 https://developer.Apple.com/videos/play/wwdc2013/218/

私はすぐにこれを自分のアプリで採用しました。ここに私が好きなタブバーコントローラーのカスタム遷移のデモがあります:

enter image description here

本当にすばらしいのは、必要なアニメーションを決定したら、トランジションinteractive(つまり、ボタンをクリックする代わりにジェスチャーで操作する)を簡単に実行できることです。

enter image description here

さて、あなたは言っているかもしれません:さて、しかし、それは私が念頭に置いていたアニメーションではありません。問題ない!カスタムトランジションアーキテクチャに慣れたら、アニメーションを好きなように変更するのは簡単です。このバリアントでは、「古い」ビューコントローラがスライドしないように、1行コメントアウトしました。

enter image description here

だからあなたの想像力を暴走させましょう! iOSが意図する方法であるカスタム遷移アニメーションを採用します。

7
matt

PushViewControllerナビゲーションに何か必要な場合は、これを試すことができます。

ただし、TabBarControllerでタブを切り替えると、これは機能しません。そのため、@mihai-erősのソリューションを使用します

スライドアニメーションの場合は、好みに応じてアニメーション期間を変更し、このクラスをナビゲーションセグエに割り当てます。

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)
        }) 
    }
}
2
Kinshuk Kashyap