文档章节

QQ界面 抽屉效果

商永祥
 商永祥
发布于 2015/12/15 12:28
字数 1122
阅读 88
收藏 1

闲来无事做的一个QQ界面的抽屉,简单地封装了调用的方法,拖到工程里面可以直接使用

方法是最底层的view是你的抽屉列表视图,需要将主页控制器的view直接加到抽屉控制器的view上面。当你侧滑或者是点击右上角按钮的时候,直接改变主页view的坐标系就可以。

在新建的ViewController中封装需要调用的方法

/**
 *  初始化抽屉视图和主页视图
 *
 *  @param
 */
- (instancetype)initWithLeftView:(UIViewController *)leftVC
                     andMainView:(UIViewController *)mainVC{
    self = [super init];
    if (self) {
        self.speedf = 0.7;
        self.leftVC = leftVC;
        self.mainVC = mainVC;
        
        // 滑动手势
        self.pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGestureAction:)];
        [self.mainVC.view addGestureRecognizer:self.pan];
        
        [self.pan setCancelsTouchesInView:YES];
        self.pan.delegate = self;
        
        self.leftVC.view.hidden = YES;
        [self.view addSubview:self.leftVC.view];
        
        // 蒙版
        UIView * view = [[UIView alloc]initWithFrame:self.leftVC.view.bounds];
        view.backgroundColor = [UIColor blackColor];
        self.contentView = view;
        [self.leftVC.view addSubview:self.contentView];
        
        // 获取左侧TableView
        for (UIView * obj in self.leftVC.view.subviews) {
            if ([obj isKindOfClass:[UITableView class]]) {
                self.leftTableView = (UITableView *)obj;
            }
        }
        
        self.leftTableView.backgroundColor = [UIColor clearColor];
        self.leftTableView.frame = CGRectMake(0, 0, WIDTH - 100, HEIGHT);
        
        [self.view addSubview:self.mainVC.view];
        self.closed = YES;//初始时侧滑窗关闭
    }
    return self;
}

里面的leftVC就是列表的抽屉视图,mainVC就是主页视图。外部初始化一个控制器的时候直接调用这个方法就行。

然后就是在视图将要出现的时候让抽屉视图隐藏

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    self.leftVC.view.hidden = NO;
}

关闭抽屉视图

// 关闭视图
- (void)closeLeftView{
    [UIView beginAnimations:nil context:nil];
    self.mainVC.view.transform = CGAffineTransformScale(CGAffineTransformIdentity,1.0,1.0);
    self.mainVC.view.center = CGPointMake(WIDTH / 2, HEIGHT / 2);
    self.closed = YES;
    
    self.leftTableView.center = CGPointMake(30, HEIGHT * 0.5);
    self.leftTableView.transform = CGAffineTransformScale(CGAffineTransformIdentity,1,1);
    self.contentView.alpha = kLeftAlpha;
    
    [UIView commitAnimations];
}

打开抽屉视图

// 打开左视图
- (void)openLeftView{

    [UIView beginAnimations:nil context:nil];
    self.mainVC.view.transform = CGAffineTransformScale(CGAffineTransformIdentity,1,1);
    self.mainVC.view.center = kMainPageCenter;
    self.closed = NO;
    
    self.leftTableView.center = CGPointMake((WIDTH - 100) * 0.5, HEIGHT * 0.5);
    self.leftTableView.transform = CGAffineTransformScale(CGAffineTransformIdentity,1.0,1.0);
    self.contentView.alpha = 0;
    
    [UIView commitAnimations];
    // [self disableTapButton];
}

设置滑动开关 这里是要让手势不冲突 因为在抽屉视图显现的时候需要将手势关掉

/**
 *  设置滑动开关是否开启
 *
 *  @param enabled YES:支持滑动手势,NO:不支持滑动手势
 */
- (void)setPanEnabled: (BOOL) enabled{

    [self.pan setEnabled:enabled];

}

单击手势

#pragma mark - 单击手势
-(void)handeTap:(UITapGestureRecognizer *)tap{
    
    if ((!self.closed) && (tap.state == UIGestureRecognizerStateEnded))
    {
        [UIView beginAnimations:nil context:nil];
        tap.view.transform = CGAffineTransformScale(CGAffineTransformIdentity,1.0,1.0);
        tap.view.center = CGPointMake([UIScreen mainScreen].bounds.size.width/2,[UIScreen mainScreen].bounds.size.height/2);
        self.closed = YES;
        
        self.leftTableView.center = CGPointMake(30, HEIGHT * 0.5);
        self.leftTableView.transform = CGAffineTransformScale(CGAffineTransformIdentity,0.7,0.7);
        self.contentView.alpha = kLeftAlpha;
        
        [UIView commitAnimations];
        _scalef = 0;
        // [self removeSingleTap];
    }
    
}

