iOS Implementation Navigation Bar Transparent Sample Code

  • 2021-12-12 10:02:50
  • OfStack

I encountered such a scenario in a recent project, Set navigation bar transparency on 1 page that is entered by push. And requires control to hover the head view of tableview group, nav varies in transparency with the tableview offset, Of course, this requirement is not difficult, but if the current page continues with push1 pages that do not need such effects, a pit will appear when returning to the current page, and the display of nav is very abrupt. The following is a direct solution... ps: Suppose A pages need to be transparent, and B pages are Apush and do not need to be transparent

First, write in viewDidload of the page where the navigation bar needs to be transparent


self.title = @"Title";
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
  self.navigationController.navigationBar.shadowImage = [UIImage new];
  self.barImageView = self.navigationController.navigationBar.subviews.firstObject;
  self.barImageView.alpha = 0;
  // Set the status bar 
  [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
  // Set the title color 
  self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor clearColor]};

In the scrollViewDidScroll proxy method


-(void)scrollViewDidScroll:(UIScrollView *)scrollView {

  CGFloat offset = scrollView.contentOffset.y;
  // Set according to your own needs (136) The size of 
  CGFloat alpha = offset / 136;
  _barImageView.alpha = alpha;
  // Record the current transparency , To return to the current page 
  _alpha = alpha;
  [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithFloat:alpha] forKey:@"_alpha"];
  // Set the transparency of the title 
  self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor colorWithWhite:0 alpha:alpha]};
}

viewWillAppear, viewDidAppear, viewWillDisappear of the current page


-(void)viewWillAppear:(BOOL)animated
{

  [super viewWillAppear:animated];
  self.table.delegate = self;

}

-(void)viewDidAppear:(BOOL)animated {
  BOOL isGesturePop = [[[NSUserDefaults standardUserDefaults] objectForKey:@"isGesturePop"] boolValue];
  if (!isGesturePop) {
    _barImageView.alpha = _alpha;
    self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor colorWithWhite:0 alpha:_alpha]};
  }
  [super viewDidAppear:animated];
}

-(void)viewWillDisappear:(BOOL)animated
{
  [super viewWillDisappear:animated];
  self.table.delegate = nil;
  self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor blackColor]};

  _barImageView.alpha = 1;
  [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:@"isGesturePop"];
}

So we need push next 1 page need what operation, we need to show the normal nav in this page and ban the system gesture pop, write one pop gesture, in order to facilitate us to get the pop sliding offset, in the time of doing two classes, in the end there will be source posted

B. m must comply with UIGestureRecognizerDelegate and import NavigationInteractiveTransition. h

Global variable


@property (nonatomic, strong) NavigationInteractiveTransition *navT;

viewDidLoad


self.navigationController.interactivePopGestureRecognizer.enabled = NO;

  UIGestureRecognizer *gesture = self.navigationController.interactivePopGestureRecognizer;
  gesture.enabled = NO;
  UIView *gestureView = gesture.view;

  UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] init];
  popRecognizer.delegate = self;
  popRecognizer.maximumNumberOfTouches = 1;
  [gestureView addGestureRecognizer:popRecognizer];

  _navT = [[NavigationInteractiveTransition alloc] initWithViewController:self.navigationController];
  [popRecognizer addTarget:_navT action:@selector(handleControllerPop:)];

UIGestureRecognizerDelegate proxy method gestureRecognizerShouldBegin


- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
  // Record whether it is currently sliding back through gestures 
  [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:@"isGesturePop"];
  /**
   *  There are two conditions that do not allow gestures to be executed. 1 The current controller is the root controller; 2 If this push , pop Animation is executing (private property) 
   */
  return self.navigationController.viewControllers.count != 1 && ![[self.navigationController valueForKey:@"_isTransitioning"] boolValue];
}

Two class source codes that need to be dependent on

NavigationInteractiveTransition.h


#import <UIKit/UIKit.h>

@class UIViewController, UIPercentDrivenInteractiveTransition;
@interface NavigationInteractiveTransition : NSObject <UINavigationControllerDelegate>
- (instancetype)initWithViewController:(UIViewController *)vc;
- (void)handleControllerPop:(UIPanGestureRecognizer *)recognizer;
- (UIPercentDrivenInteractiveTransition *)interactivePopTransition;
@end

NavigationInteractiveTransition.m


#import "NavigationInteractiveTransition.h"
#import "PopAnimation.h"

@interface NavigationInteractiveTransition ()
@property (nonatomic, weak) UINavigationController *vc;
@property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactivePopTransition;
@property(nonatomic, strong) UIImageView *barImageView;
@end

@implementation NavigationInteractiveTransition

