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

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

相关文章

Java根据IP地址实现归属地获取

《Java根据IP地址实现归属地获取》Ip2region是一个离线IP地址定位库和IP定位数据管理框架,这篇文章主要为大家详细介绍了Java如何使用Ip2region实现根据IP地址获取归属地,感兴趣... 目录一、使用Ip2region离线获取1、Ip2region简介2、导包3、下编程载xdb文件4、J

PyQt5+Python-docx实现一键生成测试报告

《PyQt5+Python-docx实现一键生成测试报告》作为一名测试工程师,你是否经历过手动填写测试报告的痛苦,本文将用Python的PyQt5和python-docx库,打造一款测试报告一键生成工... 目录引言工具功能亮点工具设计思路1. 界面设计:PyQt5实现数据输入2. 文档生成:python-

Android实现一键录屏功能(附源码)

《Android实现一键录屏功能(附源码)》在Android5.0及以上版本,系统提供了MediaProjectionAPI,允许应用在用户授权下录制屏幕内容并输出到视频文件,所以本文将基于此实现一个... 目录一、项目介绍二、相关技术与原理三、系统权限与用户授权四、项目架构与流程五、环境配置与依赖六、完整

浅析如何使用xstream实现javaBean与xml互转

《浅析如何使用xstream实现javaBean与xml互转》XStream是一个用于将Java对象与XML之间进行转换的库,它非常简单易用,下面将详细介绍如何使用XStream实现JavaBean与... 目录1. 引入依赖2. 定义 JavaBean3. JavaBean 转 XML4. XML 转 J

Flutter实现文字镂空效果的详细步骤

《Flutter实现文字镂空效果的详细步骤》:本文主要介绍如何使用Flutter实现文字镂空效果,包括创建基础应用结构、实现自定义绘制器、构建UI界面以及实现颜色选择按钮等步骤,并详细解析了混合模... 目录引言实现原理开始实现步骤1:创建基础应用结构步骤2:创建主屏幕步骤3:实现自定义绘制器步骤4:构建U

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

Android实现定时任务的几种方式汇总(附源码)

《Android实现定时任务的几种方式汇总(附源码)》在Android应用中,定时任务(ScheduledTask)的需求几乎无处不在:从定时刷新数据、定时备份、定时推送通知,到夜间静默下载、循环执行... 目录一、项目介绍1. 背景与意义二、相关基础知识与系统约束三、方案一:Handler.postDel

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句