iPhone: Làm thế nào để chuyển đổi các tab bằng hình ảnh động?


106

Tôi đang chuyển đổi các tab theo chương trình trong một ứng dụng điều khiển thanh tab bằng cách sử dụng UITabBarController.selectedIndex. Vấn đề tôi đang cố gắng giải quyết là làm thế nào để tạo hiệu ứng chuyển đổi giữa các chế độ xem. I E. từ chế độ xem của tab hiện tại sang chế độ xem của tab đã chọn.

Ý tưởng đầu tiên là sử dụng UITabBarControllerDelegate, nhưng có vẻ như điều này không được gọi khi chuyển đổi các tab theo chương trình. Bây giờ tôi đang xem xét UITabBarDelegate.didSelectItem: như một móc có thể để thiết lập hoạt ảnh chuyển tiếp.

Có ai quản lý để tạo hiệu ứng chuyển đổi không? Nếu có, làm thế nào?


1
FWIW, nhiều câu trả lời được bình chọn cao này có trước các chuyển đổi tùy chỉnh được nêu trong câu trả lời của Runocủa Heberti . Đó là cách phù hợp để giải quyết các hoạt ảnh tùy chỉnh này. Xem video WWDC 2013 Chuyển tiếp Tùy chỉnh Sử dụng Bộ điều khiển Chế độ xem .
Rob

Câu trả lời:


154

Cập nhật 04/2016: Justed muốn cập nhật điều này để nói lời cảm ơn đến mọi người vì tất cả các phiếu bầu. Cũng xin lưu ý rằng điều này ban đầu được viết từ khi ... trước ARC, trước các ràng buộc, trước ... rất nhiều thứ! Vì vậy, hãy tính đến điều này khi quyết định có sử dụng các kỹ thuật này hay không. Có thể có nhiều cách tiếp cận hiện đại hơn. Ồ, và nếu bạn tìm thấy. Vui lòng thêm câu trả lời để mọi người có thể xem. Cảm ơn.

Một thời gian sau ...

Sau nhiều nghiên cứu, tôi đã đưa ra hai giải pháp hiệu quả. Cả hai điều này đều hoạt động và tạo hoạt ảnh giữa các tab.

Giải pháp 1: chuyển đổi từ chế độ xem (đơn giản)

Đây là cách dễ nhất và sử dụng phương pháp chuyển tiếp UIView được xác định trước. Với giải pháp này, chúng ta không cần phải quản lý các lượt xem vì phương thức này sẽ làm việc cho chúng ta.

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

Giải pháp 2: cuộn (phức tạp hơn)

Một giải pháp phức tạp hơn, nhưng cung cấp cho bạn nhiều quyền kiểm soát hoạt ảnh hơn. Trong ví dụ này, chúng ta có các chế độ xem để trượt và tắt. Với cái này, chúng ta cần tự quản lý các lượt xem.

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

Giải pháp này trong 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
   }
}

1
Cảm ơn rất nhiều vì câu trả lời, nó hoạt động rất tốt. Tuy nhiên, tôi đã tìm thấy một lỗi trong cả hai giải pháp, tôi không chắc điều này có xảy ra với mọi người hay không, nhưng có vẻ như khi trang được chuyển đổi, có một khoảng cách giữa thanh điều hướng và thanh trạng thái, sau đó sau khi hoạt ảnh kết thúc, khoảng cách thu hẹp. Điều này làm cho phần kết của phim hoạt hình hơi lộn xộn. Bạn có biết tại sao điều này lại xảy ra không?
Enrico Susatyo

Rất tiếc, không xảy ra với mã của tôi. Điều đó nghe có vẻ rất giống một vấn đề mà tôi đã gặp trước đây khi vị trí của khung xem mới không chính xác liên quan đến cửa sổ và thanh trạng thái. Hãy thử chạy mã toe để hoán đổi các lượt xem mà không cần thực hiện chuyển đổi và xem liệu nó có còn xảy ra hay không.
drekka

Đúng, nó vẫn xảy ra mà không cần thực hiện chuyển tiếp. Tôi đã thử phương pháp đầu tiên. Nó có thể là vị trí của khung, tôi sẽ chơi với nó một chút nữa. Tôi đã cố gắng thay đổi các khung hình lên, và cố gắng phù hợp với khung với fromView nhưng không có may mắn cho đến nay ...
Enrico Susatyo

2
@EmileCormier đặt nó trong TabBar đại biểu của shouldSelectViewControllerphương pháp và trở NO có
cheesus

