Implementar una navegación de migas de pan simple

Artículos anteriores

Encuentre imágenes similares en los álbumes de IOS
Conectividad multipar La comunicación multipunto de campo cercano
implementa un simple explorador de archivos sandbox

lograr efecto

Las funciones principales son las siguientes

  • presione la vista, la barra de navegación de migas de pan aumenta automáticamente el elemento de la vista correspondiente

  • Haga clic en el elemento correspondiente de la barra de navegación de migas de pan, salte al texto correspondiente al elemento

  • Cuando el ancho del contenido del elemento de la barra de navegación de las migas de pan es mayor que el ancho de la pantalla actual, la barra de navegación de las migas de pan habilita el modo deslizante y se mueve automáticamente al último elemento para garantizar que el último elemento de la barra de navegación de las migas de pan corresponda a la vista actual.

  • Cuando el ancho del contenido del elemento de la barra de navegación de la ruta de navegación es menor o igual que el ancho de la pantalla actual, la barra de navegación de la ruta de navegación cierra el modo deslizante

El efecto de demostración es el siguiente

Simulador de grabación de pantalla - iPhone 8 - 2021-11-06 at 15.08.45.gif

Proceso de implementación

La implementación se divide principalmente en dos secciones, una es el controlador de navegación de migas de pan y la otra es la barra de navegación de migas de pan.

Controlador de navegación de migas de pan

La versión actual no se ocupa de la función de retorno de deslizamiento lateral de UINavigationController, por lo que la función de retorno de deslizamiento lateral de UINavigationController está desactivada temporalmente.

Barra de migas de pan añadida

Para facilitar la gestión del apilamiento y empuje del controlador, debemos heredar el UINavigationController proporcionado por el sistema.

@interface AMBreadCrumbNavController : UINavigationController

@end
复制代码

Como se muestra en la figura a continuación, si usa el UINavigationController proporcionado por el sistema, habrá una barra de navegación integrada. Por lo tanto, debemos ocultar el NavigationBa incorporado y agregar nuestra propia barra de navegación de migas de pan.

Captura de pantalla del simulador - iPhone 8 - 2021-11-06 a las 15.29.32.png

Después de agregar a la barra de navegación, debemos indicarle a la barra de navegación de migas de pan personalizada, la pila del controlador en el controlador de navegación actual y colocar el controlador de vista raíz entrante en la pila del controlador. Luego, se administra mediante una barra de navegación de migas de pan personalizada.

Y pase el método de protocolo de la barra de navegación de migas de pan al controlador de navegación actual AMBreadCrumbNavController para su implementación.

El código de implementación es el siguiente:

- (instancetype)initWithRootViewController:(UIViewController *)rootViewController {

    //super中已经初始化好导航条了

    if (self = [super initWithRootViewController:rootViewController]) {
        //将导航栏设置为不透明
        self.navigationBar.translucent = NO;
        //设置根视图
        self.rootViewController = rootViewController;
        //分类添加一个面包屑导航条,用来覆盖掉系统自带的导航条
        [self breadCrumbNav];
        //初始化根视图控制器导航栏
        self.breadCrumbBar.controllers = @[self.rootViewController];
        //设置面包屑导航代理
        self.breadCrumbBar.delegate = self;
        //隐藏自带导航条
        [self setNavigationBarHidden:YES];
    }

    return self;
}
复制代码

Aquí, el método de agregar la barra de navegación de migas de pan se cambia para que se implemente mediante la clasificación de UIViewController+AMBreadCrumbNav, a fin de agregar la navegación de migas de pan a otros tipos de controladores en el futuro, no solo para el diseño de UINavigationController.

@interface UIViewController (AMBreadCrumbNav)

/// 面包屑导航栏整个导航栏视图
@property(strong,nonatomic) UIView* breadCrumbView;

/// 面包屑功能条
@property(strong,nonatomic) AMBreadCrumbNavBar* breadCrumbBar;

/// 右侧拓展视图
@property(strong,nonatomic) UIView* rightView;

/// 给右侧拓展视图添加自定义控件
/// **@param** item 右侧控件
- (void) addRightItem:(UIView*) item;

///// 右侧拓展按钮
//@property(strong,nonatomic) UIButton* selectButton;

- (void) breadCrumbNav;
@end
复制代码

Controlador pop y push

接下来我们要来实现这个导航控制器的入栈控制器和出栈控制器的方法。

控制器入栈

入栈方法很简单,我们只需要重写UINavigationController的pushViewController,并且将最新的控制器数组传递给面包屑导航条,使其更新导航条内容。

实现代码如下


- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    //关闭侧滑返回
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
        self.interactivePopGestureRecognizer.enabled = NO;
    //先入栈
    [super pushViewController:viewController animated:animated];
    //更新面包屑导航条
    self.breadCrumbBar.controllers = self.viewControllers;
}
复制代码

