IOS/Objective-C:与 Show Segue 相比,自定义 Segue 对导航栏的影响 [英] IOS/Objective-C: Custom Segue Effect on Navigation Bar Compared with Show Segue

查看:35
本文介绍了IOS/Objective-C:与 Show Segue 相比,自定义 Segue 对导航栏的影响的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个视图控制器,我使用常规的 Show Segue(从右到左)向一个方向前进,并使用自定义 segue(从左到右)向另一个方向前进.我不认为我应该放松一下,因为 VC 都不从属于另一个,并且使用这些 segue 意味着一个导航控制器可以管理事物.

I have two view controllers where I use a regular Show Segue (Right to Left) to go in one direction and a custom segue (Left to Right) to go in the other direction. I don't think I should do an unwind because neither VC is subordinate to other and using these segues means one navigation controller manages things.

在两个 VC 的左上角,我有一个包含个人资料照片的公共 BarButton.

In the upper left hand corner of both VCs I have a common BarButton containing a profile photo.

使用常规的从右到左转场时,栏按钮上的个人资料照片保持不变.当屏幕的其余部分移入时,这看起来很棒,但两者共有的元素,个人资料照片保持原位.

When using the regular Right to Left Segue, the profile photo on the bar button remains unchanged. This looks great as the rest of the screen moves in but the element common to both, the profile photo stays in place.

在另一个方向(从左到右),然而,使用自定义转场,包括导航栏在内的整个 VC 屏幕突然出现,您基本上会看到个人资料照片从左边缘进入,然后停留在正常的左栏中同一张照片之前的按钮位置.这看起来很糟糕.

In the other direction (Left to Right), however, using the custom segue, the entire VC screen including the navigation bar swoops in and you basically see the profile photo come in from the left edge before resting in the normal left bar button position where the same photo was a moment earlier. This looks bad.

有什么方法可以强制导航栏中的公共元素在自定义转场期间保持原位,以更好地模仿系统显示转场的行为?

Is there any way to force a common element in the navigation bar to stay in place during a custom segue to better mimic the behavior of the system show segue?

预先感谢您的任何建议.

Thanks in advance for any suggestions.

这是我的自定义转场代码:

Here is my code for the custom segue:

#import "customSegue.h"
#import "QuartzCore/QuartzCore.h"

@implementation customSegue

-(void)perform {

    UIViewController *destinationController = (UIViewController*)[self destinationViewController];

    UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
    CGFloat animationDuration = .40;  
    transition.duration = animationDuration;
    transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
    transition.type = kCATransitionMoveIn;  
    transition.subtype = kCATransitionFromLeft;  

    [sourceViewController.navigationController.view.layer addAnimation:transition
                                                                forKey:kCATransition];

    UIColor *previousWindowBackgroundColor = sourceViewController.view.window.backgroundColor;

    sourceViewController.view.window.backgroundColor = destinationController.view.backgroundColor;


    [sourceViewController.navigationController pushViewController:destinationController animated:NO];
    // switch the window color back after the transition duration from above
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(animationDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // make sure we still have a handle on the destination controller
        if (destinationController) {
            destinationController.view.window.backgroundColor = previousWindowBackgroundColor;
        }
    });

}

@end

推荐答案

你好@user6631314

Hello again @user6631314

我认为您不会通过使用 CATransition 应用并将其附加到 navigationController 视图层来获得您想要的.

I don't think you're going to get what you want by applying using a CATransition and attaching it to the navigationController view's layer.

相反,我建议将presentingViewController 设为UINavigationController 的委托,并为LTR 推送滚动您自己的逻辑(导航栏会更流畅,您不必再担心过渡期间出现的黑条我之前的回复帮助您解决/解决方法).

Instead I would recommend making the presentingViewController a delegate for UINavigationController and rolling your own logic for the LTR push (it will be a lot smoother with the navigation bar and you should no longer have to worry about that black bar during the transition that my previous response helped you resolve/workaround).

为此,您需要将呈现视图控制器(或某些协调器视图控制器)设置为 UINavigationControllerDelegate 并实现此方法:

So to do this you'll need to set the presenting view controller (or some coordinator view controller) to be the UINavigationControllerDelegate and implement this method:

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                  animationControllerForOperation:(UINavigationControllerOperation)operation
                                               fromViewController:(UIViewController*)fromVC
                                                 toViewController:(UIViewController*)toVC

在该方法中,您需要检查操作是否为 UINavigationControllerOperationPush,如果是,则返回符合 UIViewControllerAnimatedTransitioning 协议的 NSObject 子类(否则返回 nil以允许所有其他导航操作成为标准).在该类中,您将处理自定义导航控制器推送动画覆盖.

