iPhone: Bagaimana cara mengganti tab dengan animasi?

106

Saya beralih tab secara terprogram dalam aplikasi yang digerakkan bilah tab menggunakan UITabBarController.selectedIndex. Masalah yang saya coba selesaikan adalah bagaimana menganimasikan transisi antar tampilan. yaitu. dari tampilan tab saat ini ke tampilan tab yang dipilih.

Pikiran pertama adalah memanfaatkan UITabBarControllerDelegate, tetapi tampaknya ini tidak dipanggil saat berpindah tab secara terprogram. Saya sekarang sedang mempertimbangkan UITabBarDelegate.didSelectItem: sebagai pengait yang mungkin untuk mengatur animasi transisi.

Adakah yang berhasil menghidupkan transisi? Jika ya, bagaimana caranya?

drekka
sumber
1
FWIW, banyak dari jawaban yang sangat dipilih ini mendahului transisi khusus yang diuraikan dalam jawaban Runo dan juga Heberti . Itu adalah cara yang tepat untuk menangani animasi khusus ini. Lihat video WWDC 2013 Transisi Kustom Menggunakan View Controllers .
Rob

Jawaban:

154

Pembaruan 04/2016: Justed ingin memperbarui ini untuk mengucapkan terima kasih kepada semua orang untuk semua suara. Harap perhatikan juga bahwa ini awalnya ditulis jauh kembali ketika ... sebelum ARC, sebelum kendala, sebelumnya ... banyak hal! Jadi harap pertimbangkan hal ini saat memutuskan apakah akan menggunakan teknik ini. Mungkin ada pendekatan yang lebih modern. Oh, dan jika Anda menemukannya. Harap tambahkan tanggapan agar semua orang dapat melihat. Terima kasih.

Suatu saat nanti ...

Setelah banyak penelitian, saya menemukan dua solusi yang berfungsi. Keduanya bekerja dan melakukan animasi antar tab.

Solusi 1: Transisi dari tampilan (sederhana)

Ini adalah yang termudah dan menggunakan metode transisi UIView yang telah ditentukan sebelumnya. Dengan solusi ini, kami tidak perlu mengelola tampilan karena metode yang berfungsi untuk kami.

// Get views. controllerIndex is passed in as the controller we want to go to. 
UIView * fromView = tabBarController.selectedViewController.view;
UIView * toView = [[tabBarController.viewControllers objectAtIndex:controllerIndex] view];

// Transition using a page curl.
[UIView transitionFromView:fromView 
                    toView:toView 
                  duration:0.5 
                   options:(controllerIndex > tabBarController.selectedIndex ? UIViewAnimationOptionTransitionCurlUp : UIViewAnimationOptionTransitionCurlDown)
                completion:^(BOOL finished) {
                    if (finished) {
                        tabBarController.selectedIndex = controllerIndex;
                    }
                }];

Solusi 2: Gulir (lebih kompleks)

Solusi yang lebih kompleks, tetapi memberi Anda lebih banyak kontrol atas animasi. Dalam contoh ini kita mendapatkan tampilan untuk meluncur dan mematikan. Dengan yang satu ini kita perlu mengatur sendiri pandangannya.

// Get the views.
UIView * fromView = tabBarController.selectedViewController.view;
UIView * toView = [[tabBarController.viewControllers objectAtIndex:controllerIndex] view];

// Get the size of the view area.
CGRect viewSize = fromView.frame;
BOOL scrollRight = controllerIndex > tabBarController.selectedIndex;

// Add the to view to the tab bar view.
[fromView.superview addSubview:toView];

// Position it off screen.
toView.frame = CGRectMake((scrollRight ? 320 : -320), viewSize.origin.y, 320, viewSize.size.height);

