一个很好用的侧滑框架ICSDrawerController实现的 QQ 侧滑及换肤功能

使用ICSDrawerController 实现侧滑功能

在ICSDrawerController 第三方上做了修改实现,QQ 点击头像打开关抽屉头像渐变的效果

- (void)hiddenHeadView:(hiddenHeadViewBlock)block;
@property(nonatomic,copy) hiddenHeadViewBlock hiddenBlock;
- (void)hiddenHeadView:(hiddenHeadViewBlock)block
{
    self.hiddenBlock = block;
}

在拖拽滑动的手势方法中监听滑动的方法中来改变透明度

- (void)panGestureRecognized:(UIPanGestureRecognizer *)panGestureRecognizer
{
    NSParameterAssert(self.leftView);
    NSParameterAssert(self.centerView);

    UIGestureRecognizerState state = panGestureRecognizer.state;
    CGPoint location = [panGestureRecognizer locationInView:self.view];
    CGPoint velocity = [panGestureRecognizer velocityInView:self.view];

    switch (state) {

        case UIGestureRecognizerStateBegan:
            self.panGestureStartLocation = location;//记录当前的位置
            if (self.drawerState == ICSDrawerControllerStateClosed) {
                [self willOpen];
            }
            else {
                [self willClose];
            }
            break;

        case UIGestureRecognizerStateChanged: { //每次拖拽滑动
            CGFloat delta = 0.0f;
            if (self.drawerState == ICSDrawerControllerStateOpening) {
                delta = location.x - self.panGestureStartLocation.x;
            }
            else if (self.drawerState == ICSDrawerControllerStateClosing) {
                delta = kICSDrawerControllerDrawerDepth - (self.panGestureStartLocation.x - location.x);
            }

            CGRect l = self.leftView.frame;
            CGRect c = self.centerView.frame;
            if (delta > kICSDrawerControllerDrawerDepth) {
                l.origin.x = 0.0f;
                c.origin.x = kICSDrawerControllerDrawerDepth;
            }
            else if (delta < 0.0f) {
                l.origin.x = kICSDrawerControllerLeftViewInitialOffset;
                c.origin.x = 0.0f;
            }
            else {
                // While the centerView can move up to kICSDrawerControllerDrawerDepth points, to achieve a parallax effect
                // the leftView has move no more than kICSDrawerControllerLeftViewInitialOffset points
                l.origin.x = kICSDrawerControllerLeftViewInitialOffset
                           - (delta * kICSDrawerControllerLeftViewInitialOffset) / kICSDrawerControllerDrawerDepth;

                c.origin.x = delta;
                CGFloat alpha = 1 - delta/100/2.6;
                if (alpha > 1.0) {
                    alpha = 1.0;
                }else if(alpha < 0){
                    alpha = 0;
                }
                //头像是否显示隐藏
                self.hiddenBlock(alpha);
            }

            self.leftView.frame = l;
            self.centerView.frame = c;

            break;
        }

        case UIGestureRecognizerStateEnded: { //拖拽结束

            if (self.drawerState == ICSDrawerControllerStateOpening) {
                CGFloat centerViewLocation = self.centerView.frame.origin.x;
                if (centerViewLocation == kICSDrawerControllerDrawerDepth) {
                    // Open the drawer without animation, as it has already being dragged in its final position
                    [self setNeedsStatusBarAppearanceUpdate];
                    [self didOpen];
                }
                else if (centerViewLocation > self.view.bounds.size.width / 3
                         && velocity.x > 0.0f) {
                    // Animate the drawer opening
                    [self animateOpening];
                }
                else {
                    // Animate the drawer closing, as the opening gesture hasn‘t been completed or it has
                    // been reverted by the user
                    [self didOpen];
                    [self willClose];
                    [self animateClosing];
                }

            } else if (self.drawerState == ICSDrawerControllerStateClosing) {
                CGFloat centerViewLocation = self.centerView.frame.origin.x;
                if (centerViewLocation == 0.0f) {
                    // Close the drawer without animation, as it has already being dragged in its final position
                    [self setNeedsStatusBarAppearanceUpdate];
                    [self didClose];
                }
                else if (centerViewLocation < (2 * self.view.bounds.size.width) / 3
                         && velocity.x < 0.0f) {
                    // Animate the drawer closing
                    [self animateClosing];
                }
                else {
                    // Animate the drawer opening, as the opening gesture hasn‘t been completed or it has
                    // been reverted by the user
                    [self didClose];

                    // Here we save the current position for the leftView since
                    // we want the opening animation to start from the current position
                    // and not the one that is set in ‘willOpen‘
                    CGRect l = self.leftView.frame;
                    [self willOpen];
                    self.leftView.frame = l;

                    [self animateOpening];
                }
            }
        }
            break;

        default:
            break;
    }
}

