实现侧边抽屉效果-YRSideViewController

在项目当中经常用到类似抽屉效果的页面转换,下面是简单的视图切换。

1,首先声明SideViewController,用来装所有要在屏幕中显示的控制器。

2,为SideViewController添加属性和方法,每个属性的作用都有注释。代码如下:

// SliderViewController.h

//普通动画的block

typedef void(^RootViewMoveBlock) (UIView *rootView,CGRect orhinFrame,CGFloat xoffeset);

@interface SideViewController : UIViewController

@property (assign ,nonatomic) BOOL needSwipeShowMenu;//是否开启手势滑动出菜单

@property (strong ,nonatomic) UIViewController *rightViewContorller;//右边控制器

@property (strong,nonatomic) UIViewController *leftViewController;//左边控制器

@property (strong,nonatomic) UIViewController *mainViewController;//主页面控制器

@property (assign,nonatomic) CGFloat leftViewShowWidth;//左侧栏展示大小

@property (assign,nonatomic)CGFloat rightViewShowWidth;//右侧栏展示大小

@property (assign,nonatomic)NSTimeInterval animationDuration;//动画时长

@property (assign,nonatomic)BOOL showBoundsShadow;//是否显示边框阴影

@property (copy,nonatomic)RootViewMoveBlock rootViewMoveBlock;//可在此block做动画效果

//block 的setter方法

-(void)setRootViewMoveBlock:(RootViewMoveBlock)rootViewMoveBlock;

-(void)showLeftViewController:(BOOL)animated;//展示左边栏

-(void)showRightViewController:(BOOL)animated;//展示右边栏

-(void)hideSideViewController:(BOOL)animated;//回复正常位置

@end

可以根据实际情况确定是否使用leftViewController/rightViewController,但是一般情况下我们必须设置mainViewcontroller。

在.h文件中,只是提供了外部接口,让使用起来方便一些。在整个api中,侧边抽屉效果最难的应该就是对视图的缩放处理了,结合起来动画效果,工程量也是不堪小视的。

下面来看源代码:

#import "SideViewController.h"

#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width

#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height

@interface SideViewController ()

{

UIView *_baseView;

UIView *_currentView;//rootViewController.view

UIPanGestureRecognizer *_panGestureRecognizer;

CGPoint _startPanPoint;

CGPoint _lastPanPoint;

BOOL _panMovingRightOrLeft;//true是右,false是左

UIButton *_coverButton;

}

@end

@implementation SideViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {

_leftViewShowWidth = 267;

_rightViewShowWidth = 267;

_animationDuration = 0.35;

_showBoundsShadow = true;

_panGestureRecognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];

_panMovingRightOrLeft = false;

_lastPanPoint = CGPointZero;

_coverButton = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];

[_coverButton addTarget:self action:@selector(hideSideViewController) forControlEvents:UIControlEventTouchUpInside];

}

return self;

}

-(id)init{

return [self initWithNibName:nil bundle:nil];

}

#pragma mark - 视图进出方法

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view.

_baseView = self.view;

_baseView.backgroundColor = [UIColor orangeColor];

self.needSwipeShowMenu = true;

}

-(void)viewWillAppear:(BOOL)animated{

[super viewWillAppear:animated];

if (!self.mainViewController) {

NSAssert(false, @"还没有设置mainViewCOntroller");

}

if (_currentView != _mainViewController.view) {

[_currentView removeFromSuperview];

_currentView = _mainViewController.view;

[_baseView addSubview:_currentView];

_currentView.frame = _baseView.bounds;

}

}

#pragma mark - setter方法的重写

-(void)setLeftViewController:(UIViewController *)leftViewController{

if (_leftViewController != leftViewController) {

if (_leftViewController) {

[_leftViewController removeFromParentViewController];

}

_leftViewController = leftViewController;

if (_leftViewController) {

[self addChildViewController:_leftViewController];

}

}

}

/**

*  rightViewController

*/

-(void)setRightViewContorller:(UIViewController *)rightViewContorller{

if (_rightViewContorller != rightViewContorller) {

if (_rightViewContorller) {

[_rightViewContorller removeFromParentViewController];

}

_rightViewContorller = rightViewContorller;

if (_rightViewContorller) {

[self addChildViewController:_rightViewContorller];

}

}

}

/**

*  needSwipeShowMenu

*/

-(void)setNeedSwipeShowMenu:(BOOL)needSwipeShowMenu{

_needSwipeShowMenu = needSwipeShowMenu;

if (needSwipeShowMenu) {

[_baseView addGestureRecognizer:_panGestureRecognizer];

}else{

[_baseView removeGestureRecognizer:_panGestureRecognizer];

}

}