[UIView animateWithDuration:0.3 
                 animations: ^{

                     // Animate the views on and off the screen. This will appear to slide.
                     fromView.frame =CGRectMake((scrollRight ? -320 : 320), viewSize.origin.y, 320, viewSize.size.height);
                     toView.frame =CGRectMake(0, viewSize.origin.y, 320, viewSize.size.height);
                 }

                 completion:^(BOOL finished) {
                     if (finished) {

                         // Remove the old view from the tabbar view.
                         [fromView removeFromSuperview];
                         tabBarController.selectedIndex = controllerIndex;                
                     }
                 }];

Solusi ini di Swift:

extension TabViewController: UITabBarControllerDelegate {
      public func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {

           let fromView: UIView = tabBarController.selectedViewController!.view
           let toView  : UIView = viewController.view
           if fromView == toView {
                 return false
           }

           UIView.transitionFromView(fromView, toView: toView, duration: 0.3, options: UIViewAnimationOptions.TransitionCrossDissolve) { (finished:Bool) in

        }
        return true
   }
}
drekka
sumber
1
Terima kasih banyak atas jawabannya, ini bekerja dengan sangat baik. Namun saya menemukan satu bug di kedua solusi, saya tidak yakin apakah ini terjadi pada semua orang, tetapi tampaknya ketika halaman dialihkan, ada celah antara bilah navigasi dan bilah status, lalu setelah animasi selesai, celah tertutup. Ini membuat akhir animasi sedikit gelisah. Tahukah Anda mengapa ini terjadi?
Enrico Susatyo
Hmm, tidak terjadi dengan kode saya. Kedengarannya sangat mirip dengan masalah yang pernah saya lihat sebelumnya di mana posisi bingkai tampilan baru tidak benar dalam kaitannya dengan jendela dan bilah status. Coba jalankan kode kaki untuk bertukar tampilan tanpa melakukan transisi dan lihat apakah itu masih terjadi.
drekka
Ya, itu tetap terjadi tanpa melakukan transisi. Saya mencoba metode pertama. Itu mungkin posisi bingkai, saya akan bermain-main dengannya sedikit lagi. Saya mencoba menggeser bingkai ke atas, dan mencoba mencocokkan bingkai dengan fromView tetapi sejauh ini tidak berhasil ...
Enrico Susatyo
2
@EmileCormier memasukkannya ke dalam metode delegasi TabBar shouldSelectViewControllerdan TIDAK mengembalikannya ke sana
cheesus
2
@drekka ini tidak bekerja untuk saya. dapatkah Anda menjelaskan dari mana asalnya controllerIndex? dan mengapa Anda tidak menggunakan [viewController view] dari metode tabBarControllerDelegate untuk 'toView'? Thnaks
shannoga
25

berikut ini adalah percobaan saya untuk menggunakan formulir kode drekka ke dalam metode delegasi (UITabBarControllerDelegate)

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {

    NSArray *tabViewControllers = tabBarController.viewControllers;
    UIView * fromView = tabBarController.selectedViewController.view;
    UIView * toView = viewController.view;
    if (fromView == toView)
        return false;
    NSUInteger fromIndex = [tabViewControllers indexOfObject:tabBarController.selectedViewController];
    NSUInteger toIndex = [tabViewControllers indexOfObject:viewController];

    [UIView transitionFromView:fromView
                        toView:toView
                      duration:0.3
                       options: toIndex > fromIndex ? UIViewAnimationOptionTransitionFlipFromLeft : UIViewAnimationOptionTransitionFlipFromRight
                    completion:^(BOOL finished) {
                        if (finished) {
                            tabBarController.selectedIndex = toIndex;
                        }
                    }];
    return true;
}
Ryan Wu
sumber
2
Anda harus mengembalikan beberapa nilai sesuai dengan deklarasi metode, tetapi pendekatan ini berfungsi dengan baik +1
voromax
2
Anda dapat mengatur delegasi ke file implementasi UITabController Anda dengan menambahkan self.delegate = self; dalam fungsi viewDidLoad () Anda. Ini akan memungkinkan fungsi di atas dipanggil.
Chris Fremgen
21

Solusi saya untuk iOS7.0 atau lebih tinggi.

Anda dapat menentukan pengontrol animasi khusus di delegasi bilah tab.