2
@drekka điều này không hiệu quả với tôi. bạn có thể giải thích rằng controllerIndex đến từ đâu? và tại sao bạn không chỉ sử dụng [viewController view] từ phương thức tabBarControllerDelegate cho 'toView'? Thnaks
shannoga

25

sau đây là tôi thử sử dụng dạng mã drekka vào phương thức ủy nhiệm (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;
}

2
Bạn nên trả lại một số giá trị theo phương pháp kê khai, nhưng cách tiếp cận này làm việc thoải mái 1
voromax

2
Bạn có thể đặt ủy quyền cho tệp triển khai UITabController của mình bằng cách thêm self.delegate = self; trong hàm viewDidLoad () của bạn. Điều này sẽ cho phép hàm trên được gọi.
Chris Fremgen

21

Giải pháp của tôi cho iOS7.0 trở lên.

Bạn có thể chỉ định một bộ điều khiển hoạt ảnh tùy chỉnh trong đại biểu của thanh tab.

Triển khai một bộ điều khiển hoạt ảnh như thế này:

@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

Sau đó, sử dụng nó trong UITabBarControllerDelegate của bạn:

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

2
Và hãy nhớ kết nối Đại biểu của bạn với ổ cắm đại biểu của TabViewController. Làm việc đẹp. Giải pháp sạch nhất ở đây.
Andrew Duncan

Điều này có thể được thực hiện thông qua bảng phân cảnh và nhanh chóng bây giờ tôi đang xem xét tính năng này trong IOS 10.x?
mobibob

16

Thay vì sử dụng tabBarController:shouldSelectViewController:là tốt hơn để thực hiệntabBarController:animationControllerForTransitionFromViewController:toViewController:

TransitionObject.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
Đây có vẻ là câu trả lời tốt nhất. Không có vấn đề với giải pháp này.
sabiland

15

Tôi nghĩ rằng bạn có thể dễ dàng đạt được các chuyển đổi cho UITabBarControlelr bằng cách sử dụng CATransition; Điều này cũng sẽ giải quyết bất kỳ tác dụng phụ nào của việc sử dụng transferFromView: toView:

Sử dụng điều này bên trong lớp TabBarController tùy chỉnh của bạn được mở rộng từ 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"];
}

Hi vọng điêu nay co ich :)


1
tôi nghĩ chúng ta có thể sử dụng "shouldSelectViewController" thay vì "didSelectViewController"
Ryan Wu

13

Tôi đã viết một bài sau khi thử các câu trả lời khác nhau ở đây.

Mã này bằng Swift và bạn có thể lập trình thay đổi tab bằng hoạt ảnh bằng cách gọi 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
        })
}

Nếu bạn muốn thay đổi tất cả các tab để có hoạt ảnh, hãy nối nó vào UITabBarControllerDelegatenhư vậy:

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
}

Điều này rất sạch sẽ và hoạt hình đẹp mắt.
Mohammad Zekrallah

9

Giải pháp của tôi trong Swift:

Tạo lớp TabBar tùy chỉnh và đặt nó trong TabBar bảng phân cảnh của bạ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
 }

}

điều này không hoạt động trong ios9 - lỗi trả về từ phương thức tìm, tức là Downcast từ '[UIViewController]?' thành '[UIViewController]' chỉ các tùy chọn mở ra; ý bạn là sử dụng '!'?
lozflan

Điều này gần như tốt, ngoại trừ tôi gặp phải một lỗi sẽ không hoạt ảnh ( finishedsẽ là sai). Tôi không biết tại sao điều đó lại xảy ra, nhưng tôi nghĩ rằng nó liên quan đến sự chuyển đổi CA mà nghĩ rằng không có gì "để hoạt hình". Tôi đã chuyển sang tạo hoạt ảnh với các khung hình và điều đó đã hoạt động.
samwize

3

Tôi đã sử dụng giải pháp của @ Mofumofu và nâng cấp nó lên Swift 1.2 và cũng triển khai hoạt ảnh lên / xuống. Có nghĩa là, ViewController mới xuất hiện và đẩy cái cũ lên nếu chỉ số của viewcontroller mới lớn hơn cái cũ. Nếu không thì hướng đi xuống.

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

        }
    }

}

Trong Container ViewController:

extension XYViewController: UITabBarControllerDelegate {

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

}

3

Đây là giải pháp Swift 3 của tôi:

Tôi ghi đè selectIndex của UITabBarViewController của mình như sau:

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

Sau đó, tôi sử dụng chức năng này để bắt chước hoạt ảnh push / pop gốc:

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

Tôi hy vọng nó sẽ giúp :)



2

điều này có thể được giải quyết theo hai cách

