iPhone: Animasyonlu sekmeler arasında nasıl geçiş yapılır?


106

Kullanarak sekme çubuğuyla çalışan bir uygulamada programlı olarak sekmeleri değiştiriyorum UITabBarController.selectedIndex. Çözmeye çalıştığım sorun, görünümler arasındaki geçişin nasıl canlandırılacağı. yani. geçerli sekmenin görünümünden seçili sekmenin görünümüne.

İlk düşünce, öğesinden yararlanmaktı UITabBarControllerDelegate, ancak görünen o ki, sekmeler arasında programlı olarak geçiş yaparken bu çağrılmıyor. Şimdi şunu düşünüyorum UITabBarDelegate.didSelectItem: bir geçiş animasyonu oluşturmak için olası bir kanca.

Geçişleri canlandırmayı başaran var mı? Varsa nasıl?


1
FWIW, bu yüksek oy alan cevapların çoğu, Runo'nun yanıtı ve Heberti'nin yanıtlarında belirtilen özel geçişlerden önce geliyor . Bunlar, bu özel animasyonların üstesinden gelmenin doğru yolu. Görünüm Denetleyicilerini Kullanarak WWDC 2013 videosuna bakın .
Rob

Yanıtlar:


154

Güncelleme 04/2016: Justed, tüm oylar için herkese teşekkür etmek için bunu güncellemek istedi. Lütfen bunun orijinal olarak ... ARC'den önce, kısıtlamalardan önce, daha önce ... birçok şeyden önce yazıldığına dikkat edin! Bu tekniklerin kullanılıp kullanılmayacağına karar verirken lütfen bunu dikkate alın. Daha modern yaklaşımlar olabilir. Oh, bir tane bulursan. Lütfen herkesin görebilmesi için bir yanıt ekleyin. Teşekkürler.

Bir süre sonra ...

Çok fazla araştırmadan sonra iki çalışma çözümü buldum. Bunların ikisi de çalıştı ve sekmeler arasındaki animasyonu yaptı.

1.Çözüm: Görünümden geçiş (basit)

Bu en kolayıdır ve önceden tanımlanmış bir UIView geçiş yöntemini kullanır. Bu çözümle görünümleri yönetmemize gerek yok çünkü yöntem bizim için çalışıyor.

// 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;
                    }
                }];

2.Çözüm: Kaydırma (daha karmaşık)

Daha karmaşık bir çözüm, ancak size animasyon üzerinde daha fazla kontrol sağlar. Bu örnekte, görünümlerin kayarak açılıp kapanmasını sağlıyoruz. Bununla görüşleri kendimiz yönetmemiz gerekiyor.

// 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;                
                     }
                 }];

Swift'deki Bu Çözüm:

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
   }
}

1
Cevap için çok teşekkürler, gerçekten işe yarıyor. Ancak her iki çözümde de bir hata buldum, bunun herkesin başına gelip gelmediğinden emin değilim, ancak sayfanın geçişi yapıldığında gezinme çubuğu ile durum çubuğu arasında bir boşluk olduğu ve ardından animasyon bittikten sonra boşluk kapanır. Bu, animasyonun sonunu biraz gergin hale getirir. Bunun neden olduğunu biliyor musunuz?
Enrico Susatyo

Hmm, koduma uymuyordu. Bu, daha önce gördüğüm, pencere ve durum çubuğuyla ilişkili olarak yeni görünüm çerçevesinin konumlandırmasının doğru olmadığı bir soruna çok benziyor. Geçiş yapmadan görünümleri değiştirmek için parmak kodu çalıştırmayı deneyin ve hala devam edip etmediğini görün.
drekka

Evet, yine de bir geçiş yapmadan gerçekleşir. İlk yöntemi denedim. Çerçevenin konumu olabilir, onunla biraz daha oynayacağım. Ben ... çerçeveyi yukarı kayması çalıştı ve fromView ile çerçeve eşleşen çalıştı ama şimdiye kadar hiç şansım yok
Enrico Susatyo

2
@EmileCormier bunu TabBar temsilcisinin shouldSelectViewControlleryöntemine koydu ve
HAYIR'ı

2
@drekka bu benim için çalışmıyor. controllerIndex'in nereden geldiğini açıklayabilir misiniz? ve neden 'toView' için tabBarControllerDelegate yönteminden [viewController görünümü] 'nü kullanmıyorsunuz? Thnaks
shannoga

25

aşağıdaki drekka kod formunu temsilci (UITabBarControllerDelegate) yöntemine kullanma denemem