Terapkan pengontrol animasi seperti ini:

@interface TabSwitchAnimationController : NSObject <UIViewControllerAnimatedTransitioning>

@end

@implementation TabSwitchAnimationController

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
    return 0.2;
}

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController* fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController* toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView* toView = toVC.view;
    UIView* fromView = fromVC.view;

    UIView* containerView = [transitionContext containerView];
    [containerView addSubview:toView];
    toView.frame = [transitionContext finalFrameForViewController:toVC];

    // Animate by fading
    toView.alpha = 0.0;
    [UIView animateWithDuration:[self transitionDuration:transitionContext]
                          delay:0.0
                        options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction
                     animations:^{
                         toView.alpha = 1.0;
                     }
                     completion:^(BOOL finished) {
                         toView.alpha = 1.0;
                         [fromView removeFromSuperview];
                         [transitionContext completeTransition:YES];
                     }];
}

@end

Kemudian gunakan di UITabBarControllerDelegate Anda:

- (id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
            animationControllerForTransitionFromViewController:(UIViewController *)fromVC
                                              toViewController:(UIViewController *)toVC
{
    return [[TabSwitchAnimationController alloc] init];
}
Runo Sahara
sumber
2
Dan ingat untuk menghubungkan Delegasi Anda ke outlet delegasi TabViewController. Bekerja dengan baik. Solusi terbersih disini.
Andrew Duncan
Bisakah ini dilakukan melalui storyboard dan cepat sekarang setelah saya melihat fitur ini di iOS 10.x?
mobibob
16

Daripada digunakan tabBarController:shouldSelectViewController:lebih baik diimplementasikantabBarController:animationControllerForTransitionFromViewController:toViewController:

TransitioningObject.swift

import UIKit

class TransitioningObject: NSObject, UIViewControllerAnimatedTransitioning {

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        let fromView: UIView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
        let toView: UIView = transitionContext.viewForKey(UITransitionContextToViewKey)!

        transitionContext.containerView().addSubview(fromView)
        transitionContext.containerView().addSubview(toView)

        UIView.transitionFromView(fromView, toView: toView, duration: transitionDuration(transitionContext), options: UIViewAnimationOptions.TransitionCrossDissolve) { finished in
            transitionContext.completeTransition(true)
        }
    }

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
        return 0.25
    }
}

TabBarViewController.swift

import UIKit

    class TabBarViewController: UITabBarController, UITabBarControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.delegate = self
    }

    // MARK: - Tabbar delegate

    func tabBarController(tabBarController: UITabBarController, animationControllerForTransitionFromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return TransitioningObject()
    }
}
Heberti Almeida
sumber
3
Ini sepertinya jawaban terbaik. Tidak ada masalah dengan solusi ini.
sabiland
15

Saya pikir Anda dapat dengan mudah mencapai transisi untuk UITabBarControlelr menggunakan CATransition; Ini juga akan menyelesaikan semua efek samping dari penggunaan transisiFromView: toView:

Gunakan ini di dalam kelas TabBarController kustom Anda yang diperluas dari UITabBarController.

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController (UIViewController*)viewController {

    CATransition *animation = [CATransition animation];
    [animation setType:kCATransitionFade];
    [animation setDuration:0.25];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:
                              kCAMediaTimingFunctionEaseIn]];
    [self.view.window.layer addAnimation:animation forKey:@"fadeTransition"];
}

Semoga ini membantu :)

flopr
sumber
1
saya pikir kita dapat menggunakan "shouldSelectViewController" daripada "didSelectViewController"
Ryan Wu
13

Saya menulis postingan setelah mencoba berbagai jawaban di sini.

Kode ada di Swift, dan Anda dapat mengubah tab secara terprogram dengan animasi dengan memanggil animateToTab.

