iOS实现简单抽屉效果

2020-02-22 09:58:28王冬梅

抽屉效果

所谓抽屉效果就是三个视图,向右拖拽显示左边的视图,向左拖拽显示右边的视图,当拖拽大于屏幕的一半时最上面的视图会自动定位到一边,当点击左边或右边视图时会最上面视图会自动复位。

效果如图:三个视图(左边:浅灰色视图、右边:品红视图、主视图:黑色视图)

封装代码

DrawerViewController

#import <UIKit/UIKit.h>
@interface DrawerViewController : UIViewController

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

@end

// -------------------------------------------------------
#import "DrawerViewController.h"

#define ScreenWidth [UIScreen mainScreen].bounds.size.width
#define ScreenHeight [UIScreen mainScreen].bounds.size.height
#define MaxOffsetY 100
#define MaxOffsetX ([UIScreen mainScreen].bounds.size.width - 100)

@implementation DrawerViewController
- (void)viewDidLoad {
  [super viewDidLoad];

  // 1. 初始化视图
  [self setup];

  // 2. 给mainView添加拖动手势
  UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGesture:)];
  [self.mainView addGestureRecognizer:panGestureRecognizer];

  // 3. 给self.view添加一个单击手势
  UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)];
  [self.view addGestureRecognizer:tap];
}

- (void)tapGesture:(UITapGestureRecognizer *)tap {
  // mainView复位
  [UIView animateWithDuration:0.2 animations:^{
    self.mainView.frame = self.view.bounds;
  }];
}

- (void)panGesture:(UIPanGestureRecognizer *)pan {
  CGPoint offsetPoint = [pan translationInView:self.view];
  self.mainView.frame = [self frameWithOffset:offsetPoint.x];

  if (self.mainView.frame.origin.x > 0) {
    // → 右移(显示leftView)
    self.rightView.hidden = YES;
  } else if (self.mainView.frame.origin.x < 0) {
    // ← 左移(显示rightView)
    self.rightView.hidden = NO;
  }

  // 如果拖拽结束,自动定位
  CGFloat targetOffsetX = 0;
  if (pan.state == UIGestureRecognizerStateEnded) {
    if (self.mainView.frame.origin.x >= ScreenWidth * 0.5) { // 右侧
      targetOffsetX = MaxOffsetX;
    } else if (CGRectGetMaxX(self.mainView.frame) < ScreenWidth * 0.5){ // 左侧
      targetOffsetX = -MaxOffsetX;
    }

    // 计算出当前位置距离目标位置所需要的偏移距离
    CGFloat offsetX = targetOffsetX - self.mainView.frame.origin.x;

    // 滑动不到屏幕一般时仍然显示mainView(self.view.bounds) 否则自动定位到左侧或右侧
    CGRect mainFrame = targetOffsetX == 0 ? self.view.bounds : [self frameWithOffset:offsetX];
    [UIView animateWithDuration:0.2 animations:^{
      self.mainView.frame = mainFrame;
    }];
  }

  [pan setTranslation:CGPointZero inView:self.view];
}

- (CGRect)frameWithOffset:(CGFloat)offsetX {
  CGRect newFrame = self.mainView.frame;
  newFrame.origin.x += offsetX;   // x


  CGFloat offsetY = self.mainView.frame.origin.x * MaxOffsetY / ScreenWidth;
  newFrame.origin.y = fabs(offsetY);  // y

  CGFloat offsetHeight = ScreenHeight - (newFrame.origin.y * 2);
  newFrame.size.height = offsetHeight;  // height

  return newFrame;
}

- (void)setup {
  UIView *leftView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
  //leftView.backgroundColor = [UIColor lightGrayColor];
  _leftView = leftView;
  [self.view addSubview:leftView];

  UIView *rightView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
  //rightView.backgroundColor = [UIColor magentaColor];
  _rightView = rightView;
  [self.view addSubview:rightView];

  UIView *mainView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
  //mainView.backgroundColor = [UIColor blackColor];
  _mainView = mainView;
  [self.view addSubview:mainView];
}

@end