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

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

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

uva 10387 Billiard(简单几何)

题意是一个球从矩形的中点出发,告诉你小球与矩形两条边的碰撞次数与小球回到原点的时间,求小球出发时的角度和小球的速度。 简单的几何问题,小球每与竖边碰撞一次,向右扩展一个相同的矩形;每与横边碰撞一次,向上扩展一个相同的矩形。 可以发现,扩展矩形的路径和在当前矩形中的每一段路径相同,当小球回到出发点时,一条直线的路径刚好经过最后一个扩展矩形的中心点。 最后扩展的路径和横边竖边恰好组成一个直