qq侧滑
上一篇博客带大家实现了:Android
自定义控件打造史上最简单的侧滑菜单 ,有兄弟看了以后说,你这滑动菜单过时了呀~QQ5.0的效果还不错~~嗯,的确,上一篇也承诺过,稍微修改上一篇的代码,实现QQ5.0侧滑菜单~~好了,下面就开始为大家展示写一个类QQ的侧滑有多easy ~!
1、原理分析
首先对比一下我们上篇的实现距离QQ的效果还有多远:

差距还是蛮大的
区别1、QQ的内容区域会伴随菜单的出现而缩小
区别2、QQ的侧滑菜单给人的感觉是隐藏在内容的后面,而不是拖出来的感觉
区别3、QQ的侧滑菜单有一个缩放以及透明度的效果~
那么我们如何能做到呢:
对于区别1:这个好办,我们可以在滑动的时候,不断的改变内容区域的大小;如何改变呢?我们在菜单出现的整个过程中,不断记录菜单显示的宽度与其总宽度的比值,是个从0到1的过程,然后把0~1转化为1~0.7(假设内容区域缩小至0.7);不断去缩小内容区域;
对于区别3:也比较好办,上面已经可以得到0到1的这个值了,那么缩放和透明度的动画就不在话下了;
对于区别2:我们使用的HorizontalScrollView,然后水平放置了菜单和内容,如何让菜单可以隐藏到内容的后面呢?其实也比较简单,在菜单出现的过程中,不断设置菜单的x方向的偏移量;0的时候完全隐藏,0.3的时候,隐藏x方向偏移量为0.7个宽度,类推~~~
好了,分析完毕,那么对于这些动画用什么实现最好呢?
想都不用想,属性动画哈,如果你对属性动画不了解,可以参:Android
属性动画(Property Animation) 完全解析 (上)和Android
属性动画(Property Animation) 完全解析 (下)
2、实现
1、初步的代码
布局文件神马的,都和上一篇一模一样,这里就不重复贴代码了,不了解的,先看下上一篇;
先看一下上一篇我们已经实现的完整代码:
- package com.example.zhy_slidingmenu;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.util.AttributeSet;
- import android.util.TypedValue;
- import android.view.MotionEvent;
- import android.view.ViewGroup;
- import android.widget.HorizontalScrollView;
- import android.widget.LinearLayout;
- import com.zhy.utils.ScreenUtils;
- public class SlidingMenu extends HorizontalScrollView
- {
- /**
- * 屏幕宽度
- */
- private int mScreenWidth;
- /**
- * dp
- */
- private int mMenuRightPadding;
- /**
- * 菜单的宽度
- */
- private int mMenuWidth;
- private int mHalfMenuWidth;
- private boolean isOpen;
- private boolean once;
- public SlidingMenu(Context context, AttributeSet attrs)
- {
- this(context, attrs, 0);
- }
- public SlidingMenu(Context context, AttributeSet attrs, int defStyle)
- {
- super(context, attrs, defStyle);
- mScreenWidth = ScreenUtils.getScreenWidth(context);
- TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
- R.styleable.SlidingMenu, defStyle, 0);
- int n = a.getIndexCount();
- for (int i = 0; i < n; i++)
- {
- int attr = a.getIndex(i);
- switch (attr)
- {
- case R.styleable.SlidingMenu_rightPadding:
- // 默认50
- mMenuRightPadding = a.getDimensionPixelSize(attr,
- (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, 50f,
- getResources().getDisplayMetrics()));// 默认为10DP
- break;
- }
- }
- a.recycle();
- }
- public SlidingMenu(Context context)
- {
- this(context, null, 0);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
- {
- /**
- * 显示的设置一个宽度
- */
- if (!once)
- {
- LinearLayout wrapper = (LinearLayout) getChildAt(0);
- ViewGroup menu = (ViewGroup) wrapper.getChildAt(0);
- ViewGroup content = (ViewGroup) wrapper.getChildAt(1);
- mMenuWidth = mScreenWidth - mMenuRightPadding;
- mHalfMenuWidth = mMenuWidth / 2;
- menu.getLayoutParams().width = mMenuWidth;
- content.getLayoutParams().width = mScreenWidth;
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b)
- {
- super.onLayout(changed, l, t, r, b);
- if (changed)
- {
- // 将菜单隐藏
- this.scrollTo(mMenuWidth, 0);
- once = true;
- }
- }
- @Override
- public boolean onTouchEvent(MotionEvent ev)
- {
- int action = ev.getAction();
- switch (action)
- {
- // Up时,进行判断,如果显示区域大于菜单宽度一半则完全显示,否则隐藏
- case MotionEvent.ACTION_UP:
- int scrollX = getScrollX();
- if (scrollX > mHalfMenuWidth)
- {
- this.smoothScrollTo(mMenuWidth, 0);
- isOpen = false;
- } else
- {
- this.smoothScrollTo(0, 0);
- isOpen = true;
- }
- return true;
- }
- return super.onTouchEvent(ev);
- }
- /**
- * 打开菜单
- */
- public void openMenu()
- {
- if (isOpen)
- return;
- this.smoothScrollTo(0, 0);
- isOpen = true;
- }
- /**
- * 关闭菜单
- */
- public void closeMenu()
- {
- if (isOpen)
- {
- this.smoothScrollTo(mMenuWidth, 0);
- isOpen = false;
- }
- }
- /**
- * 切换菜单状态
- */
- public void toggle()
- {
- if (isOpen)
- {
- closeMenu();
- } else
- {
- openMenu();
- }
- }
- }
利用HorizontalScrollView,监听了ACTION_UP的事件,当用户抬起手指时,根据当前菜单显示的宽度值,判断是缩回还是完全展开;给用户提供了一个rightPadding属性,用于设置菜单离右屏幕的距离;以及对外提供了打开,关闭,切换的几个方法;具体的讲解看下上篇博客了;
2、实现的思路
现在我们开始解决那3个区别,已经选择了使用属性动画,现在决定动画效果应该加在哪儿?
不用说,我用大腿想一想都应该是在ACTION_MOVE中,是的,ACTION_MOVE中的确可以,不断获取当前的getScrollX / mMenuWidth,不断改变菜单的透明度,缩放,X方向的偏移量;不断改变内容区域的宽度和高度;
说一下,起初我也是在MOVE中这么做的,但是呢,出现两个问题:
1、动画效果并不是很流畅,特别是菜单,有抖动的效果;
2、用户抬起后,还需要在UP里面,继续未完成的动画,就是说,你的透明度、缩放神马的,当用户抬起以后就需要自动变化了;
于是乎,我就开始换了个方向,既然是SrollView,肯定有一个ScrollChanged方法,功夫不负有心人,真心这么个方法:
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt)
- {
- }
这个方法只要scrollChanged就会触发,l就是我们需要的scrollX,太赞了~~~
3、动画比例的计算
我们在onScrollChanged里面,拿到 l 也就是个getScrollX,即菜单已经显示的宽度值;
- float scale = l * 1.0f / mMenuWidth;
与菜单的宽度做除法运算,在菜单隐藏到显示整个过程,会得到1.0~0.0这么个变化的区间;
有了这个区间,就可以根据这个区间设置动画了;
1、首先是内容区域的缩放比例计算:
我们准备让在菜单出现的过程中,让内容区域从1.0~0.8进行变化~~
那么怎么把1.0~0.0转化为1.0~0.8呢,其实很简单了:
float rightScale = 0.8f + scale * 0.2f; (scale 从1到0 ),是不是哦了~
接下来还有3个动画:
2、菜单的缩放比例计算
仔细观察了下QQ,菜单大概缩放变化是0.7~1.0
float leftScale = 1 - 0.3f * scale;
3、菜单的透明度比例:
我们设置为0.6~1.0;即:0.6f + 0.4f * (1 - scale)
4、菜单的x方向偏移量:
看一下QQ,并非完全从被内容区域覆盖,还是有一点拖出的感觉,所以我们的偏移量这么设置:
tranlateX = mMenuWidth * scale * 0.6f ;刚开始还是让它隐藏一点点~~~
4、完整的实现
说了这么多,其实到上一篇史上最简单的侧滑,到QQ5.0的效果的转变,只需要几行代码~~
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt)
- {
- super.onScrollChanged(l, t, oldl, oldt);
- float scale = l * 1.0f / mMenuWidth;
- float leftScale = 1 - 0.3f * scale;
- float rightScale = 0.8f + scale * 0.2f;
- ViewHelper.setScaleX(mMenu, leftScale);
- ViewHelper.setScaleY(mMenu, leftScale);
- ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));
- ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.6f);
- ViewHelper.setPivotX(mContent, 0);
- ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
- ViewHelper.setScaleX(mContent, rightScale);
- ViewHelper.setScaleY(mContent, rightScale);
- }
就这么几行。这里属性动画用的nineoldandroids为了保持向下的兼容;主要就是设置了各种动画,上面都详细说了~~~
然后,记得把我们的菜单和内容的布局,单独声明出来为我们的mMenu ,mContent ~没了,就改了这么几行~
3、效果图
是骡子是马,拉出来溜溜
菜单栏需要ListView的拖动也是不会冲突了,上篇已经测试了;
关于动画属性的范围:上面介绍的特别清楚,比如内容我们是最小显示0.8,你要是喜欢0.6,自己去修改一下;包括偏移量,透明度等范围;
因为上一篇已经写了如何把属性抽取成自定义的属性;所以这里就没有抽取了,不然总觉得是在重复~
嗯,最近还有写APP的侧滑,是这样的,就是菜单栏完全隐藏在内容区域下面,如果需要这样需求的:
其实我还满喜欢这样效果的。
实现呢,注释几行代码就实现了:
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt)
- {
- super.onScrollChanged(l, t, oldl, oldt);
- float scale = l * 1.0f / mMenuWidth;
- // float leftScale = 1 - 0.3f * scale;
- // float rightScale = 0.8f + scale * 0.2f;
- //
- // ViewHelper.setScaleX(mMenu, leftScale);
- // ViewHelper.setScaleY(mMenu, leftScale);
- // ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));
- ViewHelper.setTranslationX(mMenu, mMenuWidth * scale );
- // ViewHelper.setPivotX(mContent, 0);
- // ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
- // ViewHelper.setScaleX(mContent, rightScale);
- // ViewHelper.setScaleY(mContent, rightScale);
- }
好了,虽说最终的实现看起来还是很简单的,看起来,嗯~~但是从无到有的这个过程还是不容易的~~各种尝试,我能说我连蹲坑都在滑QQ的菜单观察么~哈,见笑了;博客中也写出了过程中失败的尝试,希望能够更好的让大家在里面学到些有用的东西~~YEAH!! 就到这,没事就留个言~~~再不留言,我就来个源码请留下邮箱,嘿嘿,开个玩笑~
最后,我建了一个QQ群,方便大家交流。群号:55032675
---------------------------------------------------------------------------------------------------------------------------------------
本博客内容视频版,已经上线,如果你不喜欢枯燥的文本,请猛戳:
qq侧滑的更多相关文章
- Swift实战-小QQ(第2章):QQ侧滑菜单
QQ侧滑实现架构:需要建立以下几个ViewController:1.XQBaseViewController 2.LeftViewController3.RightViewController4.Co ...
- (转载)实现QQ侧滑边栏
Android ViewDragHelper实现QQ侧滑边栏 移动手机版的QQ的左边侧栏,有一个特殊的交互设计效果:当用户手指向右或向左滑动时,QQ的左边会弹出或收缩一个侧滑的边栏.这种效果简单的做法 ...
- Android开源框架之SwipeListView导入及模拟QQ侧滑
SwipeListView是Github上的一个开源框架,地址:https://github.com/47deg/android-swipelistview SwipeListView was bor ...
- 再造 “手机QQ” 侧滑菜单(三)——视图联动
代码示例:https://github.com/johnlui/SwiftSideslipLikeQQ 本 文中,我们将一起使用 UINavigationController 来管理主视图,并实现点击 ...
- 自定义控件?试试300行代码实现QQ侧滑菜单
Android自定义控件并没有什么捷径可走,需要不断得模仿练习才能出师.这其中进行模仿练习的demo的选择是至关重要的,最优选择莫过于官方的控件了,但是官方控件动辄就是几千行代码往往可能容易让人望而却 ...
- android开发学习 ------- 仿QQ侧滑效果的实现
需要做一个仿QQ侧滑删除的一个效果: 一开始是毫无头绪,百度找思路,找到 https://blog.csdn.net/xiaxiazaizai01/article/details/53036994 ...
- iOS仿QQ侧滑菜单、登录按钮动画、仿斗鱼直播APP、城市选择器、自动布局等源码
iOS精选源码 QQ侧滑菜单,右滑菜单,QQ展开菜单,QQ好友分组 登录按钮 3分钟快捷创建高性能轮播图 ScrollView嵌套ScrolloView(UITableView .UICollecti ...
- 仿QQ侧滑菜单<大自然的搬运工-代码不是我的>
1.记录下效果图 2.二个工具类 package myapplication.com.myapplicationfortest.utils; import android.util.Log; /** ...
- 再造 “手机QQ” 侧滑菜单(一)——实现侧滑效果
本系列文章中,我们将尝试再造手机QQ的侧滑菜单,力争最大限度接近手Q的实际效果,并使用 Auto Layout 仿造左侧菜单,实现和主视图的联动. 代码示例:https://github.com/jo ...
随机推荐
- bzoj1272 Gate Of Babylon
[问题描述] [输入格式] [输出格式] [样例输入] 2 1 10 13 3 [样例输出] 12 [样例说明] [数据范围] 先容斥,考虑枚举哪些条件强制不满足,即直接选出b[i]+1件宝具 假设强 ...
- [HNOI2001]矩阵乘积
题目描述 输入输出格式 输入格式: 第1行为:x y (第1行为两个正整数:x,y分别表示输出结果所在的行和列) 第2行为:m n o p(第2行给出的正整数表明A为m×n矩阵,B为n×o矩阵,C为o ...
- VK-Cup2017 Wild Card Round 2
来自FallDream的博客,未经允许,请勿转载,谢谢. Cf的Vkcup外卡赛2 上次round2和ditoly翻车了 所以只好来打打了 规则是给一道比较特殊的题目,你要找出较优的解 Unive ...
- 阿里Java研发工程师实习面经
十分幸运 拿到阿里云的offer,感谢周围无数人对我的支持和鼓励,所以写篇面经希望可以帮助大家. 面试中,运气占很大一部分的,所以你们若是没有通过,一定不要气馁,继续加油. 每个努力的人 都值得钦佩, ...
- JS中怎样判断undefined(比较不错的方法)
最近做项目碰到的问题.拿出来跟大家分享一下吧. 用servlet赋值给html页面文本框值后,用alert来弹出这个值.结果显示"undefined".所以我就自然的用这个值和字符 ...
- hibernate实体对象的三种状态:自由状态,持久状态,游离状态.
自由态与游离态的区别: 当一个持久化对象,脱离开Hibernate的缓存管理后,它就处于游离状态,游离对象和自由对象的最大区别在于,游离对象在数据库中可能还存在一条与它 对应的记录,只是现在这个游离对 ...
- 剑指架构师系列-MySQL的安装及主从同步
1.安装数据库 wget http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm rpm -ivh mysql-commun ...
- git 学习笔记(常用命令)
1.新建一个文件,如果没有使用git add 命令将它提交到暂存区,那么这个文件就还没有被跟踪. 2.通过配置.gitignore文件可以指定要忽略的文件,被忽略的文件夹是不会被提交到暂存区的.所以这 ...
- 通讯协议序列化解读(二) protostuff详解教程
上一篇文章 通讯协议序列化解读(一):http://www.cnblogs.com/tohxyblog/p/8974641.html 前言:上一面文章我们介绍了java序列化,以及谷歌protobu ...
- Docker配置文件
Docker 的 Registry 利用配置文件提供了一些仓库的模板(flavor),用户可以直接使用它们来进行开发或生产部署. 模板 在 config_sample.yml 文件中,可以看到一些现成 ...