下面就是UIPanGestureRecognizer手势的实现方法 里面是将视图的改变封装了起来

// 手势触发事件
- (void)panGestureAction:(UIPanGestureRecognizer *)panAction{

    CGPoint point = [panAction translationInView:self.view];
    _scalef = (point.x * self.speedf + _scalef);

    BOOL needMoveWithTap = YES; // 是否跟随手势移动
    if (((self.mainVC.view.frame.origin.x <= 0) && (_scalef <= 0)) || ((self.mainVC.view.frame.origin.x >= (WIDTH - 100 )) && (_scalef >= 0))) {
        //
        _scalef = 0;
        needMoveWithTap = NO;
    }
    
    // 根据视图位置判断是左滑还是右滑
    if (needMoveWithTap && (panAction.view.frame.origin.x >= 0) && (panAction.view.frame.origin.x <= (WIDTH - 100))) {
        CGFloat panCenterX = panAction.view.center.x + point.x * self.speedf;
        if (panCenterX < WIDTH * 0.5 - 2) {
            panCenterX = WIDTH * 0.5;
        }
        CGFloat panCenterY = panAction.view.center.y;
        panAction.view.center = CGPointMake(panCenterX, panCenterY);
        
        // scale
        CGFloat scale = 1;
        panAction.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, scale, scale);
        [panAction setTranslation:CGPointMake(0, 0) inView:self.view];
        CGFloat leftTabCenterX = 30 + ((WIDTH - 100) * 0.5 - 30) * (panAction.view.frame.origin.x / (WIDTH - 100));
        NSLog(@"%f",leftTabCenterX);
        
        // leftScale
        CGFloat leftScale = 0.7 + (1 - 0.7) * (panAction.view.frame.origin.x / (WIDTH - 100));
        
        self.leftTableView.center = CGPointMake(leftTabCenterX, HEIGHT * 0.5);
        self.leftTableView.transform = CGAffineTransformScale(CGAffineTransformIdentity, leftScale,leftScale);
        
        //tempAlpha kLeftAlpha~0
        CGFloat tempAlpha = kLeftAlpha - kLeftAlpha * (panAction.view.frame.origin.x / (WIDTH - 100));
        self.contentView.alpha = tempAlpha;

    }else{
        //超出范围,
        if (self.mainVC.view.frame.origin.x < 0){
            [self closeLeftView];
            _scalef = 0;
        }
        else if (self.mainVC.view.frame.origin.x > (WIDTH - 100)){
            [self openLeftView];
            _scalef = 0;
        }
    }
    //手势结束后修正位置,超过约一半时向多出的一半偏移
    if (panAction.state == UIGestureRecognizerStateEnded) {
        if (fabs(_scalef) > vCouldChangeDeckStateDistance)
        {
            if (self.closed)
            {
                [self openLeftView];
            }
            else
            {
                [self closeLeftView];
            }
        }
        else
        {
            if (self.closed)
            {
                [self closeLeftView];
            }
            else
            {
                [self openLeftView];
            }
        }
        _scalef = 0;
    }
}

Delegate的实现方法

#pragma mark - Delegate
-(BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldReceiveTouch:(UITouch*)touch {
    
    if(touch.view.tag == vDeckCanNotPanViewTag)
    {
        //        NSLog(@"不响应侧滑");
        return NO;
    }
    else
    {
        //        NSLog(@"响应侧滑");
        return YES;
    }
}

下面是我用到一些宏定义

#define WIDTH [UIScreen mainScreen].bounds.size.width
#define HEIGHT [UIScreen mainScreen].bounds.size.height
#define SIZE [UIScreen mainScreen].bounds.size
#define vCouldChangeDeckStateDistance  (WIDTH - 100) / 2.0 - 40 //滑动距离大于此数时,状态改变(关--》开,或者开--》关)
#define kMainPageCenter  CGPointMake(WIDTH + WIDTH * 1 / 2.0 - 100, HEIGHT / 2)  //打开左侧窗时,中视图中心点
#define vDeckCanNotPanViewTag    20000 // 不响应此侧滑的View的tag

#define kLeftAlpha 0.9  //左侧蒙版的最大值

最后外部调用的时候要在appDelegate中初始化

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window  = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    [self.window makeKeyAndVisible];
    self.window.backgroundColor = [UIColor whiteColor];
    
    MainViewController * mainVC = [[MainViewController alloc]init];
    self.mainNC = [[RootNavigationController alloc]initWithRootViewController:mainVC];
    
    LeftSortViewController * leftSoutVC = [[LeftSortViewController alloc]init];
    UINavigationController * leftNC = [[UINavigationController alloc]initWithRootViewController:leftSoutVC];
    
    self.leftSlideVC = [[LeftSlideViewController alloc]initWithLeftView:leftNC andMainView:self.mainNC];
    self.leftSlideVC.title = @"抽屉视图";
    
    self.window.rootViewController = self.leftSlideVC;
    
    [[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"BackImage"] forBarMetrics:UIBarMetricsDefault];

    return YES;
}