-(void)showShadow:(BOOL)show{

_currentView.layer.shadowOpacity = show? .8f : .0f;

if (show) {

_currentView.layer.cornerRadius = 4.0f;

_currentView.layer.shadowOffset = CGSizeZero;

_currentView.layer.shadowRadius = 4.0f;

_currentView.layer.shadowPath = [UIBezierPath bezierPathWithRect:_currentView.bounds].CGPath;

}

}

#pragma mark - showOrHideTheView

-(void)willShowLeftViewController{

if (!_leftViewController || _leftViewController.view.superview) {

return;

}

_leftViewController.view.frame = _baseView.bounds;

[_baseView insertSubview:_leftViewController.view belowSubview:_currentView];

if (_rightViewContorller && _rightViewContorller.view.superview) {

[_rightViewContorller.view removeFromSuperview];

}

}

-(void)willShowRightViewController{

if (!_rightViewContorller || _rightViewContorller.view.superview) {

return;

}

_rightViewContorller.view.frame=_baseView.bounds;

[_baseView insertSubview:_rightViewContorller.view belowSubview:_currentView];

if (_leftViewController && _leftViewController.view.superview) {

[_leftViewController.view removeFromSuperview];

}

}

-(void)showLeftViewController:(BOOL)animated{

if (!_leftViewController) {

return;

}

[self willShowLeftViewController];

NSTimeInterval animatedTime = 0;

if (animated) {

animatedTime = ABS(_leftViewShowWidth - _currentView.frame.origin.x) / _leftViewShowWidth * _animationDuration;

}

[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

[UIView animateWithDuration:animatedTime animations:^{

[self layoutCurrentViewWithOffset:_leftViewShowWidth];

[_currentView addSubview:_coverButton];

[self showShadow:_showBoundsShadow];

}];

}

-(void)showRightViewController:(BOOL)animated{

if (!_rightViewContorller) {

return;

}

[self willShowRightViewController];

NSTimeInterval animatedTime = 0;

if (animated) {

animatedTime = ABS(_rightViewShowWidth + _currentView.frame.origin.x) / _rightViewShowWidth * _animationDuration;

}

[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

[UIView animateWithDuration:animatedTime animations:^{

[self layoutCurrentViewWithOffset:-_rightViewShowWidth];

[_currentView addSubview:_coverButton];

[self showShadow:_showBoundsShadow];

}];

}

-(void)hideSideViewController:(BOOL)animated{

[self showShadow:false];

NSTimeInterval animatedTime = 0;

if (animated) {

animatedTime = ABS(_currentView.frame.origin.x / (_currentView.frame.origin.x > 0 ? _leftViewShowWidth:_rightViewShowWidth))*_animationDuration;

}

[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

[UIView animateWithDuration:animatedTime animations:^{

[self layoutCurrentViewWithOffset:0];

} completion:^(BOOL finished) {

[_coverButton removeFromSuperview];

[_leftViewController.view removeFromSuperview];

[_rightViewContorller.view removeFromSuperview];

}];

}

-(void)hideSideViewController{

[self hideSideViewController:true];

}

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {

// Check for horizontal pan gesture

if (gestureRecognizer == _panGestureRecognizer) {

UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer*)gestureRecognizer;

CGPoint translation = [panGesture translationInView:_baseView];

if ([panGesture velocityInView:_baseView].x < 600 && ABS(translation.x)/ABS(translation.y)>1) {

return YES;

}

return NO;

}

return YES;

}

- (void)pan:(UIPanGestureRecognizer*)pan{

if (_panGestureRecognizer.state==UIGestureRecognizerStateBegan) {

_startPanPoint=_currentView.frame.origin;

if (_currentView.frame.origin.x==0) {

[self showShadow:_showBoundsShadow];

}

CGPoint velocity=[pan velocityInView:_baseView];

if(velocity.x>0){

if (_currentView.frame.origin.x>=0 && _leftViewController && !_leftViewController.view.superview) {

[self willShowLeftViewController];

}

}else if (velocity.x<0) {

if (_currentView.frame.origin.x<=0 && _rightViewContorller && !_rightViewContorller.view.superview) {

[self willShowRightViewController];

}

}

return;

}

CGPoint currentPostion = [pan translationInView:_baseView];

CGFloat xoffset = _startPanPoint.x + currentPostion.x;

if (xoffset>0) {//向右滑

if (_leftViewController && _leftViewController.view.superview) {

xoffset = xoffset>_leftViewShowWidth?_leftViewShowWidth:xoffset;

}else{

xoffset = 0;

}

}else if(xoffset<0){//向左滑

if (_rightViewContorller && _rightViewContorller.view.superview) {

xoffset = xoffset<-_rightViewShowWidth?-_rightViewShowWidth:xoffset;

}else{

xoffset = 0;

}

}

if (xoffset!=_currentView.frame.origin.x) {

[self layoutCurrentViewWithOffset:xoffset];

}

if (_panGestureRecognizer.state==UIGestureRecognizerStateEnded) {

if (_currentView.frame.origin.x!=0 && _currentView.frame.origin.x!=_leftViewShowWidth && _currentView.frame.origin.x!=-_rightViewShowWidth) {

if (_panMovingRightOrLeft && _currentView.frame.origin.x>20) {

[self showLeftViewController:true];

}else if(!_panMovingRightOrLeft && _currentView.frame.origin.x<-20){

[self showRightViewController:true];

}else{

[self hideSideViewController];

}

}else if (_currentView.frame.origin.x==0) {

[self showShadow:false];

}

_lastPanPoint = CGPointZero;

}else{

CGPoint velocity = [pan velocityInView:_baseView];

if (velocity.x>0) {

_panMovingRightOrLeft = true;

}else if(velocity.x<0){

_panMovingRightOrLeft = false;

}

}

}

//重写此方法可以改变动画效果,PS._currentView就是RootViewController.view

- (void)layoutCurrentViewWithOffset:(CGFloat)xoffset{

if (_showBoundsShadow) {

_currentView.layer.shadowPath = [UIBezierPath bezierPathWithRect:_currentView.bounds].CGPath;

}

if (self.rootViewMoveBlock) {//如果有自定义动画,使用自定义的效果

self.rootViewMoveBlock(_currentView,_baseView.bounds,xoffset);

return;

}

/*平移的动画

[_currentView setFrame:CGRectMake(xoffset, _baseView.bounds.origin.y, _baseView.frame.size.width, _baseView.frame.size.height)];

return;

//*/

//    /*平移带缩放效果的动画

static CGFloat h2w = 0;

if (h2w==0) {

h2w = _baseView.frame.size.height/_baseView.frame.size.width;

}

CGFloat scale = ABS(600 - ABS(xoffset)) / 600;

scale = MAX(0.8, scale);

_currentView.transform = CGAffineTransformMakeScale(scale, scale);

CGFloat totalWidth=_baseView.frame.size.width;

CGFloat totalHeight=_baseView.frame.size.height;

if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {

totalHeight=_baseView.frame.size.width;

totalWidth=_baseView.frame.size.height;

}

if (xoffset>0) {//向右滑的

[_currentView setFrame:CGRectMake(xoffset, _baseView.bounds.origin.y + (totalHeight * (1 - scale) / 2), totalWidth * scale, totalHeight * scale)];

}else{//向左滑的

[_currentView setFrame:CGRectMake(_baseView.frame.size.width * (1 - scale) + xoffset, _baseView.bounds.origin.y + (totalHeight*(1 - scale) / 2), totalWidth * scale, totalHeight * scale)];

}

//*/

}

@end

整个.m文件是对setter方法的重写和一些动画效果,以及缩放效果的实现。

整个缩放效果的逻辑都在layoutCurrentViewWithOffset:xoffset中,在左右视图出现的时候都会调用这个方法,对控制器进行图形处理。

如果我们想使用普通的平移效果,那么只需要在用到sideViewController的地方实现回调的rootViewBlock即可:

[sideViewController setRootViewMoveBlock:^(UIView *rootView, CGRect orginFrame, CGFloat xoffset) {

//使用简单的平移动画

rootView.frame=CGRectMake(xoffset, orginFrame.origin.y, orginFrame.size.width, orginFrame.size.height);

}];

假设我们已经在其他控制器或者appdelegate里面设置了sideViewcontroller左右控制器,那么,我们可以用单例来取到:(appdelegate.h里面有sideViewController属性)

AppDelegate *delegate=(AppDelegate*)[[UIApplication sharedApplication]delegate];

SideViewController *sideViewController=[delegate sideViewController];

[sideViewController showLeftViewController:true];//通过他来设置左右滑动。

左右控制器的事件我们也可以在当前使用sideViewController中实现,只需要在左右控制器中写好回调的block或者使用delegate传到控制器中即可。

时间: 2024-10-31 09:51:34

实现侧边抽屉效果-YRSideViewController的相关文章

iOS抽屉效果和侧边菜单

iOS抽屉效果和侧边菜单 源码下载地址 1.效果演示 1. 抽屉效果演示 1. 侧边菜单演示 2.使用说明 构造方法 initialization /// 构造方法(左控制器 & 右控制器 & 背景图片) -(instancetype)initWithLeftController:(UIViewController *)leftController andMainController:(UIViewController *)mainController andRightController

第三方抽屉效果

1.  抽屉效果的基本原理应用了父子视图的层级,视图的位置改变,动画,手势操作等主要知识点.熟练掌握基础知识并灵活运用,即可实现该效果. > 父子视图的层级: 在指定层级上插入子视图 [view insertSubView: atIndex:] > 视图位置的改变: 通过视图的frame,center属性调整 > 动画:可使用UIView或CALayer的动画,这里主要使用了UIView的动画方法 [UIView animateWithDuration:……. ] > 手势操作:主

产品设计课程——TAB导航与侧边抽屉的交互方式

如果你是个产品设计经理,或是说你是一个产品设计师.现在的你需要设计一个含有许多页面和模块,不能在一屏内显示完全的应用.你一定会首先想到去设计一个底部或顶部的Tab导航.可是这样的话,多出来的一排导航看上去有点碍眼.如果尝试把他们收到侧边栏里,比如“侧边抽屉导航”又会如何呢?今天就让我们围绕这产品设计课程,将这一个问题仔细探讨一下,本文来自于e良师益友网,elsyy.com. 如果你们的应用的也是多视图的,在你们的团队里,以下话题一定常常引发激烈讨论: 是把导航选项都显示在屏幕上,让你们的用户可以

ios开发抽屉效果的封装使用

#import "DragerViewController.h" #define screenW [UIScreen mainScreen].bounds.size.width @interface DragerViewController () /** <#注释#> */ @property (nonatomic, weak) UIView *leftV; @property (nonatomic, weak) UIView *rightV; @property (non

动画的抽屉效果

添加三个View // // ViewController.m // UISenior17_抽屉效果 // // Created by lanou3g on 16/5/27. // Copyright © 2016年 张明杰. All rights reserved. // #import "ViewController.h" //frame #define XMGkeyPath(objc, keyPath) @(((void)objc.keyPath, #keyPath)) //获取

iOS开发——实用技术OC篇&amp;简单抽屉效果的实现

简单抽屉效果的实现 就目前大部分App来说基本上都有关于抽屉效果的实现,比如QQ/微信等.所以,今天我们就来简单的实现一下.当然如果你想你的效果更好或者是封装成一个到哪里都能用的工具类,那就还需要下一些功夫了,我们这里知识简单的介绍怎么去实现,不过一般我们开发都是找别人做好的,也没必要烂肺时间,除非你真的是大牛或者闲的蛋疼. 其实关于抽屉效果就是界面有三个View,其实一个主View其他两个分别是左边和右边的View,我们分别为他们添加手势,实现左右滑动显示对应的View. 一:所以,首先我们需

抽屉效果的实现

抽屉效果 添加子视图 *   简单的滑动效果 * 监听控制器处理事件方法 * 获取x轴偏移量 * 改变主视图的frame *   利用KVO做视图切换 往左移动,显示右边,隐藏左边 往右移动,显示左边,隐藏右边 *  复杂的滑动效果,PPT讲解(根据手指每移动一点,x轴的偏移量算出当前视图的frame) 假设x移到320时,y移动到60,算出没移动一点x,移动多少y offsetY = offsetX * 60 / 320  手指每移动一点,x轴偏移量多少,y偏移多少 为了好看,x移动到320,

iOS实现抽屉效果

抽屉效果 在iOS中很多应用都用到了抽屉效果,例如腾讯的QQ,百度贴吧- --- 1. 最终效果如下图所示 --- 2.实现步骤 1.开始启动的时候,新建3个不同颜色的View的 1.设置3个成员属性,记录三种颜色的View @property (nonatomic,weak) UIView* redView; @property (nonatomic,weak) UIView* greenView; @property (nonatomic,weak) UIView* blueView; 2.

ios开发中超简单抽屉效果(MMDrawerController)的实现

ios开发中,展示类应用通常要用到抽屉效果,由于项目需要,本人找到一个demo,缩减掉一些不常用的功能,整理出一个较短的实例. 首先需要给工程添加第三方类库 MMDrawerController: 这里讲的实例只加入了左滑抽屉.右滑和左滑只是初始化时多添加一个右视图控制器,其他方法基本相同. 下面是用手势实现抽屉的拉出和收回 1.初始化跟视图控制器时,在AppDelegate中导入头文件 #import "MMDrawerController.h" 2.初始化方法先初始化左视图和中心视