抽屉效果实现原理

实现一个简单的抽屉效果:

核心思想:KVO实现监听mainV的frame值的变化

核心代码:

#import "ViewController.h"

// @"frame"

#define XMGkeyPath(objc, keyPath) @(((void)objc.keyPath, #keyPath))

// 在宏里面如果在参数前添加了#,就会把参数变成C语言字符串

// 获取屏幕的宽度
#define screenW [UIScreen mainScreen].bounds.size.width

// 获取屏幕的高度
#define screenH [UIScreen mainScreen].bounds.size.height

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 添加所有的子控件
    [self setUpAllChildView];

    // 添加拖拽手势
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];

    [_mainV addGestureRecognizer:pan];

    // KVO作用:时刻监听某个对象的某个属性的改变
    // _main frame属性的改变
    // Observer:观察者
    // KeyPath:监听的属性
    // NSKeyValueObservingOptionNew:表示监听新值的改变
    [_mainV addObserver:self forKeyPath:XMGkeyPath(_mainV, frame) options:NSKeyValueObservingOptionNew context:nil];

    // 给控制器的view添加一个点按

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)];

    [self.view addGestureRecognizer:tap];

}

- (void)tap
{
    if (_mainV.frame.origin.x != 0) {
        // 把_mainV还原最开始的位置

        [UIView animateWithDuration:0.25 animations:^{
            _mainV.frame = self.view.bounds;

        }];

    }
}

// 只要监听的属性一改变,就会调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (_mainV.frame.origin.x > 0) { // 往右滑动,显示左边控件,隐藏右边控件
        _rightV.hidden = YES;
    }else if (_mainV.frame.origin.x < 0){ // 往左滑动,显示右边控件
        _rightV.hidden = NO;
    }
}

// 注意:当对象被销毁的时候,一定要注意移除观察者
- (void)dealloc
{
    // 移除观察者
    [_mainV removeObserver:self forKeyPath:XMGkeyPath(_mainV, frame)];
}

#define targetR 300

#define targetL -230

- (void)pan:(UIPanGestureRecognizer *)pan
{
    // 获取手势的偏移量
    CGPoint transP = [pan translationInView:_mainV];

    // 获取x轴的偏移量,相对于上一次
    CGFloat offsetX = transP.x;

    // 修改最新的main.frame,
    _mainV.frame = [self frameWithOffsetX:offsetX];

    // 复位
    [pan setTranslation:CGPointZero inView:_mainV];

    // 判断下当前手指有没有抬起,表示手势结束
    if (pan.state == UIGestureRecognizerStateEnded) { // 手指抬起,定位
        // x>屏幕的一半,定位到右边某个位置
        CGFloat target = 0;
        if (_mainV.frame.origin.x > screenW * 0.5) {
            target = targetR;
        }else if (CGRectGetMaxX(_mainV.frame) < screenW * 0.5){
            // 最大的x < 屏幕一半的时候,定义到左边某个位置
            target = targetL;
        }

        // 获取x轴的偏移量
        CGFloat offsetX = target - _mainV.frame.origin.x;

        [UIView animateWithDuration:0.25 animations:^{

            _mainV.frame = [self frameWithOffsetX:offsetX];
        }];

    }
}

#define XMGMaxY 100

// 给定一个x轴的偏移量计算下最新main的frame
- (CGRect)frameWithOffsetX:(CGFloat)offsetX
{

    // 获取当前main的frame
    CGRect frame = _mainV.frame;

    // 计算当前的x,y,w,h
    // 获取最新的x
    CGFloat x = frame.origin.x + offsetX;

    // 获取最新的y
    CGFloat y = x / screenW * XMGMaxY;

    // 当用户往左边移动的时候,_main.x < 0,y需要增加,为正
    if (frame.origin.x < 0) {
        y = -y;
    }

    // 获取最新的h
    CGFloat h = screenH - 2 * y;

    // 获取缩放比例
    CGFloat scale = h / screenH;

    // 获取最新的w
    CGFloat w = screenW * scale;

    return CGRectMake(x, y, w, h);
}

// 添加所有的子控件
- (void)setUpAllChildView
{
    // left
    UIView *leftV = [[UIView alloc] initWithFrame:self.view.bounds];
    leftV.backgroundColor = [UIColor greenColor];
    [self.view addSubview:leftV];
    _leftV = leftV;

    // right
    UIView *rightV = [[UIView alloc] initWithFrame:self.view.bounds];
    rightV.backgroundColor = [UIColor blueColor];
    [self.view addSubview:rightV];
    _rightV = rightV;

    // main
    UIView *mainV = [[UIView alloc] initWithFrame:self.view.bounds];
    mainV.backgroundColor = [UIColor redColor];
    [self.view addSubview:mainV];
    _mainV = mainV;
}

@end

用法:

继承ViewController

实现如下代码即可:

#import "SlideViewController.h"

@interface SlideViewController ()

@end

@implementation SlideViewController

- (void)viewDidLoad{
    [super viewDidLoad];
    NSLog(@"%s",__func__);

    // 创建一个tableView控制器
    UITableViewController *tableVc = [[UITableViewController alloc] init];

    tableVc.view.frame = self.mainV.bounds;

    [self.mainV addSubview:tableVc.view];

    // 设计原理,如果A控制器的view成为b控制器view的子控件,那么这个A控制器必须成为B控制器的子控制器
    [self addChildViewController:tableVc];

    UIViewController *VC = [[UIViewController alloc] init];

    UIImageView *imagev = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"胸小别讲话"]];

    //    imagev.contentMode = UIViewContentModeScaleAspectFill;

    imagev.frame = VC.view.frame;

    [VC.view addSubview:imagev];

    [self.rightV addSubview:VC.view];

    [self addChildViewController:VC];

}

@end

github地址:https://github.com/chglog/drawer

原文地址:https://www.cnblogs.com/chglog/p/9133278.html

时间: 2024-10-25 19:22:26

抽屉效果实现原理的相关文章

剖析Path侧边栏抽屉效果原理(抽屉效果,Path效果)

如今很多App应用,都用到了侧边栏的效果,比如网易新闻(还带有偏移缩小),今日头条(普遍这种),Path(最先应用这种抽屉效果,所以这种效果也叫Path效果),code4App上已经有很多网友写的第三方侧边栏类,大家可以直接拿来用.这里我主要的是介绍一下这种效果的实现原理,涉及了几个知识点,在其他地方也能用到. UINavigationController和UITabBarController是2个主要的视图控制容器,都有属性viewControllers,能够很好地管理多个视图控制器.但有的时

抽屉效果的实现原理

@property (nonatomic, strong)UIImageView *choytiimage; @property (nonatomic, strong)UIButton *choutibutton; @property (nonatomic, strong)UIButton *button; @property (nonatomic, strong)UILabel *label; @property (nonatomic, strong)UILabel *label1; @pro

第三方抽屉效果

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

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.初始化方法先初始化左视图和中心视