- (instancetype)initWithViewController:(UIViewController *)vc
{
  self = [super init];
  if (self) {
    self.vc = (UINavigationController *)vc;
    self.vc.delegate = self;
  }
  return self;
}

/**
 *  We put every user's Pan Gesture operation as 1 Times pop Execution of animation 
 */
- (void)handleControllerPop:(UIPanGestureRecognizer *)recognizer {
  /**
   * interactivePopTransition That's the way we talk about it 2 Returned object, we need to update its progress to control Pop For the animation process, we use the position of the finger in the view and the ratio of the width of the view as its progress. 
   */
  CGFloat progress = [recognizer translationInView:recognizer.view].x / recognizer.view.bounds.size.width;
  [self.vc.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
  self.vc.navigationBar.shadowImage = [UIImage new];
  self.barImageView = self.vc.navigationBar.subviews.firstObject;

  CGFloat alpha = [[[NSUserDefaults standardUserDefaults] objectForKey:@"_alpha"] floatValue];
  self.barImageView.alpha = 1 - progress > alpha ? alpha : 1 - progress;
//  NSLog(@"===progress==%.2f",progress);
  /**
   *  Stabilize the progress interval and let it be in 0.0 (Incomplete) ~ 1.0 (Completed) 
   */
  progress = MIN(1.0, MAX(0.0, progress));
  if (recognizer.state == UIGestureRecognizerStateBegan) {
    /**
     *  Gesture start, new 1 Monitor objects 
     */
    self.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
    /**
     *  Tell the controller to start executing pop Animation of 
     */
    [self.vc popViewControllerAnimated:YES];
  }
  else if (recognizer.state == UIGestureRecognizerStateChanged) {

    /**
     *  Update the completion progress of gestures 
     */
    [self.interactivePopTransition updateInteractiveTransition:progress];
  }
  else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {

    /**
     *  At the end of the gesture, if the progress is greater than 1 Half, then it's finished pop Operation, or start over. 
     */
    if (progress > 0.5) {
      [self.interactivePopTransition finishInteractiveTransition];
      self.barImageView.alpha = 0;;
    }
    else {
      [self.interactivePopTransition cancelInteractiveTransition];
    }

    self.interactivePopTransition = nil;
  }

}

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                 animationControllerForOperation:(UINavigationControllerOperation)operation
                        fromViewController:(UIViewController *)fromVC
                         toViewController:(UIViewController *)toVC {
  /**
   *  Method 1 If the current execution is Pop Operation, we return our custom Pop Animated object. 
   */
  if (operation == UINavigationControllerOperationPop)
    return [[PopAnimation alloc] init];

  return nil;
}

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
             interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {

  /**
   *  Method 2 Will pass you the current animation object animationController If we customize it, judge Pop Animate the object, then return the interactivePopTransition To monitor animation completion. 
   */
  if ([animationController isKindOfClass:[PopAnimation class]])
    return self.interactivePopTransition;

  return nil;
}

@end

PopAnimation.h


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

@interface PopAnimation : NSObject <UIViewControllerAnimatedTransitioning>

@end

PopAnimation.m


#import "PopAnimation.h"

@interface PopAnimation ()
@property (nonatomic, strong) id <UIViewControllerContextTransitioning> transitionContext;
@end

@implementation PopAnimation

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
  // This method returns the time when the animation was executed 
  return 0.25;
}

/**
 * transitionContext You can think of it as 1 Tools for getting 1 Series animation executes related objects, and notifies the system whether the animation is completed or not. 
 */
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
  /**
   *  Get the controller from which the animation comes 
   */
  UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
  /**
   *  Get the controller to which the transition is made 
   */
  UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

  /**
   *  Transition animation is a time animation of two controller views, which requires 1 A containerView To act as 1 A "stage" for animation execution. 
   */
  UIView *containerView = [transitionContext containerView];
  [containerView insertSubview:toViewController.view belowSubview:fromViewController.view];

  NSTimeInterval duration = [self transitionDuration:transitionContext];

  /**
   *  To perform animation, we let fromVC Move to the far right side of the screen 
   */
  [UIView animateWithDuration:duration animations:^{
    fromViewController.view.transform = CGAffineTransformMakeTranslation([UIScreen mainScreen].bounds.size.width, 0);
  }completion:^(BOOL finished) {
    /**
     *  When your animation is finished, this method must be called, otherwise the system will assume that any of your remaining operations are in the process of animation execution. 
     */
    [transitionContext completeTransition:!transitionContext.transitionWasCancelled];
  }];

}

- (void)animationDidStop:(CATransition *)anim finished:(BOOL)flag {
  [_transitionContext completeTransition:!_transitionContext.transitionWasCancelled];
}
@end


Related articles: