文档章节

QQ界面 抽屉效果

商永祥
 商永祥
发布于 2015/12/15 12:28
字数 1122
阅读 90
收藏 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
【Android进阶】多抽屉效果 (类似最早QQ使用的效果)

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

晨曦之光
2012/03/01
5.8K
4
急事求教,关于抽提效果的问题!!

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

YCJ1314
2012/08/26
38
0
MMDrawerController左边抽屉push的三种情况

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

文学振噢
01/04
0
0
盘点2014不容错过的UI源码

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

牵着蜗牛去西藏
2014/12/31
2.4K
4

没有更多内容

加载失败,请刷新页面

加载更多

FTP 协议 1.0

自己制作的FTP协议:

Explorer0
9分钟前
0
0
Android 通过DrawableInflater加载自定义Drawable

一、Drawable 在Android系统张,图形图像的绘制需要在画布上进行操作和处理,但是绘制需要了解很多细节以及可能要进行一些复杂的处理,因此系统提供了一个被称之为Drawable的类来进行绘制处理...

IamOkay
20分钟前
1
0
灵活无处安放,所以选择流浪....《漆黑的空间》& 《灰色轨迹》

灵活无处安放,所以选择流浪....《漆黑的空间》& 《灰色轨迹》

yizhichao
26分钟前
1
0
Kafka+Flink 实现准实时异常检测系统

1.背景介绍 异常检测可以定义为“基于行动者(人或机器)的行为是否正常作出决策”,这项技术可以应用于非常多的行业中,比如金融场景中做交易检测、贷款检测;工业场景中做生产线预警;安防...

架构师springboot
今天
7
0
DecimalFormat 类基本使用

/* * DecimalFormat 类主要靠 # 和 0 两种占位符号来指定数字长度 * 0 表示如果位数不足则以 0 填充 * # 表示只要有可能就把数字拉上这个位置 * */ public static void main(String[] args){...

嘴角轻扬30
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部