zoukankan      html  css  js  c++  java
  • 第二十五篇、抽屉效果的核心代码

    // pan 拽 手势处理
    - (IBAction)panGesture:(UIPanGestureRecognizer *)sender
    {
       
      // 如果是刚按下的状态,则记住,mainView的起始x
      if (UIGestureRecognizerStateBegan == sender.state) {
        _startX = self.mainView.frame.origin.x;
      }
       
       
      // 平移拖动的距离
      CGPoint delta = [sender translationInView:_mainView];
       
      CGRect frame = self.mainView.frame;
       
      // 计算新的x值,并做健壮性判断
      kEndX = _startX + delta.x;
       
      // 1,限制最大拖动范围
       
      if (kEndX >= kLeftWidth) {
        kEndX = kLeftWidth;
      }
      if (kEndX <= - kRightWidth) {
        kEndX = - kRightWidth;
      }
      // 2,由于 左view和右view在重叠,所以要隐藏其中的一个
      if (kEndX > 0) {
        // NSLog(@"--调用频率相当高--");
        _rightView.hidden = YES;
        _leftView.hidden = NO;
      } else {
        _rightView.hidden = NO;
        _leftView.hidden = YES;
      }
       
       
      if (UIGestureRecognizerStateEnded == sender.state) {
         
        // 手势结束的时候,需进行robust判断
         
        // 2,分析end松手时候,的位置x,决定展开到什么程度
    /*
        // 2.1 如果只向右拖了一点点,小于 1/2 的左view的宽度,则归0
        if (kEndX < 0.5*kLeftWidth && kEndX >= 0) {
          kEndX = 0;
        }else if (kEndX >= 0.5*kLeftWidth && kEndX <= kLeftWidth) {
          // 2.2 如果向右拖一大半了,大于 1/2 的左view的宽度,虽然还没到位,也可以认为是到位了
          kEndX = kLeftWidth;
        }else if (kEndX > - 0.5*kRightWidth && kEndX <= 0) {
          // 2.3 如果只向左拖了一点点,小于 1/2 的右view的宽度,则归0
          kEndX = 0;
        }else if (kEndX <= - 0.5*kRightWidth) {
          // 2.4 如果向左拖一大半了,大于 1/2 的右view的宽度,虽然还没到位,也可以认为是到位了
          kEndX = - kRightWidth;
        }
    */
         
         
        // 第2种判断方式
        // 起始为0,delta.x大于0 代表向右滑动
        if (_startX == 0 && delta.x >0) {
          kEndX = kLeftWidth;
        }else if (_startX == 0 && delta.x < 0){
          // 起始为0,delta.x小于0 代表向左滑动
          kEndX = - kRightWidth;
        }else if (_startX == kLeftWidth && delta.x < 0){
          // 起始为kLeftWidth,delta.x小于0 代表向左滑动
          kEndX =0;
        }else if (_startX == - kRightWidth && delta.x > 0){
          // 起始为- kRightWidth,delta.x大于0 代表向右滑动
          kEndX = 0;
        }
         
     
         
      }
       
      // 最后,才设置mainView的新的frame
      [UIView animateWithDuration:0.2 animations:^{
            self.mainView.frame=frame;
      }];
       
       
       
      // 最后,为mainView所在的图层 添加阴影效果
      [self addShadowFormainViewWithEndX:kEndX];
       
    }
     
    // 自定义方法,为mainView所在的图层 添加阴影效果 (调用频率相当高)
    - (void)addShadowFormainViewWithEndX:(CGFloat)endX
    {
      // 1,点击工程,加号,导入第3方框架 #import <QuartzCore/QuartzCore.h>
       
      // 2,拿到mainView所在的图层,设置阴影 参数
      
      // NSLog(@"调用频率很高---");
      _mainView.layer.shadowColor = [UIColor blackColor].CGColor;
      _mainView.layer.shadowOpacity = 0.5;
      if (endX >= 0) {
        _mainView.layer.shadowOffset = CGSizeMake(-5, 0);
      } else {
        _mainView.layer.shadowOffset = CGSizeMake(5, 0);
      }
       
    }
     
    // 单击按钮,也一样可以展开 左右侧边栏
    - (IBAction)btnClick:(UIButton *)sender
    {
      // 定义一个临时变量
      CGFloat startX = _mainView.frame.origin.x;
       
       
      // 先为mainView所在的图层 添加阴影效果
      [self addShadowFormainViewWithEndX:sender.tag == 1?1:-1];
       
       
      // 定义一个临时变量
      CGFloat tempEndX = 0;
      // 左边的按钮被单击
      if (1 == sender.tag) {
    
        // 隐藏右半边
        _leftView.hidden = NO;
        _rightView.hidden = YES;
         
        if (startX == 0) {
          tempEndX = kLeftWidth;
        }else if (startX == kLeftWidth){
          tempEndX = 0;
        }
      } else {
        // 单击右边按钮, 隐藏左半边
        _leftView.hidden = YES;
        _rightView.hidden = NO;
        if (startX == 0) {
          tempEndX = - kRightWidth;
        }else if (startX == - kRightWidth){
          tempEndX = 0;
        }
      }
      // 最后才设置mainView的x,调用抽取出来的公共代码,设置mainView的x,参数是endX
      [self setmainViewX:tempEndX];
       
       
     
    }
     
     
    // 抽取出来的公共代码,设置mainView的x,参数是endX
    - (void)setmainViewX:(CGFloat)endX
    {
      CGRect frame = self.mainView.frame;
      frame.origin.x = endX;
      [UIView animateWithDuration:0.2 animations:^{
        self.mainView.frame=frame;
      }];
       
    }

    三个view提供给外面的属性都是weak

    动画效果用CATransform3DMakeScale

    第二种实现方式:

    .h

    #define rScreenHeight [UIScreen mainScreen].bounds.size.height
    #define rScreenWidth [UIScreen mainScreen].bounds.size.width
    
    #define rOffSet rScreenWidth / 4
    
    #import <UIKit/UIKit.h>
    
    @interface RLSideslipController : UIViewController
    
    /*
     *初始化方法
     *main      最中间的视图控制器
     *left      向右滑动时的视图控制器
     *
     */
    - (instancetype)initWithMainViewController:(UIViewController *)main
                            leftViewController:(UIViewController *)left;
    
    @end

    .m

    #define rMainFrame CGRectMake(0,0,rScreenWidth,rScreenHeight)
    #define rLeftFrame CGRectMake(-rOffSet,0,rScreenWidth,rScreenHeight)
    
    #define rVelocityRatio rOffSet / (rScreenWidth - rOffSet)
    
    #import "RLSideslipController.h"
    
    @interface RLSideslipController ()
    
    @property (nonatomic, strong) UIViewController * mainVC;
    @property (nonatomic, strong) UIViewController * leftVC;
    @property (nonatomic, strong) UIView * maskView;
    //左侧边缘手势
    @property (nonatomic, strong) UIScreenEdgePanGestureRecognizer * edge;
    //右滑手势
    @property (nonatomic, strong) UIPanGestureRecognizer * pan;
    //点击手势
    @property (nonatomic, strong) UITapGestureRecognizer * tap;
    
    @end
    
    #pragma mark - initalizer
    - (instancetype)initWithMainViewController:(UIViewController *)main leftViewController:(UIViewController *)left {
        if (self = [super init]) {
            self.mainVC = main;
            self.leftVC = left;
        }
        return self;
    }
    
    #pragma mark - load
    - (void)viewDidLoad {
        [super viewDidLoad];
        //设置两个视图的frame
        self.mainVC.view.frame = rMainFrame;
        self.leftVC.view.frame = rLeftFrame;
        //将两个视图添加进来,并且main在上层
        [self.view addSubview:self.leftVC.view];
        [self.view addSubview:self.mainVC.view];
        //初始添加侧滑手势
        [self.view addGestureRecognizer:self.edge];
    }
    
    #pragma mark - Getters
    - (UIScreenEdgePanGestureRecognizer *)edge {
        if (!_edge) {
            _edge = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToEdge:)];
            _edge.edges = UIRectEdgeLeft;//设置只有在左侧边缘滑动时才响应
        }
        return _edge;
    }
    
    - (UIPanGestureRecognizer *)pan {
        if (!_pan) {
            _pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToPan:)];
        }
        return _pan;
    }
    
    - (UITapGestureRecognizer *)tap {
        if (!_tap) {
            _tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToTap:)];
        }
        return _tap;
    }
    
    - (UIView *)maskView {
        if (!_maskView) {
            _maskView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, rScreenWidth, rScreenHeight)];
            _maskView.backgroundColor = [UIColor clearColor];
        }
        return _maskView;
    }
    
    #pragma mark - responds
    - (void)respondsToEdge:(UIScreenEdgePanGestureRecognizer *)sender {
        CGPoint transformPoint = [sender translationInView:self.view];
        switch (sender.state) {
            case UIGestureRecognizerStateBegan: {
                [self.maskView addGestureRecognizer:self.tap];
                [self.mainVC.view addSubview:self.maskView];
            }
                break;
            case UIGestureRecognizerStateChanged: {
                //不等式rScreenWidth * 3 / 2 - rOffSet >= mainCenterX >= rScreenWidth / 2
                CGFloat mainCenterX = MIN(rScreenWidth * 3 / 2 - rOffSet, MAX(rScreenWidth / 2, rScreenWidth / 2 + transformPoint.x));
                //不等式rScreenWidth / 2 >= mainCenterX >= rScreenWidth / 2 - rOffSet
                CGFloat leftCenterX = MIN(rScreenWidth / 2, MAX(rScreenWidth / 2 - rOffSet, rScreenWidth / 2 - rOffSet + transformPoint.x * rVelocityRatio));
                self.mainVC.view.center = CGPointMake(mainCenterX, rScreenHeight / 2);
                self.leftVC.view.center = CGPointMake(leftCenterX, rScreenHeight / 2);
            }
                break;
            case UIGestureRecognizerStateEnded: {
                CGFloat mainCurrentCenterX = self.mainVC.view.center.x;//当前主视图的位置
                CGFloat allOffSet = rScreenWidth - rOffSet;//主视图应该移动的偏移量
                CGFloat ratio = (mainCurrentCenterX - rScreenWidth / 2) / allOffSet;//当前完成了得百分比
                __weak typeof(self)weakSelf = self;
                if (ratio >= 0.6) {
                    //完成显示的剩余动画
                    [self showWithRatio:ratio completion:^{
                        [weakSelf.view removeGestureRecognizer:weakSelf.edge];
                        [weakSelf.mainVC.view addGestureRecognizer:weakSelf.pan];
                    }];
                }else {
                    //完成消失的剩余动画
                    [self dismissWithRatio:ratio completion:^{
                        [weakSelf.maskView removeGestureRecognizer:weakSelf.tap];
                        [weakSelf.maskView removeFromSuperview];
                    }];
                }
            }
                break;
            default:
                break;
        }
    }
    
    - (void)respondsToPan:(UIPanGestureRecognizer *)sender {
        CGPoint transformPoint = [sender translationInView:self.view];
        //如果向右滑动,则直接返回
        if (transformPoint.x > 0) {
            return;
        }
        switch (sender.state) {
            case UIGestureRecognizerStateChanged: {
                //不等式rScreenWidth * 3 / 2 - rOffSet >= mainCenterX >= rScreenWidth / 2
                CGFloat mainCenterX = MIN(rScreenWidth * 3 / 2 - rOffSet, MAX(rScreenWidth / 2, rScreenWidth * 3 / 2 - rOffSet + transformPoint.x));
                //不等式rScreenWidth / 2 >= mainCenterX >= rScreenWidth / 2 - rOffSet
                CGFloat leftCenterX = MIN(rScreenWidth / 2, MAX(rScreenWidth / 2 - rOffSet, rScreenWidth / 2 + transformPoint.x * rVelocityRatio));
                self.mainVC.view.center = CGPointMake(mainCenterX, rScreenHeight / 2);
                self.leftVC.view.center = CGPointMake(leftCenterX, rScreenHeight / 2);
            }
                break;
            case UIGestureRecognizerStateEnded: {
                CGFloat mainCurrentCenterX = self.mainVC.view.center.x;//当前主视图的位置
                CGFloat allOffSet = rScreenWidth - rOffSet;//主视图应该移动的偏移量
                CGFloat ratio = (mainCurrentCenterX - rScreenWidth / 2) / allOffSet;//当前完成了得百分比
                if (ratio < 0.4) {
                    __weak typeof(self)weakSelf = self;
                    [self dismissWithRatio:ratio completion:^{
                        [weakSelf.view addGestureRecognizer:weakSelf.edge];
                        [weakSelf.mainVC.view removeGestureRecognizer:weakSelf.pan];
                        [weakSelf.maskView removeGestureRecognizer:weakSelf.tap];
                        [weakSelf.maskView removeFromSuperview];
                    }];
                }else {
                    [self showWithRatio:1 - ratio completion:nil];
                }
            }
                break;
            default:
                break;
        }
    }
    
    - (void)respondsToTap:(UITapGestureRecognizer *)sender {
        __weak typeof(self)weakSelf = self;
        [self dismissWithRatio:1 completion:^{
            [weakSelf.view addGestureRecognizer:weakSelf.edge];
            [weakSelf.mainVC.view removeGestureRecognizer:weakSelf.pan];
            [weakSelf.maskView removeGestureRecognizer:weakSelf.tap];
            [weakSelf.maskView removeFromSuperview];
        }];
    }
    
    #pragma mark - show or dismiss
    - (void)showWithRatio:(CGFloat)ratio completion:(void(^)(void))comple  {
        __weak typeof(self)weakSelf = self;
        [UIView animateWithDuration:1 * (1 - ratio) animations:^{
            weakSelf.mainVC.view.center = CGPointMake(rScreenWidth * 3 / 2 - rOffSet, rScreenHeight / 2);
            weakSelf.leftVC.view.center = CGPointMake(rScreenWidth / 2, rScreenHeight / 2);
        } completion:^(BOOL finished) {
            if (comple) {
                comple();
            }
        }];
    }
    
    - (void)dismissWithRatio:(CGFloat)ratio completion:(void(^)(void))comple {
        __weak typeof(self)weakSelf = self;
        [UIView animateWithDuration:1 * ratio animations:^{
            weakSelf.mainVC.view.center = CGPointMake(rScreenWidth / 2, rScreenHeight / 2);
            weakSelf.leftVC.view.center = CGPointMake(rScreenWidth / 2 - rOffSet, rScreenHeight / 2);
        } completion:^(BOOL finished) {
            if (comple) {
                comple();
            }
        }];
    }
  • 相关阅读:
    EFCore实践教程三
    EFCore实践测试二
    EFCore实践测试一
    git学习3
    git学习2
    git学习1
    ABP学习
    autofac笔记
    时间计算本质理论3-平行宇宙,对未来的子线程计算
    时间计算本质理论2-时间计算速度的不同步
  • 原文地址:https://www.cnblogs.com/HJQ2016/p/5870082.html
Copyright © 2011-2022 走看看