ios侧滑菜单控件

先上效果图把:


ios侧滑菜单控件_第1张图片
左侧拖动.gif

ios侧滑菜单控件_第2张图片
![右侧点击.gif](http://upload-images.jianshu.io/upload_images/1249505-2b9771b56dc93e1e.gif?imageMogr2/auto-orient/strip)

项目有这个需求,之前是别人做的效果不太好,后来需要重写,但还是不是我负责,但是那段时间不算很忙,也用自己的思路尝试着写了一下,实现的效果很差。
现在这个完成效果是项目组的主程写的,最近有空看了一下代码,然后自己模仿着重写了一下。

看完代码,其实实现思路很简单
1.在控制器中添加三个UIView,分别用来放三个子控制器;
2.为view添加panGesture,在手势的delegate中获取位移来处理界面变化;
3.利用UIView的transform属性来实现界面的变化和移动。

关于transform属性,是用矩阵乘法对界面进行位移,旋转,放大缩小等,其实可以简单理解为基于参考坐标系做出一系列变化:

CGAffineTransformRotate // 旋转
CGAffineTransformScale // 放大缩小
CGAffineTransformTranslate // 位移

基本思路就是这样,接下来是具体实现:

1.初始化方法:
- (instancetype)initWithMainViewController:(UIViewController *)mainVC
leftViewController:(UIViewController *)leftVC
rightViewController:(UIViewController *)rightVC
{
self = [super init];

      if (self) {
        [self prepare];
        self.mainViewController = mainVC;
        self.leftViewController = leftVC;
        self.rightViewController = rightVC;
    }
    return self;
}

2.初始化界面:
为控制器添加_leftContainerView,_rightContainerView及_mainContainerView,在leftViewController的setter方法中做一些设置,配置界面的默认位置及大小等:
- (void)setLeftViewController:(UIViewController *)leftViewController
{
if (!leftViewController) {
return;
}
_canShowLeft = YES;
_leftViewController = leftViewController;

    _leftViewController.view.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
    [self addChildViewController:leftViewController];
    [_leftContainerView addSubview:leftViewController.view];
    _leftContainerView.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, -leftShowWidth, 0);
    _leftContainerView.transform = CGAffineTransformScale(_leftContainerView.transform, leftScale, leftScale);
}

此处使用的参数为预先设置好的,可以修改leftScale或rightScale,改变为图1或图3的显示效果:
#pragma mark ---------- left config -----------
static CGFloat const leftShowWidth = 240.f;
static CGFloat const leftScale = 0.8f; // 缩放比例
static CGFloat const leftDragbleWidth = 80.f; // 左侧可拖动宽度
static CGFloat const leftMinDragLength = 100.f; //触发所需要拖动的最短距离

3.做好界面默认配置以后,需要的就是添加Pan手势,并做处理,
此处只表述思路,实际代码复杂的多
- (void)panGestureHandler:(UIPanGestureRecognizer *)gesture
{
CGPoint point = [gesture locationInView:self.view];

    switch (gesture.state) {
        case UIGestureRecognizerStateBegan:
        {
          // 记录拖拽的起点
            _startDragPoint = point;
            _lastDragPoint = point;
        }
        break;
        case UIGestureRecognizerStateChanged:
        {
             CGFloat move_length = point.x - _lastDragPoint.x;
             CGFloat scale = 1;
              _lastDragPoint = point;
            // 进行判断是呼出哪边的界面  此处写呼出左侧界面
              scale = 1-(move_length/leftShowWidth)*(1-leftScale);
                    
            // 根据拖拽移动的距离进行界面的变化
              _mainContainerView.transform = CGAffineTransformTranslate(_mainContainerView.transform, move_length, 0);
              _mainContainerView.transform = CGAffineTransformScale(_mainContainerView.transform, scale, scale);
                    
              CGFloat left_scale = 1+(move_length/leftShowWidth)*(1-leftScale);
              _leftContainerView.transform = CGAffineTransformTranslate(_leftContainerView.transform, move_length, 0);
              _leftContainerView.transform = CGAffineTransformScale(_leftContainerView.transform, left_scale, left_scale);                 
        }
        break;
        case UIGestureRecognizerStateEnded:
        {                            
              CGFloat move_length = fabs(point.x - _startDragPoint.x);
              // 判断拖拽距离是否足够显示或隐藏界面 
              // 此处只作为例子,以左侧界面为例子
                if (move_length>leftMinDragLength) {
                    if (_isLeftShow) {
                        [self hideLeft];
                    }else{
                        [self showLeft];
                    }
                }else{
                    if (_isLeftShow) {
                        [self showLeft];
                    }else{
                        [self hideLeft];
                    }
        }
        break;

上述代码中,进行界面变化前还需增加判断,何时停止变化。

在show和hide方法中,需要进行动画duration的计算,然后进行界面变化。剩下的基本就是在两个leftController和rightController中进行界面布局了。

由于使用了多个controller,所以leftController和rightController的跳转操作要交由mainController的navigationController来进行,代码中提供了属性以供跳转,若有不同需求,需要重写此属性的getter方法。

@property (nonatomic, strong, readonly) UINavigationController *sliderNavigationController;

基本思路就是这样,比较复杂的基本上是界面位移缩放比例的换算,需要在GestureChanged状态中进行处理。

github地址

若有BUG或改进方法,欢迎留言或给我发邮件。

你可能感兴趣的:(ios侧滑菜单控件)