控制器出栈

因为关闭了导航控制器的侧滑返回功能,而且导航条上也没有对应的出栈按钮。所以我想要实现控制器的出栈,只有点面包屑导航条上的控制器对应的按钮,从而切换到指定的控制器。

所以这里我们需要实现面包屑导航条的委托方法。从而获取到当前在面包屑导航条上所点击的控制器,也就是我们想要切换到控制器。

当获取到了想要切换到的控制器之后,我们就需要将这个控制器之后的控制器全部出栈,只保留当前想要切换的控制器以及它之前的控制器

比如 A - B - C - D这个控制器栈,我们当前在D控制器页面,当我们点击B之后,clickViewController代理方法给我们回传需要切换到的控制器B,这时候我们就需要将C 和 D两个控制器出栈,只保留A和B两个控制器在栈内。

-(void)clickViewController:(UIViewController *)viewController{

    if ([self.viewControllers containsObject:viewController]) {
        if ([self.visibleViewController isEqual:viewController]) {
            return;
        }
        [self popToViewController:viewController animated:YES];
       //判断当前ViewControllers栈底元素是否是根视图,因为如果是跨页面跳转,比如A-B-C-D,D-C跳转 self.viewControllers栈底元素是根视图A,但是D-B跳转,self.viewControllers栈底元素却不是根视图A
        if (![self.viewControllers.firstObject isEqual:self.rootViewController]) {
            //删除不是根视图的栈底元素
            [self.viewControllers.firstObject removeFromParentViewController];
        }
        //更新面包屑导航条
        self.breadCrumbBar.controllers = self.viewControllers;
    }
}
复制代码

面包屑导航条

面包屑导航条内部是由一个UICollectionView来实现的,每一个控制器对应CollectionView中的一个item。

item分为文字区和拓展区

  • 文字区主要显示当前控制器要在面包屑导航条中的显示的文字。
  • 拓展区,主要用于当item的数量大于2的时候,给非最后一个item添加面包屑导航条的分割符号。这里我们用的是一个简单 > 符号来替代,后期可以根据自身需求替换成动画或者图片。

imagen.png

当然每个item的宽度是由所要显示的文字加上拓展区的宽度来计算的。也就是说当不需要显示拓展区的时候(item只有一个或者最后一个item)时,item的宽度就等于文字区的宽度。

item显示数据获取

这里我们通过获取面包屑导航控制器(AMBreadCrumbNavController)中的控制器栈(controllers),将其传递给AMBreadCrumbNavBar

@interface AMBreadCrumbNavBar : UIView
/// 保存系统导航控制器入栈的控制器
@property(strong,nonatomic) NSArray<UIViewController*>* controllers;
@property(weak,nonatomic) id<AMBreadCrumbBarDelegate> delegate;

@end
复制代码

A través de los controladores, podemos obtener los controladores en toda la pila de controladores y luego obtener el título que debe mostrarse de acuerdo con la propiedad de elemento de navegación en el controlador UIViewController. Luego, AMBreadCrumbNavCell lo muestra.


/// AMBreadCrumbNavCell
- (void)setController:(UIViewController *)controller{
    _controller = controller;
    NSLog(@"标题是 %@",controller.navigationItem.title);
    self.titleLabel.text = controller.navigationItem.title;

}
复制代码

Deslice automáticamente hasta el final

Configure la barra de navegación de migas de pan para que se deslice automáticamente hasta el final cuando el ancho de pantalla actual no pueda mostrar todo el contenido de CollectionView.

El principio de implementación es muy simple, es decir, utilizar el método scrollToItemAtIndexPath de CollectionView

Este método no se activará cuando el elemento especificado esté visible y se desplazará automáticamente al elemento especificado cuando el elemento especificado no esté visible.

Por lo tanto, solo necesitamos obtener el último controlador cuando la barra de navegación de migas de pan (AMBreadCrumbNavBar) cargue datos, es decir, el último elemento que debe mostrarse, y dejar que CollectionView se desplace hacia él. Se puede lograr que cuando el artículo final no esté visible, se desplace automáticamente al artículo final.

El código de implementación es el siguiente

- (void)setControllers:(NSArray<UIViewController *> *)controllers{
    _controllers = controllers;
    [self.collectionView reloadData];
    //如果导航条无法展示所有cell,则将collectionView自动滑动到末尾。
    [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:controllers.count-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
}

复制代码

Tenga en cuenta que cuando scrollToItemAtIndexPath especifica el desplazamiento, asegúrese de actualizar CollectionView antes de especificar el desplazamiento.

dirección del proyecto

Si tiene algún problema, envíeme problemas y haré todo lo posible para resolverlos.

El proyecto se mejorará continuamente en el futuro.

pan rallado AMB

Supongo que te gusta

Origin juejin.im/post/7027381839526379527
Recomendado
Clasificación