我正在使用UITabBarController.selectedIndex
在标签栏驱动的应用程序中以编程方式切换标签。我试图解决的问题是如何设置视图之间的过渡动画。即。从当前选项卡的视图到所选选项卡的视图。
首先想到的是使用UITabBarControllerDelegate
,但似乎在编程切换标签时不会调用它。我现在正在考虑UITabBarDelegate.didSelectItem
:作为设置过渡动画的可能钩子。
有没有人设法为过渡设置动画? 如果是,怎么样?
答案 0 :(得分:154)
更新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
}
}
答案 1 :(得分:25)
以下是我尝试将代码格式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;
}
答案 2 :(得分:21)
我的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];
}
答案 3 :(得分:15)
最好不要使用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()
}
}
答案 4 :(得分:14)
我认为您可以使用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"];
}
希望这会有所帮助:)
答案 5 :(得分:13)
我在这里尝试了各种答案后写了post。
代码在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
}
答案 6 :(得分:9)
我在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
}
}
答案 7 :(得分:3)
这是我的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
})
}
我希望它有所帮助:)
答案 8 :(得分:3)
我使用了@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
})
}
}
}
在Container ViewController中:
extension XYViewController: UITabBarControllerDelegate {
func tabBarController(tabBarController: UITabBarController, animationControllerForTransitionFromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return TabScrollPageAnimationController(tabBarController: tabBarController)
}
}
答案 9 :(得分:2)
修复了动画片......
UIView * fromView = self.view.superview;
答案 10 :(得分:2)
您可以根据点按的项目进行动画处理 - 在此示例中,如果点击的索引是&gt;,则我们可以使用flipFromLeft。如果被点击的索引是&lt;而不是之前选择的索引,我们将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
}
答案 11 :(得分:2)
这可以通过两种方式解决
1 - 在AppDelegate.m文件中写一次。请记住使用&lt;&gt;包含UITabBarControllerDelegate在你的AppDelegate.h中冒号(:)之后
-(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){
}];
}
希望这有帮助......!
答案 12 :(得分:1)
// 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;
}
}];
}
}];
答案 13 :(得分:0)
这是我的工作代码( 3个选项卡,还没有尝试过更多!!)来设置选项卡之间的转换动画。它主要基于drekka的解决方案,但已经在tabbar的委托方法中实现,所以如果你只是复制/粘贴它就可以完成工作..(你永远不知道!)
-(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;
}
答案 14 :(得分:0)
我想在按下按钮时在两个子视图控制器之间使用翻转过渡,并按如下方式实现:
-(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,可以在app delegate中轻松设置。
答案 15 :(得分:0)
这适用于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
}
答案 16 :(得分:0)
@samwize答案翻译为 Swift 3 - 在这一个上竖起大拇指,创建一个左到右页面效果:
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
})
}
答案 17 :(得分:0)
@samwize's answer已针对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
})
}
答案 18 :(得分:-2)
你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
});
}