一个很简单的侧边栏导航实现

2024-06-03 06:08
文章标签 简单 实现 导航 侧边

本文主要是介绍一个很简单的侧边栏导航实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一个简单的sidebar的小例子。

在实习的项目中,有一个重要的UI部分就是一个sidebar.之前一直很想自己能够重构这一部分,但是无论是参考项目代码还是到GitHub上的代码,我都感觉到很吃力。因为大部分设计到很多跳转,让我一下子很难理清楚。五一的时候重新整理了下写代码的思路,觉得要自己先理清楚基本的过程,写每一个方法前都要明白这个方法要达到什么样的功能。今天花了一上午参考了一个GitHub的样例写了一个小小sidebar,在这里记录一下这个过程,也相当于做一个笔记。

—-分割线—-

在手机APP上,我们可以看到许多侧边栏的应用。侧边栏不仅仅可以起到一个导航的作用,也可以用来展示一些相关的信息。我们可以看到像网易新闻,QQ等APP的侧边栏功能非常强大。而我认为,使用侧边栏相对于一般的顶部导航栏更为美观,也能省去视图的一部分空间占用。

首先,我们要认识到,侧边栏是一个视图。我们通过在当前视图的导航按钮或者通过手势来调出侧边栏。因此,首先要认识一下手势。

在UIKit中,有专门的手势识别器。这里我仅仅记录一下在侧边栏调用中要使用的滑动手势swip。其他的手势我认为也是大同小异,只需要自己写一个demo就能很好的理解。

下面这个方法展示了一个如何去添加一个手势到视图

- (void)addSwipToView:(UIView *)view withDirection:(UISwipeGestureRecognizerDirection)direction {UISwipeGestureRecognizer *swip = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwip:)];swip.direction = direction;[view addGestureRecognizer:swip];
}

UISwipeGestureRecognizer 这个代表了这是一个扫动的手势识别。direction是手势滑动的方向。

接下来,有了手势,我们就需要去写一个方法来处理手势将会处罚的动作