Within that method you'll want to check if the operation is a UINavigationControllerOperationPush and if so return a subclass of NSObject that conforms to the UIViewControllerAnimatedTransitioning protocol (otherwise return nil to allow all other navigation operations to be standard). Within that class will be where you handle the custom navigation controller push animation override.

LTR 推送动画的基本逻辑是,您希望从屏幕左侧开始 toView,然后将其设置为动画,使其在您的动画持续时间(代码为 0.4)后完全显示在屏幕上——因此启动x 位置偏移到视图宽度的负值(因此它完全在屏幕外)然后在动画期间将 x 位置设置为 0(或者您可以 += 视图的宽度).

The basic logic for the LTR push animation is that you want to start the toView off the screen to the left, then animate it in so that it's completely onscreen after your animation duration (0.4 from your code) -- therefore start the x position offset to the negative value of the view's width (so it's completely offscreen) then during the animation set the x position to 0 (or you could just += the view's width).

以下是当前自定义 segue 实现的示例(请注意导航栏也会滑过,这是您在此处发布的问题):

Here's the example of what the current custom segue implementation looks like (notice the navigation bar slides over as well, which is the issue you're posting about here):

以及使用自定义动画控制器的过渡:

And the transition by using the custom animation controller:

完整代码如下:

#import "ViewController.h"
#import "LTRPushAnimator.h"

@interface ViewController () < UINavigationControllerDelegate>
@property (strong, nullable) UIView *profileView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.navigationController.delegate = self;
    self.navigationItem.hidesBackButton = YES;
    self.profileView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
    UIImageView *profileImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Homer.jpg"]];
    [profileImageView setFrame:CGRectMake(0, 0, 40, 40)];
    profileImageView.layer.cornerRadius = 20.0f;
    profileImageView.layer.masksToBounds = YES;
    profileImageView.clipsToBounds = YES;
    profileImageView.layer.borderColor = [UIColor blackColor].CGColor;
    profileImageView.layer.borderWidth = 1.0f;
    [self.profileView addSubview:profileImageView];
    UIBarButtonItem *lbi = [[UIBarButtonItem alloc] initWithCustomView:self.profileView];
    self.navigationItem.leftBarButtonItem = lbi;
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
}

- (IBAction)pushFakeViewController:(id)sender {
    UIViewController *fakeViewController = [[UIViewController alloc] init];
    fakeViewController.view.backgroundColor = [UIColor redColor];
    UIBarButtonItem *lbi = [[UIBarButtonItem alloc] initWithCustomView:self.profileView];
    fakeViewController.navigationItem.leftBarButtonItem = lbi;
    fakeViewController.navigationItem.hidesBackButton = YES;
    [self.navigationController pushViewController:fakeViewController animated:YES];
    // this is just in here to pop back to the root view controller since we removed the back button, it can be removed obviously
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.navigationController popViewControllerAnimated:YES];
    });
}

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                  animationControllerForOperation:(UINavigationControllerOperation)operation
                                               fromViewController:(UIViewController*)fromVC
                                                 toViewController:(UIViewController*)toVC
{
    if (operation == UINavigationControllerOperationPush) {
        return [[LTRPushAnimator alloc] init];
    }
    // otherwise standard animation
    return nil;
}

@end

LTRPushAnimator.h

LTRPushAnimator.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface LTRPushAnimator : NSObject <UIViewControllerAnimatedTransitioning>

@end

NS_ASSUME_NONNULL_END

LTRPushAnimator.m

LTRPushAnimator.m

#import "LTRPushAnimator.h"

@implementation LTRPushAnimator

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
    return 0.4;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    [self _animatePushByFrameWithContext:transitionContext];
}

- (void)_animatePushByFrameWithContext:(id<UIViewControllerContextTransitioning>)transitionContext {
    UIViewController *toViewController   = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    CGRect toVCFrame = toViewController.view.frame;
    CGFloat viewWidth = toVCFrame.size.width;
    toVCFrame.origin.x -= viewWidth;
    [toViewController.view setFrame:toVCFrame];
    [[transitionContext containerView] addSubview:toViewController.view];
    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        CGRect finalVCFrame = toViewController.view.frame;
        finalVCFrame.origin.x = 0;
        [toViewController.view setFrame:finalVCFrame];
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
}

@end

这篇关于IOS/Objective-C:与 Show Segue 相比,自定义 Segue 对导航栏的影响的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