func animateToTab(toIndex: Int) {
    let tabViewControllers = viewControllers!
    let fromView = selectedViewController!.view
    let toView = tabViewControllers[toIndex].view    
    let fromIndex = tabViewControllers.indexOf(selectedViewController!)

    guard 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.mainScreen().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.userInteractionEnabled = false

    UIView.animateWithDuration(0.5, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: UIViewAnimationOptions.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.userInteractionEnabled = true
        })
}

Jika Anda ingin semua perubahan tab memiliki animasi, kaitkan UITabBarControllerDelegateseperti ini:

func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
    let tabViewControllers = tabBarController.viewControllers!
    guard let toIndex = tabViewControllers.indexOf(viewController) else {
        return false
    }

    // Our method
    animateToTab(toIndex)

    return true
}
samwize
sumber
Ini sangat bersih dan bergerak dengan indah.
Mohammad Zekrallah
9

Solusi saya di Swift:

Buat kelas TabBar kustom dan setel di TabBar storyboard Anda

class MainTabBarController: UITabBarController, UITabBarControllerDelegate {

override func viewDidLoad() {
    super.viewDidLoad()
    self.delegate = self
    // Do any additional setup after loading the view.
}

func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {


    let tabViewControllers = tabBarController.viewControllers!
    let fromView = tabBarController.selectedViewController!.view
    let toView = viewController.view

    if (fromView == toView) {
        return false
    }

    let fromIndex = tabViewControllers.indexOf(tabBarController.selectedViewController!)
    let toIndex = tabViewControllers.indexOf(viewController)

    let offScreenRight = CGAffineTransformMakeTranslation(toView.frame.width, 0)
    let offScreenLeft = CGAffineTransformMakeTranslation(-toView.frame.width, 0)

    // start the toView to the right of the screen


    if (toIndex < fromIndex) {
        toView.transform = offScreenLeft
        fromView.transform = offScreenRight
    } else {
        toView.transform = offScreenRight
        fromView.transform = offScreenLeft
    }

    fromView.tag = 124
    toView.addSubview(fromView)

    self.view.userInteractionEnabled = false
    UIView.animateWithDuration(0.5, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: {

        toView.transform = CGAffineTransformIdentity

        }, completion: { finished in

            let subViews = toView.subviews
            for subview in subViews{
                if (subview.tag == 124) {
                    subview.removeFromSuperview()
                }
            }
            tabBarController.selectedIndex = toIndex!
            self.view.userInteractionEnabled = true

    })

    return true
 }

}
buxik
sumber
this isnt work in ios9 - error dikembalikan dari metode find yaitu Downcast from '[UIViewController]?' untuk '[UIViewController]' hanya membuka bungkus opsional; apakah Anda bermaksud menggunakan '!'?
lozflan
Ini hampir bagus, kecuali saya menemukan bug yang tidak akan beranimasi ( finishedakan salah). Saya tidak tahu mengapa itu terjadi, tapi saya pikir itu ada hubungannya dengan transformasi CA yang menganggap "tidak ada yang dianimasikan". Saya beralih ke animasi dengan bingkai, dan itu berhasil.
samwize
3

Saya menggunakan solusi @ Mofumofu dan memutakhirkannya ke Swift 1.2 dan juga menerapkan animasi naik / turun. Artinya, ViewController baru akan muncul dan mendorong yang lama jika indeks viewcontroller baru lebih besar dari yang lama. Jika tidak, arahnya turun.

class TabScrollPageAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

    let tabBarController: UITabBarController

    init(tabBarController: UITabBarController) {
        self.tabBarController = tabBarController
    }

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
        return 0.5
    }

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        if let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey),
            let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) {
                let fromView = fromVC.view
                let toView = toVC.view

                let containerView = transitionContext.containerView()

                var directionUpwardMultiplier: CGFloat = 1.0
                if let vcs = tabBarController.viewControllers as? [UIViewController],
                    let fIndex = find(vcs, fromVC),
                    let tIndex = find(vcs, toVC) {
                        directionUpwardMultiplier = (fIndex < tIndex) ? +1.0 : -1.0
                }

                containerView.clipsToBounds = false
                containerView.addSubview(toView)

                var fromViewEndFrame = fromView.frame
                fromViewEndFrame.origin.y -= (containerView.frame.height * directionUpwardMultiplier)

                let toViewEndFrame = transitionContext.finalFrameForViewController(toVC)
                var toViewStartFrame = toViewEndFrame
                toViewStartFrame.origin.y += (containerView.frame.height * directionUpwardMultiplier)
                toView.frame = toViewStartFrame

                toView.alpha = 0.0
                UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
                    toView.alpha = 1.0
                    toView.frame = toViewEndFrame
                    fromView.alpha = 0.0
                    fromView.frame = fromViewEndFrame
                }, completion: { (completed) -> Void in
                    toView.alpha = 1.0
                    fromView.removeFromSuperview()
                    transitionContext.completeTransition(completed)
                    containerView.clipsToBounds = true
                })

        }
    }

}

Di Container ViewController:

extension XYViewController: UITabBarControllerDelegate {

    func tabBarController(tabBarController: UITabBarController, animationControllerForTransitionFromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return TabScrollPageAnimationController(tabBarController: tabBarController)
    }

}
Kádi
sumber
3

Ini solusi Swift 3 saya:

Saya mengganti selectedIndex dari UITabBarViewController saya seperti ini:

override var selectedIndex: Int{
    get{
        return super.selectedIndex
    }
    set{
        animateToTab(toIndex: newValue)
        super.selectedIndex = newValue
    }
}

Kemudian saya menggunakan fungsi ini yang meniru animasi push / pop asli:

func animateToTab(toIndex: Int) {
    guard let tabViewControllers = viewControllers, tabViewControllers.count > toIndex, let fromViewController = selectedViewController, let fromIndex = tabViewControllers.index(of: fromViewController), fromIndex != toIndex else {return}

    view.isUserInteractionEnabled = false

    let toViewController = tabViewControllers[toIndex]
    let push = toIndex > fromIndex
    let bounds = UIScreen.main.bounds

    let offScreenCenter = CGPoint(x: fromViewController.view.center.x + bounds.width, y: toViewController.view.center.y)
    let partiallyOffCenter = CGPoint(x: fromViewController.view.center.x - bounds.width*0.25, y: fromViewController.view.center.y)

    if push{
        fromViewController.view.superview?.addSubview(toViewController.view)
        toViewController.view.center = offScreenCenter
    }else{
        fromViewController.view.superview?.insertSubview(toViewController.view, belowSubview: fromViewController.view)
        toViewController.view.center = partiallyOffCenter
    }

    UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .curveEaseIn, animations: {
        toViewController.view.center   = fromViewController.view.center
        fromViewController.view.center = push ? partiallyOffCenter : offScreenCenter
    }, completion: { finished in
        fromViewController.view.removeFromSuperview()
        self.view.isUserInteractionEnabled = true
    })
}

Saya harap ini membantu :)

Nyfa117
sumber
2

perbaikan untuk animasi gelisah ...

UIView * fromView = self.view.superview;

texian
sumber
2

ini dapat diselesaikan dengan dua cara

1 - Tulis ini di file AppDelegate.m Anda sekali. Ingatlah untuk menyertakan UITabBarControllerDelegate menggunakan <> setelah titik dua (:) di AppDelegate.h Anda

-(void)tabBarController:(UITabBarController *)tabBarControllerThis didSelectViewController:(UIViewController *)viewController
{
    [UIView transitionWithView:viewController.view
                      duration:0.1
                       options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionTransitionCrossDissolve
                    animations:^(void){
                    } completion:^(BOOL finished){
                        [UIView beginAnimations:@"animation" context:nil];
                        [UIView setAnimationDuration:0.7];
                        [UIView setAnimationBeginsFromCurrentState:YES];
                        [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
                                               forView:viewController.view
                                                 cache:NO];
                        [UIView commitAnimations];
                    }];
}

2 - Tuliskan ini di setiap file ViewController.m Anda