#pragma mark - Animations
#pragma mark Opening animation
- (void)animateOpening
{
    NSParameterAssert(self.drawerState == ICSDrawerControllerStateOpening);
    NSParameterAssert(self.leftView);
    NSParameterAssert(self.centerView);

    // Calculate the final frames for the container views
    CGRect leftViewFinalFrame = self.view.bounds;
    CGRect centerViewFinalFrame = self.view.bounds;
    centerViewFinalFrame.origin.x = kICSDrawerControllerDrawerDepth;

    [UIView animateWithDuration:kICSDrawerControllerAnimationDuration
                          delay:0
         usingSpringWithDamping:kICSDrawerControllerOpeningAnimationSpringDamping
          initialSpringVelocity:kICSDrawerControllerOpeningAnimationSpringInitialVelocity
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         self.centerView.frame = centerViewFinalFrame;
                         self.leftView.frame = leftViewFinalFrame;
                         self.hiddenBlock(0);

                         [self setNeedsStatusBarAppearanceUpdate];
                     }
                     completion:^(BOOL finished) {
                         [self didOpen];
                     }];
}
#pragma mark Closing animation
- (void)animateClosing
{
    NSParameterAssert(self.drawerState == ICSDrawerControllerStateClosing);
    NSParameterAssert(self.leftView);
    NSParameterAssert(self.centerView);

    // Calculate final frames for the container views
    CGRect leftViewFinalFrame = self.leftView.frame;
    leftViewFinalFrame.origin.x = kICSDrawerControllerLeftViewInitialOffset;
    CGRect centerViewFinalFrame = self.view.bounds;

    [UIView animateWithDuration:kICSDrawerControllerAnimationDuration
                          delay:0
         usingSpringWithDamping:kICSDrawerControllerClosingAnimationSpringDamping
          initialSpringVelocity:kICSDrawerControllerClosingAnimationSpringInitialVelocity
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         self.centerView.frame = centerViewFinalFrame;
                         self.leftView.frame = leftViewFinalFrame;
                         self.hiddenBlock(1);

                         [self setNeedsStatusBarAppearanceUpdate];
                     }
                     completion:^(BOOL finished) {
                         [self didClose];
                     }];
}

给当前类扩充一个方法,拿到当前conroller的menuController

@interface UIViewController (ICSDrawerController)

//拿到当前conroller的menuController
//如果不存在,返回nil
@property (nonatomic, readonly) ICSDrawerController* menuController;

@end
@implementation UIViewController (ICSDrawerController)

- (ICSDrawerController *)menuController {

    if (self.parentViewController == nil) {
        return nil;
    }else if ([self.parentViewController isKindOfClass:[ICSDrawerController class]]) {
        return (ICSDrawerController* )self.parentViewController;
    }else {
        return self.parentViewController.menuController;
    }
}

@end

换皮肤功能使用 KVO 监听属性就可以实现,这里附上代码https://github.com/SummerHH/QQMenu

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px "PingFang SC"; color: #008400 }
span.s1 { }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #008400 }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px "PingFang SC"; color: #008400 }
span.s1 { }
span.s2 { font: 11.0px "PingFang SC" }
span.s3 { font: 11.0px Menlo }

时间: 2024-11-06 10:40:49

一个很好用的侧滑框架ICSDrawerController实现的 QQ 侧滑及换肤功能的相关文章

qt之窗口换肤(一个qss的坑:当类属性发现变化时需要重置qss)

1.相关文章 Qt 资源系统qt的moc,uic,rcc命令的使用 2.概要    毕业两年了,一直使用的是qt界面库来开发程序,使用过vs08.10.13等开发工具,并安装了qt的插件,最近在做客户端换肤功能,所以就对qt的qrc做了点儿研究,我是一个实干派(可能有点儿虚),相对于看文档来说.本文开头我就给出了两篇博客,这两篇博客对我理解qrc这个东西有很大的帮助,接下来我就简单分析下我的理解. 首先说明下qrc是qt的东西,而不属于vs,这也很容易证明,那就是vs的工程师不识别qrc文件的,

分享一个换肤解决方案

最近有朋友问到在winform程序上要做换肤功能的话,该如何处理,刚好前一段时间在项目中主导了程序换肤的这个功能.那就借这个机会整理一下,以分享给有需要的朋友. 1. 在winform程序上换肤,需要处理的涉及到每个控件及窗体.熟悉前端的朋友应该知道,在网页上实现换肤主要通过在每个元素上定义指定的标识符(如class,id等特性),然后页面通过加载不同的样式文件去渲染不同的皮肤效果,其实在winform程序中实现的思想应该是一致. 2.如上描述,我们可能需要定制使用到的每个控件,以便能读取指定的