创建两个视图去实现 还有一点就是在抽屉视图里面的点击方法 需要先调用隐藏的方法,然后push到需要跳转的页面,这里也可以不用push 。 让需要跳转界面的view直接替换掉mainVC的view。

这里是抽屉视图的点击方法

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    AppDelegate *tempAppDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    OtherViewController *vc = [[OtherViewController alloc] init];
    [tempAppDelegate.leftSlideVC closeLeftView];//关闭左侧抽屉
    
    [tempAppDelegate.mainNC pushViewController:vc animated:NO];
}


© 著作权归作者所有

共有 人打赏支持
商永祥
粉丝 0
博文 5
码字总数 3007
作品 0
济南
高仿QQ空间-更新篇

代码下载链接:http://pan.baidu.com/s/1i30F6Rz 更新内容 一 更新了登陆界面 二 增加了输入时密码时和登陆成功后播放音频的效果 三 增加了导航条渐隐的效果(和真实QQ空间的导航条一样,首先...

不孤独的美食家
2015/09/13
496
2
急事求教,关于抽提效果的问题!!

@晨曦之光 你好,想跟你请教个问题:我看到你的抽屉效果类似QQ好友列表的代码, 但是我把他加入到我的程序中之后不能够实现点开抽屉的效果呢!不知道能不能和你取得联系呢!谢谢了!!我的Q...

YCJ1314
2012/08/26
38
0
【Android进阶】多抽屉效果 (类似最早QQ使用的效果)

也不知道该怎么取名,暂且就叫他多抽屉效果吧~~ 最早QQ就是这样的效果,点一下,还有声音,呵呵。 一晃,都过去那么多年了... 废话不多说了,看下效果: 这个就是类似抽屉的效果,这边做了三...

晨曦之光
2012/03/01
5.7K
4
盘点2014不容错过的UI源码

好的UI设计不仅是让软件变得有个性有品味,还要让软件的操作变得舒适、简单、自由、充分体现软件的定位和特点。有没有想要的效果还没有实现的,这里有现成的UI源码哦,需要的拿去。 QQ v4.7....

牵着蜗牛去西藏
2014/12/31
2.1K
4
MMDrawerController左边抽屉push的三种情况

总结了大部分的界面 大概就如下三种情况: 打开左边抽屉,按钮后左边push到center控制器,这个控制器直接显示全部 (类似知乎日报) 思路:设置left的抽屉为center的nav并且关闭抽屉 打开左边抽...

文学振噢
01/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

同样是工作3年程序员,为什么别人每月25K你却只有15K?

你有没有静下心来思考过:同样是做了x年Java开发,为什么你的技术比别人差很多?为什么别人每月26K你却只有15K? 其实技术水平的高低和个人智商关系不大(毕竟能做Java编程开发大家都不会差)...

Java填坑之路
12分钟前
0
0
跨域问题:解决跨域的三种方案

当前端页面与后台运行在不同的服务器时,就必定会出现跨域这一问题,本篇简单介绍解决跨域的三种方案,部分代码截图如下,仅供参考: 方式一:使用ajax的jsonp 前端代码 服务器代码 使用该方...

rechardchensir
12分钟前
0
0
linux学习-1012

8.6 管道符和作业控制 8.7/8.8 shell变量 8.9 环境变量配置文件 扩展 bashrc和bash_profile的区别 http://ask.apelearn.com/question/7719 简易审计系统: http://www.68idc.cn/help/server/...

wxy丶
13分钟前
0
0
springboot dubbo 在程序初始化完成前 使用回声测试对服务依赖检测

<dubbo:consumer timeout="10000" check="false" /><dubbo:service delay="-1" /> @Component@Order(2)public class PrkServiceInit implements ApplicationListener {private Logge......

林伟琨
15分钟前
0
0
“网红架构师”解决你的Ceph 运维难题

Q1. 环境预准备 绝大多数MON创建的失败都是由于防火墙没有关导致的,亦或是SeLinux没关闭导致的。一定一定一定要关闭每个每个每个节点的防火墙(执行一次就好,没安装报错就忽视): CentOS s...

编程SHA
19分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部