-(void)viewWillAppear:(BOOL)animated
{
    [UIView transitionWithView:self.view
                      duration:1.0
                       options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionTransitionCrossDissolve
                    animations:^(void){
                        [super viewWillAppear:YES];
                    } completion:^(BOOL finished){
                    }];
}

semoga bantuan ini ...!

burung rajawali
sumber
1
Bagaimana cara menganimasikan transisi antara Pengontrol Navigasi? TabBarControllerDelegate hanya bekerja dengan View Controllers.
saeppi
Saya mencoba keduanya, yang pertama menampilkan tampilan baru dan kemudian menganimasikannya yang terlihat aneh. Yang kedua sepertinya tidak berpengaruh. Saya masuk ke tampilan yang terkait dengan tab2 dan menambahkan kode ke viewWillAppear dan mengujinya dan tidak ada animasi yang terlihat di antara tab.
Shannon Cole
Mencoba yang ini dengan proyek Xcode TabBarController default. Tidak beruntung dengan 1 atau 2. Saya benar-benar ingin mereka berhasil. :) Apakah saya baru saja melewatkan sesuatu?
Andrew Duncan
Saya juga, tidak beruntung .. ada ide?
Jon
2

Anda dapat menganimasikan bergantung pada Item yang disadap - Dalam contoh ini, kita flipFromLeft jika indeks yang disadap> dari indeks yang dipilih sebelumnya dan kita flipFromRight jika indeks yang disadap <dari indeks yang dipilih sebelumnya. Ini adalah Swift 4: Implementasikan metode UITabBarControllerDelegate

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {

    let fromView: UIView = tabBarController.selectedViewController!.view
    let toView: UIView = viewController.view

    if fromView == toView {
        return false
    }

    if let tappedIndex = tabBarController.viewControllers?.index(of: viewController) {
        if tappedIndex > tabBarController.selectedIndex {
            UIView.transition(from: fromView, to: toView, duration: 0.5, options: UIViewAnimationOptions.transitionFlipFromLeft, completion: nil)
        } else {
            UIView.transition(from: fromView, to: toView, duration: 0.5, options: UIViewAnimationOptions.transitionFlipFromRight, completion: nil)
        }
    }
    return true
}
Teetz
sumber
ini tidak bekerja. Saya telah menerapkannya dalam pengontrol tampilan
devedv
@devedv apa yang tidak berfungsi dengan solusi ini? Apakah Anda menyetel UITabBarControllerDelegate ke ViewController Anda?
Teetz
ya saya melakukan hal berikut di kelas AppDelegate AppDelegate: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate {}. Saya baru mengenal cepat bisakah Anda menguraikan langkah-langkah dalam jawaban Anda?
devedv
@devdev Jika ini adalah kelas AppDelegate Anda, letakkan fungsi di atas di AppDelegate Anda dan seharusnya berfungsi
Teetz
1

jawaban drekka sangat bagus. Saya mengubah transisi scroll sedikit sehingga animasinya lebih terlihat seperti animasi push Apple. Saya menambahkan animasi tambahan setelah menyelesaikan animasi pertama agar efek geser terlihat benar.

// Disable interaction during animation to avoids bugs.
self.tabBarController.view.userInteractionEnabled = NO;

// Get the views.
UIView * fromView = tabBarController.selectedViewController.view;
UIView * toView = [[tabBarController.viewControllers objectAtIndex:controllerIndex] view];

// Get the size of the view area.
CGRect viewSize = fromView.frame;
BOOL scrollRight = controllerIndex > tabBarController.selectedIndex;

// Add the to view to the tab bar view.
[fromView.superview addSubview:toView];
[fromView.superview addSubview:fromView];

self.tabBarController.selectedIndex = 0;

// Position it off screen.
toView.frame = CGRectMake((scrollRight ? (viewSize.size.width *.25) : -(viewSize.size.width * .25 )), viewSize.origin.y, viewSize.size.width, viewSize.size.height);

