Hello again @user6631314
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.
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).
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
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.
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).
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:
Here's the complete code:
#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
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface LTRPushAnimator : NSObject <UIViewControllerAnimatedTransitioning>
@end
NS_ASSUME_NONNULL_END
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