- (void)handleSwip:(UISwipeGestureRecognizer *)recognizer
{/*!*  @brief  处理滑动手势**  @since 1.0*///判断滑动的方向//当手势是向右滑动的时候if (recognizer.direction == UISwipeGestureRecognizerDirectionRight) {CGFloat height = self.view.frame.size.height;CGFloat width = self.view.frame.size.width;UINavigationController *newNv =  self.childViewControllers[_currentIndex];[UIView animateWithDuration:kAnimateDuration animations:^{/*!*  @brief  当向右侧滑动的时候,左侧边栏将要出现*          方法是计算左侧边栏和当前视图的高度比例,计算得出cover和侧边栏不同的高度。**  @since 1.0*/// animation of View controllerUIView *view = newNv.view;// 添加cover视图[self addCoverToView:view];CGFloat scale = leftMenuH / height;CGAffineTransform scaleTransf = CGAffineTransformMakeScale(scale, scale);CGFloat targetX = leftMenuW - width * (1 - scale) / 2;CGFloat targetY = leftMenuY - height * (1 - scale) / 2;CGAffineTransform transf = CGAffineTransformTranslate(scaleTransf, targetX / scale, targetY / scale);view.transform = transf;// animation of left menu_leftMenu.transform = CGAffineTransformMakeTranslation(leftMenuW, 0);}];}//滑动收拾向左if (recognizer.direction == UISwipeGestureRecognizerDirectionLeft) {/*!*  @brief  当向左滑动的时候,左侧边栏将隐藏*          放是 将cover视图上父视图上去掉**  @since 1.0*/[_cover removeFromSuperview];UINavigationController *nav = self.childViewControllers[_currentIndex];[UIView animateWithDuration:kAnimateDuration animations:^{// clear transformnav.view.transform = CGAffineTransformIdentity;_leftMenu.transform = CGAffineTransformIdentity;}];}}
```
可以看到,我们将会判断手势滑动的方向,根据左右,我们分别调用不同的行为。如果行为方法非常复杂,用另外的函数进行封装。在我们简单的看过这两个方法来了解了基本的手势处理后,接下来就是我们去看看如何去设计一个侧边栏了。首先我们自定义一个类,这里我并没有是使用interface build,所以可能效果上不是特别好。首先我的想法是建立一个View,加入不同的组件,然后代理模式使这个视图和主视图进行关联。
在这个View中,我仅仅添加了三个button来做演示。代码如下

//
// CSBLeftView.m
// SideBarDemo
//
// Created by 陈思博 on 5/5/15.
// Copyright (c) 2015 csb. All rights reserved.
//

import “CSBLeftView.h”

@interface CSBLeftView()

{
UIButton *selectButton;
}

@end

@implementation CSBLeftView

/*!
* @brief 左视图的构建思路
向视图中添加所需要的组件或者子视图
为子视图或者组件添加所需要的事件
当当前视图的按钮或者子视图发生跳转活其他的时候,通过协议进行定义相关的方法
*
* @since 1.0
*/

  • (id)initWithFrame:(CGRect)frame
    {
    /*!

    • @brief 根据传进来的frame进行设置初始化
      *
    • @since 1.0
      */
      self = [super initWithFrame:frame];
      if(self)
      {
      self.backgroundColor = [UIColor clearColor];

      UIColor *color = [[UIColor alloc] initWithRed:187.0/255.0 green:67.0/255.0 blue:71.0/255.0 alpha:1];
      [self addButtonByIcon:@”sidebar_nav_reading” tile:@”阅读” andTintColor:color];

      color = [[UIColor alloc] initWithRed:187.0/255.0 green:114.0/255.0 blue:72.0/255.0 alpha:1];
      [self addButtonByIcon:@”sidebar_nav_photo” tile:@”照片” andTintColor:color];

      color = [[UIColor alloc] initWithRed:67.0/255.0 green:125.0/255.0 blue:187.0/255.0 alpha:1];
      [self addButtonByIcon:@”sidebar_nav_news” tile:@”新闻” andTintColor:color];

    }

    return self;

}

  • (void)setDelegate:(id)delegate{
    _delegate = delegate;
    selectButton = self.subviews[0];
    selectButton.selected = YES;
    }

  • (void)addButtonByIcon:(NSString )iconName tile:(NSString )title andTintColor:(UIColor *)color
    {
    /*!

    • @brief 根绝给定的图标和标题创建添加一个Button
      *
    • @since 1.0
      */
      UIButton *button = [[UIButton alloc] init];
      [self addSubview:button];
      [button setTitle:title forState:UIControlStateNormal];
      [button setTintColor:[UIColor whiteColor]];
      [button setImage:[UIImage imageNamed:iconName] forState:UIControlStateNormal];
      [button setAdjustsImageWhenHighlighted:NO];
      // 点击事件
      [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
      // 按钮内部向左对齐
      button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
      // 标题
      button.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
      button.contentEdgeInsets = UIEdgeInsetsMake(0, 30, 0, 0);

}

  • (void)buttonAction:(UIButton *)button{
    /*!

    • @brief 按钮点击事件处理
      *
    • @since 1.0
      */
      if ([self.delegate respondsToSelector:@selector(leftMenu:ChangeViewControllerFrom:to:)]) {
      [self.delegate leftMenu:self ChangeViewControllerFrom:selectButton.tag to:button.tag];
      }
      selectButton.selected = NO;
      button.selected = YES;
      selectButton = button;
      }
  • (void)layoutSubviews{
    /*!

    • @brief 根据当前的子视图来排列
      *
    • @since 1.0
      */
      [super layoutSubviews];

    NSArray *buttons = self.subviews;
    NSInteger count = buttons.count;
    CGFloat btnW = self.bounds.size.width;
    CGFloat btnH = self.bounds.size.height / count;
    for (int i = 0; i < count; i++) {
    UIButton *button = buttons[i];
    CGRect frame = CGRectMake(0, btnH * i, btnW, btnH);
    button.tag = i;
    button.frame = frame;
    }
    }

@end


其余部分没有什么太多好说的,但有一个地方特别要注意。我们要想到,怎么才能在点击按钮后跳转到另外的视图呢?自然我们想到要为点击事件添加一个处理方法。而这个方法却并不在这里实现,而是要在主视图的类里面实现。为什么呢?因为我们要在主视图里面进行控制器的变换。接下来我们把注意力放到主视图里。
通过思考,我们可以明白,侧边栏视图实际是作为主视图的一个子视图存在的,通过手势或者按钮来唤醒。也就是说,如果要调出侧边栏,我们必须通过计算视图之间的位置关系。在初始化的时候,我们将侧边栏作为子视图添加到主视图中,同时设置侧边栏的位置。
  • (void)viewDidLoad {
    [super viewDidLoad];
    /*!

    • @brief 初始左侧视图,将视图添加到子视图中,添加子视图控制器
      *
      *
      *
    • @since 1.0
      */

    _currentIndex = 0;
    _BGImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
    _BGImageView.image = [UIImage imageNamed:@”sidebar_bg”];
    [self.view addSubview:_BGImageView];

    CSBLeftView *leftView = [[CSBLeftView alloc] initWithFrame:CGRectMake(-leftMenuW, leftMenuY, leftMenuW, leftMenuH)];
    [self.view addSubview:leftView];
    _leftMenu = leftView;
    leftView.delegate =self;

    [self addChildNvController:@”阅读”];
    [self addChildNvController:@”图片”];
    [self addChildNvController:@”新闻”];

    UINavigationController *newNv = self.childViewControllers[0];
    [self.view addSubview:newNv.view];

}


注意到,我们初始化侧边栏的时候将他初始的位置X设置为他的宽度的负数。这样就刚好使侧边栏在主视图外面。然后我们要为每个按钮要添加相匹配的控制器。这样在点击按钮后,根据按钮的index来调用相关的控制器。
  • (void)addChildNvController:(NSString *)title
    {
    /*!

    • @brief 添加一个子控制器
      *
    • @since 1.0
      */
      UIViewController *vc = [[ReadViewController alloc] init];
      vc.view.backgroundColor = [UIColor colorWithRed:220.0/255.0 green:220.0/255.0 blue:220.0/255.0 alpha:1.0];
      // UINavigationController属于容器,最少需要一个RootController,Title是设置在容器中的Controller上
      UINavigationController *newNv = [[UINavigationController alloc] initWithRootViewController:vc];
      newNv.navigationBar.barTintColor = [UIColor colorWithRed:168.0/255.0 green:20.0/255.0 blue:4.0/255.0 alpha:1.0];
      // title color
      NSDictionary *attris = @{NSForegroundColorAttributeName:[UIColor whiteColor],NSFontAttributeName:[UIFont boldSystemFontOfSize:18.0]};
      newNv.navigationBar.titleTextAttributes = attris;
      newNv.navigationBar.tintColor = [UIColor whiteColor];
      // left barItem
      UIBarButtonItem *left = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@”top_navigation_menuicon.png”] style:UIBarButtonItemStylePlain target:self action:@selector(leftButtonAction)];
      vc.navigationItem.leftBarButtonItem = left;
      vc.title = title;
      // add gesture
      [self addSwipToView:vc.view withDirection:UISwipeGestureRecognizerDirectionRight];

    [self addChildViewController:newNv];


在完成这一切后,通过代理方法,使按钮点击的时候,跳转到另一个控制器。
  • (void)leftMenu:(UIView *)leftMenu ChangeViewControllerFrom:(NSInteger)fromIndex to:(NSInteger)index
    {
    /*!

    • @brief 代理方法
      根据index来变换视图
      *
    • @since 1.0
      */

    //讲当前的子控制器的视图从父视图中移除
    UINavigationController *oldNv = self.childViewControllers[_currentIndex];
    CGAffineTransform transform = oldNv.view.transform;
    [oldNv.view removeFromSuperview];

    //添加子视图控制和相关的视图到当前视图中
    _currentIndex = index;
    UINavigationController *newNv = self.childViewControllers[_currentIndex];
    transform = newNv.view.transform;
    [self.view addSubview:newNv.view];

    [UIView animateWithDuration:kAnimateDuration animations:^{
    newNv.view.transform = CGAffineTransformIdentity;
    _leftMenu.transform = CGAffineTransformIdentity;
    }];
    [_cover removeFromSuperview];
    }
    “`

这是最后的效果图。

这里写图片描述

总结

因为在IOS自带的UI中并没有实现侧边栏,所以网上有很多人通过不同的方法来实现了侧边栏。虽然在具体的实现上面有所不同,但是总体来说主要是通过不同的controller进行转换来实现,等同一个导航栏,只是这个导航栏需要我们自己去实现。了解了各种细节,到了具体的动画效果等等就需要我们自己去尝试如果做到更好的效果了。

这篇关于一个很简单的侧边栏导航实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1026188

相关文章

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

redis群集简单部署过程

《redis群集简单部署过程》文章介绍了Redis,一个高性能的键值存储系统,其支持多种数据结构和命令,它还讨论了Redis的服务器端架构、数据存储和获取、协议和命令、高可用性方案、缓存机制以及监控和... 目录Redis介绍1. 基本概念2. 服务器端3. 存储和获取数据4. 协议和命令5. 高可用性6.

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动