[UIView animateWithDuration:0.25 
             animations: ^{
                 // Animate the views on and off the screen.
                 [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                 fromView.frame = CGRectMake(viewSize.size.width * .95, viewSize.origin.y, viewSize.size.width, viewSize.size.height);
                 toView.frame = CGRectMake((viewSize.origin.x * .90), viewSize.origin.y, viewSize.size.width, viewSize.size.height);
             }

             completion:^(BOOL finished) {
                 if (finished) {
                     // Being new animation.
                     [UIView animateWithDuration:0.2
                                          animations: ^{
                                              [UIView setAnimationCurve:UIViewAnimationCurveLinear];
                                              fromView.frame = CGRectMake(viewSize.size.width, viewSize.origin.y, viewSize.size.width, viewSize.size.height);
                                              toView.frame = CGRectMake((viewSize.origin.x), viewSize.origin.y, viewSize.size.width, viewSize.size.height);
                                          }
                                          completion:^(BOOL finished) {
                                              if (finished) {
                                                  // Remove the old view from the tabbar view.
                                                  [fromView removeFromSuperview];
                                                  // Restore interaction.
                                                  self.tabBarController.view.userInteractionEnabled = YES;
                                              }
                                          }];
                 }
             }];
Terry Tores
sumber
0

Saya ingin menggunakan transisi balik antara dua pengontrol tampilan anak dengan menekan tombol dan mencapainya sebagai berikut:

-(IBAction)flipViewControllers:(id)sender{
    NSUInteger index = self.selectedIndex;
    index++;
    if(index >= self.childViewControllers.count){
        index = 0;
    }

    self.selectedIndex = index;

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.75];
    [UIView setAnimationTransition:index % 2 ? UIViewAnimationTransitionFlipFromLeft : UIViewAnimationTransitionFlipFromRight
                           forView:self.view
                             cache:YES];
    [UIView commitAnimations];
}

Saya juga menyetel warna latar belakang menjadi hitam, dalam kasus saya, saya melakukannya dengan menyetel navigationController.view.backgroundColor tetapi dalam kasus Anda mungkin window.backgroundColor yang dapat dengan mudah disetel di delegasi aplikasi.

malhal
sumber
0

Inilah kode kerja saya ( untuk 3 tab , belum mencobanya lebih !!) untuk menganimasikan transisi antar tab. Ini terutama didasarkan pada solusi drekka, tetapi sudah diimplementasikan dalam metode delegasi tabbar, jadi itu harus melakukan pekerjaan jika Anda hanya menyalin / menempelkannya .. (Anda tidak pernah tahu!)

-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {

// Important! We validate that the selected tab is not the current tab, to avoid misplacing views
if (tabBarController.selectedViewController == viewController) {
    return NO;
}

// Find the selected view's index
NSUInteger controllerIndex = 0;
for (UIViewController *vc in tabBarController.viewControllers) {
    if (vc == viewController) {
        controllerIndex = [tabBarController.viewControllers indexOfObject:vc];
    }
}

CGFloat screenWidth = SCREEN_SIZE.width;

// Note: We must invert the views according to the direction of the scrolling ( FROM Left TO right or FROM right TO left )
UIView * fromView = tabBarController.selectedViewController.view;
UIView * toView = viewController.view;

[fromView.superview addSubview:toView];
CGRect fromViewInitialFrame = fromView.frame;
CGRect fromViewNewframe = fromView.frame;

CGRect toViewInitialFrame = toView.frame;

if ( controllerIndex > tabBarController.selectedIndex ) {
// FROM left TO right ( tab0 to tab1 or tab2 )

    // The final frame for the current view. It will be displaced to the left
    fromViewNewframe.origin.x = -screenWidth;
    // The initial frame for the new view. It will be displaced to the left
    toViewInitialFrame.origin.x = screenWidth;
    toView.frame = toViewInitialFrame;

} else {
// FROM right TO left ( tab2 to tab1 or tab0 )

    // The final frame for the current view. It will be displaced to the right
    fromViewNewframe.origin.x = screenWidth;
    // The initial frame for the new view. It will be displaced to the right
    toViewInitialFrame.origin.x = -screenWidth;
    toView.frame = toViewInitialFrame;
}

[UIView animateWithDuration:0.2 animations:^{
    // The new view will be placed where the initial view was placed
    toView.frame = fromViewInitialFrame;
    // The initial view will be place outside the screen bounds
    fromView.frame = fromViewNewframe;

    tabBarController.selectedIndex = controllerIndex;

    // To prevent user interaction during the animation
    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];

} completion:^(BOOL finished) {

    // Before removing the initial view, we adjust its frame to avoid visual lags
    fromView.frame = CGRectMake(0, 0, fromView.frame.size.width, fromView.frame.size.height);
    [fromView removeFromSuperview];

    [[UIApplication sharedApplication] endIgnoringInteractionEvents];
}];