一个很实用的前端框架Zui

杰哥给我推荐了一个很有用的前端框架-Zui,我看着觉得很神奇的,因为有很多我都不懂.在这里分享总结一下.首先,这是一个中国自己开发的框架,比起很多外国的框架来说,有很详细的API,而且是全中文的,不需要再经过其他人的翻译了.然后,它的内容十分丰富,很系统的分为了:基础,控件,组件,JS插件,视图几大块:而且使用起来,只需要导入js,在适当的地方加上正确的class类就可以了.对于,没有什么js基础的人,也是十分容易上手的.下面我就大体的介绍一下它的各个模块的功能.基础:基础里面我觉得很有用的主要

Mybatis_reveiw之Mybatis官方的一个很简单的Demo

上学的时候,一个老师讲了个故事,这个故事的大意是,我们有很多种方式去削苹果,第一种方式,使用指甲刀,第二种方式,使用机床,第三种方式,使用手摇的那种削平果小工具.我们当然都能够完成这个简单的需求,但是使用指甲刀削出来的苹果一定比较坑坑洼洼,不够美观,而且可能会让人感觉到有点没啥食欲.使用机床呢?可能会造成大量的浪费,原本一个美观大方的苹果变成了只能啃几口的正方形.第三个,因为是专门为了削苹果皮而设计的,理论上是最合适用来解决削苹果这个问题的解决方案. 一个好的架构,其实要做的事情是非常简单的,除

WCF技术剖析之三十:一个很有用的WCF调用编程技巧[上篇]

原文:WCF技术剖析之三十:一个很有用的WCF调用编程技巧[上篇] 在进行基于会话信道的WCF服务调用中,由于受到并发信道数量的限制,我们需要及时的关闭信道:当遇到某些异常,我们需要强行中止(Abort)信道,相关的原理,可以参考我的文章<服务代理不能得到及时关闭会有什么后果?>.在真正的企业级开发中,正如我们一般不会让开发人员手工控制数据库连接的开启和关闭一样,我们一般也不会让开发人员手工去创建.开启.中止和关闭信道,这些工作是框架应该完成的操作.这篇文章,我们就来介绍如果通过一些编程技巧,

消格子时一个很深的bug的修复纪录

环境: cocos2d-x 2.2.2  jsb 条件:当快速在格子中来回拖拽选取时,会一直在计算指尖和格子的真实区域是否碰撞, 报错:touchMOve时由于不停的调用BOxItem的getValidRectangle方法, 即不停的在此方法内执行 node.getContentSize().witdh, 经过好几个小时的检测,发现问题就在这一行,xcode里报错的提示显示的是框架里的touchMove相关的代码,看不出具体问题,大概知道了是在touchMOve时F出的问题 修复办法:在Box

一个方便易用的爬虫框架

本文转载至  http://www.tuicool.com/articles/VZBj2e 原文  http://itindex.net/detail/52388-框架 webmagic的是一个无须配置.便于二次开发的爬虫框架,它提供简单灵活的API,只需少量代码即可实现一个爬虫. 官方网站  http://webmagic.io/ webmagic是一个开源的Java垂直爬虫框架,目标是简化爬虫的开发流程,让开发者专注于逻辑功能的开发.webmagic的核心非常简单,但是覆盖爬虫的整个流程,也

一个Mini的ASP.NET Core框架的实现

原文:一个Mini的ASP.NET Core框架的实现 一.ASP.NET Core Mini 在2019年1月的微软技术(苏州)俱乐部成立大会上,蒋金楠老师(大内老A)分享了一个名为“ASP.NET Core框架揭秘”的课程,他用不到200行的代码实现了一个ASP.NET Core Mini框架,重点讲解了7个核心对象,围绕ASP.NET Core最核心的本质—由服务器和若干中间件构成的管道来介绍.我在腾讯视频上看到了这个课程的录像,看了两遍之后结合蒋金楠老师的博客<200行代码,7个对象—让

[ASP.NET Core 3框架揭秘] 依赖注入:一个Mini版的依赖注入框架

在前面的章节中,我们从纯理论的角度对依赖注入进行了深入论述,我们接下来会对.NET Core依赖注入框架进行单独介绍.为了让读者朋友能够更好地理解.NET Core依赖注入框架的设计与实现,我们按照类似的原理创建了一个简易版本的依赖注入框架,也就是我们在前面多次提及的Cat. 源代码下载 普通服务的注册与消费泛型服务的注册与消费多服务实例的提供服务实例的生命周期 一.编程体验 虽然我们对这个名为Cat的依赖注入框架进行了最大限度的简化,但是与.NET Core框架内部使用的真实依赖注入框架相比,