1 - Viết điều này vào tệp AppDelegate.m của bạn một lần. Hãy nhớ bao gồm UITabBarControllerDelegate bằng cách sử dụng <> sau dấu hai chấm (:) trong AppDelegate.h của bạ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 - Viết điều này vào mỗi tệp ViewController.m của bạn

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

hy vọng điều này giúp đỡ...!


1
Làm cách nào để tạo hiệu ứng chuyển đổi giữa các Bộ điều khiển Điều hướng? TabBarControllerDelegate chỉ hoạt động với View Controllers.
saeppi

Tôi đã thử cả hai, cái đầu tiên hiển thị chế độ xem mới và hơn là làm động nó trông kỳ lạ. Cái thứ hai dường như không có bất kỳ ảnh hưởng. Tôi đã vào chế độ xem được liên kết với tab2 và thêm mã vào viewWillAppear và thử nghiệm nó và không có hoạt ảnh hiển thị giữa các tab.
Shannon Cole

Đã thử cái này với dự án Xcode TabBarController mặc định. Không có may mắn với 1 hoặc 2. Tôi thực sự muốn chúng hoạt động. :) Tôi chỉ thiếu một cái gì đó?
Andrew Duncan

Tôi cũng vậy, không có may mắn .. bất kỳ ý tưởng?
Jon

2

Bạn có thể tạo hoạt ảnh tùy thuộc vào Mục được nhấn - Trong ví dụ này, chúng tôi flipFromLeft nếu chỉ mục được nhấn> hơn chỉ mục đã chọn trước đó và chúng tôi flipFromRight nếu chỉ mục được nhấn <so với chỉ mục đã chọn trước đó. Đây là Swift 4: Triển khai phương thức 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
}

đây không phải là làm việc. Tôi đã triển khai nó trong bộ điều khiển chế độ xem
devedv

@devedv điều gì không hoạt động với giải pháp này? Bạn đã đặt UITabBarControllerDelegate thành ViewController của mình chưa?
Teetz

vâng, tôi đã làm như sau trong AppDelegate lớp AppDelegate: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate {}. Tôi mới làm quen với nhanh, bạn có thể giải thích rõ các bước trong câu trả lời của bạn được không?
devedv

@devdev Nếu đây là lớp appdelegate bạn đặt các chức năng trên trong appdelegate của bạn và cần được làm việc
Teetz


1

câu trả lời của drekka thực sự tuyệt vời. Tôi đã điều chỉnh chuyển đổi cuộn một chút để hoạt ảnh trông giống hoạt ảnh đẩy của Apple hơn. Tôi đã thêm một hoạt ảnh bổ sung khi hoàn thành hoạt ảnh đầu tiên để làm cho hiệu ứng trượt đó trông đúng.

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

Tôi muốn sử dụng chuyển đổi lật giữa hai bộ điều khiển chế độ xem trẻ em trên một lần nhấn nút và đạt được nó như sau:

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

Tôi cũng đặt màu nền thành màu đen, trong trường hợp của tôi, tôi đã làm điều đó bằng cách đặt navigationController.view.backgroundColor nhưng trong trường hợp của bạn, nó có thể là window.backgroundColor có thể dễ dàng được đặt trong ứng dụng ủy quyền.


0

Đây là mã làm việc của tôi ( cho 3 tab , chưa thử thêm !!) để tạo hiệu ứng chuyển đổi giữa các tab. Nó chủ yếu dựa trên giải pháp của drekka, nhưng đã được triển khai trong phương thức ủy nhiệm của thanh tab, vì vậy nó sẽ thực hiện công việc nếu bạn chỉ sao chép / dán nó .. (bạn không bao giờ biết!)

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

}


Mặc dù đoạn mã này có thể giải quyết câu hỏi, bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho người đọc trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn.
Ferrybig

Cảm ơn vì tiền boa Ferrybig! Tôi đã cố gắng ghi lại mã nhiều như posible để làm cho nó dễ dàng hơn để undestand nó, hy vọng nó giúp
Nahuel Roldan

0

Điều này phù hợp với tôi trong 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
}

0

@samwize Câu trả lời được dịch sang Swift 3 - 2 không thích câu trả lời này, tạo hiệu ứng trang trái để vặn:

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

Câu trả lời của @ samwize đã được cập nhật cho Swift 5:

Nếu bạn muốn tất cả các thay đổi tab đều có hoạt ảnh, thì hãy sử dụng UITabBarControllerDelegate và triển khai phương pháp này:

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
}

Lập trình thay đổi tab bằng hoạt ảnh bằng cách gọi 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+

Bạn UITabBarControllerDelegatephương pháp nên được như thế này,

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

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

Và phương pháp là,

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

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.