如何在Objective-C中实现MDTabBar滑动切换标签及仿Android视图控制器
Got it, let's walk through how to build swipe-to-switch tabs with MDTabBar in Objective-C, plus that Android-style view controller transition effect you want. I know CarbonKit works really well, but we can replicate that functionality directly on top of Material Components' MDTabBar with these steps:
1. Setup MDTabBar & UIPageViewController
First, we'll pair MDTabBar with a UIPageViewController—this is the core setup for swipeable tab content. Here's how to initialize both components:
Header File (ViewController.h)
#import <UIKit/UIKit.h> #import <MaterialComponents/MaterialTabs.h> @interface ViewController : UIViewController <MDCTabBarDelegate, UIPageViewControllerDataSource, UIPageViewControllerDelegate> @property (nonatomic, strong) MDCTabBar *tabBar; @property (nonatomic, strong) UIPageViewController *pageViewController; @property (nonatomic, strong) NSArray *contentViewControllers; @end
Implementation File (ViewController.m)
Start by initializing your tab items, content view controllers, and adding both components to your main view:
- (void)viewDidLoad { [super viewDidLoad]; // 1. Create your content view controllers self.contentViewControllers = @[ [[UIViewController alloc] init], [[UIViewController alloc] init], [[UIViewController alloc] init] ]; // Add distinct background colors to test transitions ((UIViewController *)self.contentViewControllers[0]).view.backgroundColor = [UIColor systemRedColor]; ((UIViewController *)self.contentViewControllers[1]).view.backgroundColor = [UIColor systemGreenColor]; ((UIViewController *)self.contentViewControllers[2]).view.backgroundColor = [UIColor systemBlueColor]; // 2. Initialize MDTabBar self.tabBar = [[MDCTabBar alloc] initWithFrame:CGRectMake(0, self.view.safeAreaInsets.top, self.view.bounds.size.width, 48)]; self.tabBar.items = @[ [[UITabBarItem alloc] initWithTitle:@"Tab 1" image:nil tag:0], [[UITabBarItem alloc] initWithTitle:@"Tab 2" image:nil tag:1], [[UITabBarItem alloc] initWithTitle:@"Tab 3" image:nil tag:2] ]; self.tabBar.delegate = self; self.tabBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; [self.view addSubview:self.tabBar]; // 3. Initialize UIPageViewController self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil]; self.pageViewController.dataSource = self; self.pageViewController.delegate = self; // Set initial view controller [self.pageViewController setViewControllers:@[self.contentViewControllers[0]] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil]; // Add page view controller to main view [self addChildViewController:self.pageViewController]; [self.view addSubview:self.pageViewController.view]; self.pageViewController.view.frame = CGRectMake(0, CGRectGetMaxY(self.tabBar.frame), self.view.bounds.size.width, self.view.bounds.size.height - CGRectGetMaxY(self.tabBar.frame) - self.view.safeAreaInsets.bottom); self.pageViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self.pageViewController didMoveToParentViewController:self]; }
2. Link Tab Bar and Page View Controller
We need to make sure tapping a tab swipes the page view, and swiping the page updates the tab selection.
Handle Tab Bar Tap Events
Implement the MDCTabBarDelegate method to trigger page transitions:
- (void)tabBar:(MDCTabBar *)tabBar didSelectItemAtIndex:(NSUInteger)index { UIPageViewControllerNavigationDirection direction = index > tabBar.selectedItemIndex ? UIPageViewControllerNavigationDirectionForward : UIPageViewControllerNavigationDirectionReverse; [self.pageViewController setViewControllers:@[self.contentViewControllers[index]] direction:direction animated:YES completion:nil]; }
Handle Page Swipe Events
Update the tab bar when the user swipes between pages using UIPageViewControllerDelegate:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController { NSUInteger index = [self.contentViewControllers indexOfObject:viewController]; return (index > 0) ? self.contentViewControllers[index - 1] : nil; } - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController { NSUInteger index = [self.contentViewControllers indexOfObject:viewController]; return (index < self.contentViewControllers.count - 1) ? self.contentViewControllers[index + 1] : nil; } - (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers transitionCompleted:(BOOL)completed { if (completed) { UIViewController *currentVC = pageViewController.viewControllers.firstObject; NSUInteger currentIndex = [self.contentViewControllers indexOfObject:currentVC]; [self.tabBar setSelectedItemIndex:currentIndex animated:YES]; } }
3. Add Android-Style Transition Animation
The default scroll transition is close, but to match Android's smoother slide effect, we'll create a custom animator:
Custom Transition Animator
Add this helper class to your project:
@interface SlideTransitionAnimator : NSObject <UIViewControllerAnimatedTransitioning> @property (nonatomic, assign) UIPageViewControllerNavigationDirection direction; @end @implementation SlideTransitionAnimator - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext { return 0.35; // Match Android's typical transition speed } - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView *container = transitionContext.containerView; // Set initial frames CGRect containerBounds = container.bounds; toVC.view.frame = CGRectOffset(containerBounds, self.direction == UIPageViewControllerNavigationDirectionForward ? containerBounds.size.width : -containerBounds.size.width, 0); [container addSubview:toVC.view]; // Animate transition [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 usingSpringWithDamping:0.9 initialSpringVelocity:0.8 options:UIViewAnimationOptionCurveEaseInOut animations:^{ fromVC.view.frame = CGRectOffset(containerBounds, self.direction == UIPageViewControllerNavigationDirectionForward ? -containerBounds.size.width : containerBounds.size.width, 0); toVC.view.frame = containerBounds; } completion:^(BOOL finished) { [fromVC.view removeFromSuperview]; [transitionContext completeTransition:finished]; }]; } @end
Attach Animator to Page View Controller
Update your viewDidLoad to set the transition delegate, then implement the delegate method to return your custom animator:
// Add this line in viewDidLoad after initializing pageViewController self.pageViewController.transitionDelegate = self; // Implement UIPageViewControllerTransitionDelegate - (id<UIViewControllerAnimatedTransitioning>)pageViewController:(UIPageViewController *)pageViewController animationControllerForTransitionFromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { SlideTransitionAnimator *animator = [[SlideTransitionAnimator alloc] init]; NSUInteger fromIndex = [self.contentViewControllers indexOfObject:fromVC]; NSUInteger toIndex = [self.contentViewControllers indexOfObject:toVC]; animator.direction = toIndex > fromIndex ? UIPageViewControllerNavigationDirectionForward : UIPageViewControllerNavigationDirectionReverse; return animator; }
4. Polish the Tab Bar Style
Make the tab bar match Material Design guidelines (optional but recommended):
// Add these lines after initializing self.tabBar self.tabBar.selectedItemTintColor = [UIColor systemBlueColor]; self.tabBar.unselectedItemTintColor = [UIColor systemGrayColor]; self.tabBar.indicatorColor = [UIColor systemBlueColor]; self.tabBar.indicatorHeight = 2; self.tabBar.scrollable = YES; // Enable scrolling if you have more than 3 tabs
That's it! This setup will give you swipe-to-switch tabs with MDTabBar, plus a smooth Android-style transition between view controllers—no CarbonKit required.
内容的提问来源于stack exchange,提问作者Vivek