return NO;

}

Nahuel Roldan
sumber
Meskipun cuplikan kode ini dapat menyelesaikan pertanyaan, menyertakan penjelasan sangat membantu meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa mendatang, dan orang-orang itu mungkin tidak tahu alasan saran kode Anda.
Ferrybig
Terima kasih atas tipnya, Ferrybig! Saya memang mencoba untuk mendokumentasikan kode sebanyak mungkin untuk membuatnya lebih mudah dipahami, semoga membantu
Nahuel Roldan
0

Ini berfungsi untuk saya di Swift 3:

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {

    if let fromView = tabBarController.selectedViewController?.view, let toView = viewController.view {

        if fromView == toView {
            return false
        }

        UIView.transition(from: fromView, to: toView, duration: 0.2, options: .transitionCrossDissolve) { (finished) in
        }
    }

    return true
}
Benang Pitt
sumber
0

@samwize Jawaban diterjemahkan ke Swift 3 - 2 jempol yang satu ini, menciptakan efek halaman kiri ke wright:

func animateToTab(toIndex: Int) {
        let tabViewControllers = viewControllers!
        let fromView = selectedViewController!.view
        let toView = tabViewControllers[toIndex].view
        let fromIndex = tabViewControllers.index(of: selectedViewController!)

        guard 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 = screenSize.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.5, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: UIViewAnimationOptions.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
        })
    }
skyguy
sumber
0

Jawaban @ samwize diperbarui untuk Swift 5:

Jika Anda ingin semua perubahan tab memiliki animasi, gunakan UITabBarControllerDelegate dan terapkan metode ini:

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
  let tabViewControllers = tabBarController.viewControllers!
  guard let toIndex = tabViewControllers.indexOf(value:viewController) else {
    return false
  }
  animateToTab(toIndex: toIndex, fadeOutFromView: false, fadeInToView: false)
  return true
}

Ubah tab secara terprogram dengan animasi dengan memanggil animateToTab:

func animateToTab(toIndex: Int, fadeOutFromView: Bool, fadeInToView: Bool) {
  let tabViewControllers = viewControllers!
  let fromView = selectedViewController!.view
  let toView = tabViewControllers[toIndex].view
  let fromIndex = tabViewControllers.indexOf(value:selectedViewController!)
  guard 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.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
  if fadeInToView {
    toView!.alpha = 0.1
  }

  UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: [.curveEaseOut], animations: {

    if fadeOutFromView {
      fromView!.alpha = 0.0
    }

    if fadeInToView {
      toView!.alpha = 1.0
    }

    // 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
  })
}
spnkr.dll
sumber
-2

Cepat 4+

UITabBarControllerDelegateMetode Anda harus seperti ini,

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {

    animateToTab(toIndex: (tabBarController.viewControllers?.index(of: viewController))!)
    return true
}

Dan metodenya adalah,

func animateToTab(toIndex: Int) {
    let tabViewControllers = viewControllers!
    let fromView = selectedViewController!.view
    let toView = tabViewControllers[toIndex].view
    let fromIndex = tabViewControllers.index(of: selectedViewController!)

    guard 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.5, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: UIViewAnimationOptions.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
    });

}
Zumry Mohamed
sumber