我正在使用标签栏驱动的应用程序中以编程方式切换标签UITabBarController.selectedIndex
。我要解决的问题是如何为视图之间的过渡设置动画。即。从当前选项卡的视图到所选选项卡的视图。
首先想到的是利用UITabBarControllerDelegate
,但是似乎在以编程方式切换选项卡时未调用此方法。我现在正在考虑将UITabBarDelegate.didSelectItem
:作为设置过渡动画的可能钩子。
有没有人设法使过渡动画?如果是,怎么办?
我正在使用标签栏驱动的应用程序中以编程方式切换标签UITabBarController.selectedIndex
。我要解决的问题是如何为视图之间的过渡设置动画。即。从当前选项卡的视图到所选选项卡的视图。
首先想到的是利用UITabBarControllerDelegate
,但是似乎在以编程方式切换选项卡时未调用此方法。我现在正在考虑将UITabBarDelegate.didSelectItem
:作为设置过渡动画的可能钩子。
有没有人设法使过渡动画?如果是,怎么办?
Answers:
更新04/2016: Justed想更新此内容,对所有人的所有投票表示感谢。另请注意,这最初是在... ARC之前,约束之前,...之前写的。因此,在决定是否使用这些技术时,请考虑到这一点。可能会有更多现代方法。哦,如果找到一个。请添加回复,以便所有人都能看到。谢谢。
一段时间以后 ...
经过大量研究,我提出了两个可行的解决方案。这两个选项在标签之间都起作用并且起作用。
解决方案1:从视图过渡(简单)
这是最简单的方法,并且使用了预定义的UIView过渡方法。使用此解决方案,我们不需要管理视图,因为该方法可以为我们完成工作。
// 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:滚动(更复杂)
一个更复杂的解决方案,但可以让您更好地控制动画。在此示例中,我们可以打开和关闭视图。对于这一点,我们需要自己管理视图。
// 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中的此解决方案:
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
}
}
shouldSelectViewController
方法中,并在此返回NO
以下是我尝试使用代码形式drekka到委托(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;
}
我的iOS7.0或更高版本的解决方案。
您可以在标签栏的委托中指定自定义动画控制器。
实现一个动画控制器,如下所示:
@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
然后在您的UITabBarControllerDelegate中使用它:
- (id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
animationControllerForTransitionFromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
return [[TabSwitchAnimationController alloc] init];
}
代替使用tabBarController:shouldSelectViewController:
更好地实现tabBarController: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()
}
}
我认为您可以使用CATransition轻松实现UITabBarControlelr的转换;这还将解决使用transitionFromView:toView的任何副作用:
在自UITabBarController扩展的自定义TabBarController类中使用此函数。
- (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"];
}
希望这可以帮助 :)
我在这里尝试各种答案后写了一篇文章。
代码在Swift中,您可以通过调用来以动画方式更改标签页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
})
}
如果您希望所有选项卡更改都具有动画,请UITabBarControllerDelegate
像这样将其钩住:
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
}
我在Swift中的解决方案:
创建自定义TabBar类并将其设置在故事板TabBar中
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
}
}
finished
错误)。我不知道为什么会这样,但是我认为这与CA转换有关,后者认为“没有动画效果”。我转而使用框架动画,效果很好。
我使用@Mofumofu的解决方案并将其升级到Swift 1.2,还实现了上/下动画。意思是,如果新的ViewController的索引大于旧的ViewController的索引,则出现新的ViewController并向上推旧的ViewController。否则,方向朝下。
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
})
}
}
}
在容器ViewController中:
extension XYViewController: UITabBarControllerDelegate {
func tabBarController(tabBarController: UITabBarController, animationControllerForTransitionFromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return TabScrollPageAnimationController(tabBarController: tabBarController)
}
}
这是我的Swift 3解决方案:
我像这样重写UITabBarViewController的selectedIndex:
override var selectedIndex: Int{
get{
return super.selectedIndex
}
set{
animateToTab(toIndex: newValue)
super.selectedIndex = newValue
}
}
然后,我使用模仿本地推送/弹出动画的此函数:
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
})
}
希望对您有所帮助:)
这可以通过两种方式解决
1-将其一次写入您的AppDelegate.m文件中。切记在AppDelegate.h中在冒号(:)后使用<>包括UITabBarControllerDelegate。
-(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-将其写入每个ViewController.m文件中
-(void)viewWillAppear:(BOOL)animated
{
[UIView transitionWithView:self.view
duration:1.0
options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionTransitionCrossDissolve
animations:^(void){
[super viewWillAppear:YES];
} completion:^(BOOL finished){
}];
}
希望这个帮助...!
您可以根据所点击的项目进行动画处理-在本示例中,如果所点击的索引>大于上一个选定索引,则我们将执行flipFromLeft;如果所创建的索引小于先前选择的索引,则我们将对flipFromRight进行动画处理。这是Swift 4:实现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
}
drekka的回答确实很棒。我稍微调整了滚动过渡,使动画看起来更像苹果的推式动画。我在第一个动画完成时添加了一个附加动画,以使滑动效果看起来正确。
// 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;
}
}];
}
}];
我想在按下按钮时在两个子视图控制器之间使用一个翻转过渡,并实现如下:
-(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];
}
我还将背景颜色设置为黑色,在我的情况下,我通过设置navigationController.view.backgroundColor做到了这一点,但在您的情况下,它可能是window.backgroundColor,可以在应用程序委托中轻松设置。
这是我的工作代码(用于3个标签,还没有在更多标签上尝试过!!)来制作标签之间的过渡动画。它主要基于drekka的解决方案,但是已经在选项卡的委托方法中实现,因此如果您仅复制/粘贴它,它就可以完成工作。(您永远不知道!)
-(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;
}
这在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
}
@samwize答案翻译为Swift 3-2 竖起大拇指,创建了从左到右的页面效果:
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
})
}
@samwize的答案已针对Swift 5更新:
如果希望所有选项卡更改都具有动画,请使用UITabBarControllerDelegate并实现此方法:
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
}
通过调用以动画方式以编程方式更改选项卡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
})
}
你的UITabBarControllerDelegate
方法应该是这样的,
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
animateToTab(toIndex: (tabBarController.viewControllers?.index(of: viewController))!)
return true
}
方法是
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
});
}