首页 > 代码库 > 抽屉效果功能实现

抽屉效果功能实现

抽屉效果功能实现

一、.h文件
@interfaceHMDrawViewController :UIViewController

@property(nonatomic,weak, readonly)UIView *mainView;
@property(nonatomic,weak, readonly)UIView *leftView;
@property(nonatomic,weak, readonly)UIView *rightView;

@end

二、.m文件
@interfaceHMDrawViewController ()

@property(nonatomic,assign) BOOL isDraging;
@end

@implementationHMDrawViewController


- (
void)viewDidLoad
{
   
// UIViewController
    [
superviewDidLoad];
   
// Do any additional setup after loading the view.
  
   
// 1.添加子控件
    [
selfaddChildView];
#warning第三步观察_mainViewframe改变
    // 2.监听
   
/**
     * 
_mainView添加一个观察者
     *
     *  KeyPath
:监听frame这个属性
     *
     *  options
:监听新值的改变
     */

    [
_mainViewaddObserver:selfforKeyPath:@"frame"options:NSKeyValueObservingOptionNewcontext:nil];
  
}

//_mainViewframe属性改变的时候就会调用
- (
void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
   
NSLog(@"%@",NSStringFromCGRect(_mainView.frame));
   
   
if (_mainView.frame.origin.x< 0) { // 往左移动
       
// 显示右边
       
_rightView.hidden= NO;
       
// 隐藏左边
       
_leftView.hidden= YES;
    }
elseif (_mainView.frame.origin.x> 0){ // 往右移动
       
// 显示左边
       
_rightView.hidden= YES;
       
// 隐藏右边
       
_leftView.hidden= NO;
       
    }
}

#warning第一步
- (void)addChildView
{
   
// left
   
UIView *leftView = [[UIViewalloc]initWithFrame:self.view.bounds];
    leftView.
backgroundColor= [UIColorgreenColor];
    [
self.viewaddSubview:leftView];
   
_leftView = leftView;
   
   
// right
   
UIView *rightView = [[UIViewalloc]initWithFrame:self.view.bounds];
    rightView.
backgroundColor= [UIColorblueColor];
    [
self.viewaddSubview:rightView];
   
_rightView = rightView;
   
   
// mainView
   
UIView *mainView = [[UIViewalloc]initWithFrame:self.view.bounds];
    mainView.
backgroundColor= [UIColorredColor];
    [
self.viewaddSubview:mainView];
   
_mainView = mainView;
}

#warning第二步
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
   
// 获取UITouch对象
   
UITouch *touch = [touchesanyObject];
   
   
// 获取当前点
   
CGPoint currentPoint = [touchlocationInView:self.view];
   
   
// 获取上一个点
   
CGPoint prePoint = [touchpreviousLocationInView:self.view];
   
   
// x轴偏移量:当手指移动一点的时候,x偏移多少
   
CGFloat offsetX = currentPoint.x- prePoint.x;
   
   
// 设置当前主视图的frame
   
_mainView.frame= [selfgetCurrentFrameWithOffsetX:offsetX];
   
   
   
_isDraging =YES;
}
#warning第四步
#define HMMaxY
60
//当手指偏移一点,根据X轴的偏移量算出当前主视图的frame
- (
CGRect)getCurrentFrameWithOffsetX:(CGFloat)offsetX
{
   
CGFloat screenW = [UIScreenmainScreen].bounds.size.width;
   
CGFloat screenH = [UIScreenmainScreen].bounds.size.height;
   
   
// 获取y轴偏移量,手指每移动一点,y轴偏移多少
   
CGFloat offsetY = offsetX *HMMaxY/ screenW;
   
   
CGFloat scale = (screenH -2* offsetY) / screenH;
   
   
if (_mainView.frame.origin.x< 0) { // 往左边滑动
        scale = (screenH +
2 * offsetY) / screenH;
    }
   
   
// 获取之前的frame
   
CGRect frame =_mainView.frame;
    frame.
origin.x+= offsetX;
    frame.
size.height= frame.size.height*scale;
    frame.
size.width= frame.size.width*scale;
    frame.
origin.y= (screenH - frame.size.height) * 0.5;
   
   
return frame;
}

注意:
抽屉效果的固定的高度是写死的,可以定义一个宏,方便后期的维护。
算法:
offsetY = offsetX *60/ 320
scale =  currentH / screenH
currentH  =  screenH –
2 * offsetY

x = frame. origin.x + offsetX
h = frame.size.height * scale
w = frame.size.weight * scale
y =( screenH – h ) *
0.5

#define HMRTarget250
#define HMLTarget -
220
/*
 _mainView.frame.origin.x > screenW * 0.5
定位到右边
  CGRectGetMaxX(_mainView.frame) < screenW * 0.5
定位到左边 -220
 
 */

//定位
- (
void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
   
// 复位
   
if (_isDraging== NO && _mainView.frame.origin.x!= 0) {
        [
UIViewanimateWithDuration:0.25animations:^{
           
           
_mainView.frame= self.view.bounds;
        }];
    }
   
CGFloat screenW = [UIScreenmainScreen].bounds.size.width;
   
CGFloat target =0;
   
if (_mainView.frame.origin.x> screenW * 0.5) { // 定位到右边
        target =
HMRTarget;
    }
elseif (CGRectGetMaxX(_mainView.frame) < screenW * 0.5) { // 定位到左边
        target =
HMLTarget;
    }
    [
UIViewanimateWithDuration:0.25animations:^{
       
       
if (target) {//在需要定位左边或者右边
           
           
// 获取x轴偏移量
           
CGFloat offsetX = target -_mainView.frame.origin.x;
           
           
// 设置当前主视图的frame
           
_mainView.frame= [selfgetCurrentFrameWithOffsetX:offsetX];
           
        }
else{//还原
           
_mainView.frame= self.view.bounds;
        }
    }];
   
_isDraging =NO;
}

注意:
复位的时候,需要定义一个成员变量记录。
@end

注意:
知识点1:KVO观察者模式,_mainView添加一个观察者, KeyPath:监听frame这个属性,options:监听新值的改变,当frame属性的值发生改变的时候就会调用下面这个方法。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
知识点2:抽屉效果的算法。


抽屉效果功能实现