- (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;
}

2
Yöntem bildirimine göre bir değer döndürmelisiniz, ancak bu yaklaşım güzel çalışıyor +1
voromax

2
Self.delegate = self; ekleyerek temsilciyi UITabController uygulama dosyanıza ayarlayabilirsiniz. viewDidLoad () işlevinizde. Bu, yukarıdaki işlevin çağrılmasına izin verecektir.
Chris Fremgen

21

İOS7.0 veya üstü için çözümüm.

Sekme çubuğunun temsilcisinde özel bir animasyon denetleyicisi belirtebilirsiniz.

Bunun gibi bir animasyon denetleyicisi uygulayın:

@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

Ardından UITabBarControllerDelegate'inizde kullanın:

- (id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
            animationControllerForTransitionFromViewController:(UIViewController *)fromVC
                                              toViewController:(UIViewController *)toVC
{
    return [[TabSwitchAnimationController alloc] init];
}

2
Ve Delegenizi TabViewController'ın temsilci çıkışına bağlamayı unutmayın. Güzelce çalıştı. Buradaki en temiz çözüm.
Andrew Duncan

Bu, film şeridi aracılığıyla yapılabilir ve şimdi IOS 10.x'te bu özelliğe baktığıma göre hızlı olabilir mi?
mobibob

16

Kullanmak yerine tabBarController:shouldSelectViewController:uygulamak daha iyidirtabBarController: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()
    }
}

3
Bu en iyi cevap gibi görünüyor. Bu çözümde sorun yok.
sabiland

15

CATransition kullanarak UITabBarControlelr için kolayca geçiş yapabileceğinizi düşünüyorum; Bu ayrıca transitionFromView: toView kullanmanın yan etkilerini de çözecektir:

Bunu, UITabBarController'dan genişletilmiş özel TabBarController sınıfınızda kullanın.

- (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"];
}

Bu yardımcı olur umarım :)


1
"didSelectViewController" yerine "shouldSelectViewController" kullanabileceğimizi düşünüyorum
Ryan Wu

13

Buradaki çeşitli cevapları denedikten sonra bir yazı yazdım .

Kod Swift'dedir ve sekmeyi arayarak programlı olarak animasyonla değiştirebilirsiniz 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
        })
}

Tüm sekme değişikliklerinin animasyona sahip olmasını istiyorsanız, bunu UITabBarControllerDelegatebeğenmek için bağlayın:

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
}

Bu çok temiz ve güzel bir şekilde hareket ediyor.
Mohammad Zekrallah

9

Swift'deki çözümüm:

Özel TabBar sınıfı oluşturun ve bunu film şeridi TabBar'ınızda ayarlayın

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
 }

}

bu ios9'da çalışmıyor - bulma yönteminden hata döndürüldü, yani '[UIViewController]' dan aşağı yayın? ' '[UIViewController]' yalnızca isteğe bağlı öğeleri açar; '!' kullanmak mı istediniz?
lozflan

Bu neredeyse iyiydi, ancak canlandırılmayacak ( finishedyanlış olacak) bir hatayla karşılaştım . Bunun neden olduğunu bilmiyorum ama bunun "canlandırılacak bir şey olmadığını" düşünen CA dönüşümü ile ilgisi olduğunu düşünüyorum. Çerçevelerle canlandırmaya geçtim ve bu işe yaradı.
samwize

3

@ Mofumofu'nun çözümünü kullandım ve Swift 1.2'ye yükselttim ve ayrıca bir yukarı / aşağı animasyonu uyguladım. Yani, yeni ViewController açılır ve yeni görüntü denetleyicinin indeksi eskisinden daha büyükse eskisini yukarı iter. Aksi takdirde yön aşağıdır.

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
                })

        }
    }

}

Container ViewController'da:

extension XYViewController: UITabBarControllerDelegate {

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

}

3

İşte Swift 3 çözümüm:

UITabBarViewController'ımın selectedIndex'ini şu şekilde geçersiz kılıyorum:

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

Ardından, yerel push / pop animasyonunu taklit eden bu işlevi kullanıyorum:

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
    })
}

Umut ediyorum bu yardım eder :)


2

ürkek animasyon için bir düzeltme ...

UIView * fromView = self.view.superview;


2

bu iki şekilde çözülebilir

1 - Bunu AppDelegate.m dosyanıza bir kez yazın. AppDelegate.h dosyanıza iki nokta üst üste (:) 'den sonra <> kullanarak UITabBarControllerDelegate eklemeyi unutmayın.

-(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 - Bunu ViewController.m dosyanızın her birine yazın

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

umarım bu yardım ...!


1
Gezinme Denetleyicileri arasındaki geçişleri nasıl canlandırabilirim? TabBarControllerDelegate yalnızca Görünüm Denetleyicileri ile çalışır.
saeppi

İkisini de denedim, ilki yeni görünümü gösterdi ve ardından tuhaf görünen onu canlandırdı. İkincisi herhangi bir etkiye sahip görünmüyordu. Tab2 ile ilişkili görünüme girdim ve kodu viewWillAppear'a ekledim ve test ettim ve sekmeler arasında görünür bir animasyon yoktu.
Shannon Cole

Bunu varsayılan Xcode TabBarController projesiyle denedim. 1 ya da 2 ile şans yok. Gerçekten çalışmasını istedim. :) Bir şey mi kaçırıyorum?
Andrew Duncan

Ben de şans yok .. herhangi bir fikrin var mı?
Jon

2

Tıklanan Öğeye bağlı olarak animasyon uygulayabilirsiniz - Bu örnekte, tıklanan dizin önceki seçili dizinden> ise flipFromLeft'i ve tıklanan dizin önceki seçilen dizinden <ise flipFromRight'ı kullanırız. İşte Swift 4: UITabBarControllerDelegate yöntemini uygulayın

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
}

bu çalışmıyor. Bunu görünüm denetleyicisinde uyguladım
devedv

@devedv bu çözümle ne çalışmıyor? UITabBarControllerDelegate'i ViewController'ınıza ayarladınız mı?
Teetz

evet, AppDelegate sınıfı AppDelegate'de şunları yaptım: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate {}. Swift konusunda yeniyim, cevabınızdaki adımları açıklar mısınız lütfen?
devedv

@devdev Bu sizin AppDelegate sınıfınızsa, yukarıdaki işlevi AppDelegate'inize koyun ve çalışmalıdır
Teetz


1

drekka'nın cevabı gerçekten harika. Kaydırma geçişini biraz değiştirdim, böylece animasyon Apple'ın itme animasyonuna benziyordu. İlk animasyonun tamamlanmasının ardından bu kayma efektinin doğru görünmesi için ek bir animasyon ekledim.

// 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;
                                              }
                                          }];
                 }
             }];

0

Bir düğmeye basıldığında iki çocuk görünümü denetleyicisi arasında çevirme geçişi kullanmak istedim ve bunu şu şekilde başardım:

-(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];
}

Ayrıca arka plan rengini siyaha ayarladım, benim durumumda bunu navigationController.view.backgroundColor ayarını yaparak yaptım, ancak sizin durumunuzda, uygulama temsilcisinde kolayca ayarlanabilen window.backgroundColor olabilir.


0

Sekmeler arasındaki geçişleri canlandırmak için çalışma kodum ( 3 sekme için , daha fazla denemedim !!). Esas olarak drekka'nın çözümüne dayanmaktadır, ancak zaten tabbar'ın delege yönteminde uygulanmıştır, bu yüzden sadece kopyalayıp yapıştırırsanız işi yapmalıdır .. (asla bilemezsiniz!)

-(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;

}


Bu kod parçacığı soruyu çözebilirken, bir açıklama eklemek, yayınınızın kalitesini artırmaya gerçekten yardımcı olur. Gelecekte okuyucular için soruyu yanıtladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceklerini unutmayın.
Ferrybig

Ferrybig bahşiş için teşekkürler! Kodu, anlaşılmasını kolaylaştırmak için mümkün olduğunca belgelemeye çalıştım, umarım yardımcı olur
Nahuel Roldan

0

Bu benim için Swift 3'te çalışıyor:

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
}

0

@samwize Cevap Swift'e çevrildi 3 - Bunda 2 beğenme , soldan sağa bir sayfa efekti yaratır:

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
        })
    }

0

@ samwize'nin cevabı Swift 5 için güncellendi:

Tüm sekme değişikliklerinin animasyona sahip olmasını istiyorsanız, bir UITabBarControllerDelegate kullanın ve bu yöntemi uygulayın:

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
}

Aşağıdakileri arayarak sekmeyi animasyonlu programlı olarak değiştirin 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
  })
}

-2

Swift 4+

Sen UITabBarControllerDelegateyöntem, böyle olmalı

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

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

Ve yöntem,

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
    });

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.