Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭

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、初步的代码

布局文件神马的,都和上一篇一模一样,这里就不重复贴代码了,不了解的,先看下上一篇;

先看一下上一篇我们已经实现的完整代码:

[java] view plaincopy

  1. package com.example.zhy_slidingmenu;
  2. import android.content.Context;
  3. import android.content.res.TypedArray;
  4. import android.util.AttributeSet;
  5. import android.util.TypedValue;
  6. import android.view.MotionEvent;
  7. import android.view.ViewGroup;
  8. import android.widget.HorizontalScrollView;
  9. import android.widget.LinearLayout;
  10. import com.zhy.utils.ScreenUtils;
  11. public class SlidingMenu extends HorizontalScrollView
  12. {
  13. /**
  14. * 屏幕宽度
  15. */
  16. private int mScreenWidth;
  17. /**
  18. * dp
  19. */
  20. private int mMenuRightPadding;
  21. /**
  22. * 菜单的宽度
  23. */
  24. private int mMenuWidth;
  25. private int mHalfMenuWidth;
  26. private boolean isOpen;
  27. private boolean once;
  28. public SlidingMenu(Context context, AttributeSet attrs)
  29. {
  30. this(context, attrs, 0);
  31. }
  32. public SlidingMenu(Context context, AttributeSet attrs, int defStyle)
  33. {
  34. super(context, attrs, defStyle);
  35. mScreenWidth = ScreenUtils.getScreenWidth(context);
  36. TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
  37. R.styleable.SlidingMenu, defStyle, 0);
  38. int n = a.getIndexCount();
  39. for (int i = 0; i < n; i++)
  40. {
  41. int attr = a.getIndex(i);
  42. switch (attr)
  43. {
  44. case R.styleable.SlidingMenu_rightPadding:
  45. // 默认50
  46. mMenuRightPadding = a.getDimensionPixelSize(attr,
  47. (int) TypedValue.applyDimension(
  48. TypedValue.COMPLEX_UNIT_DIP, 50f,
  49. getResources().getDisplayMetrics()));// 默认为10DP
  50. break;
  51. }
  52. }
  53. a.recycle();
  54. }
  55. public SlidingMenu(Context context)
  56. {
  57. this(context, null, 0);
  58. }
  59. @Override
  60. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  61. {
  62. /**
  63. * 显示的设置一个宽度
  64. */
  65. if (!once)
  66. {
  67. LinearLayout wrapper = (LinearLayout) getChildAt(0);
  68. ViewGroup menu = (ViewGroup) wrapper.getChildAt(0);
  69. ViewGroup content = (ViewGroup) wrapper.getChildAt(1);
  70. mMenuWidth = mScreenWidth - mMenuRightPadding;
  71. mHalfMenuWidth = mMenuWidth / 2;
  72. menu.getLayoutParams().width = mMenuWidth;
  73. content.getLayoutParams().width = mScreenWidth;
  74. }
  75. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  76. }
  77. @Override
  78. protected void onLayout(boolean changed, int l, int t, int r, int b)
  79. {
  80. super.onLayout(changed, l, t, r, b);
  81. if (changed)
  82. {
  83. // 将菜单隐藏
  84. this.scrollTo(mMenuWidth, 0);
  85. once = true;
  86. }
  87. }
  88. @Override
  89. public boolean onTouchEvent(MotionEvent ev)
  90. {
  91. int action = ev.getAction();
  92. switch (action)
  93. {
  94. // Up时,进行判断,如果显示区域大于菜单宽度一半则完全显示,否则隐藏
  95. case MotionEvent.ACTION_UP:
  96. int scrollX = getScrollX();
  97. if (scrollX > mHalfMenuWidth)
  98. {
  99. this.smoothScrollTo(mMenuWidth, 0);
  100. isOpen = false;
  101. } else
  102. {
  103. this.smoothScrollTo(0, 0);
  104. isOpen = true;
  105. }
  106. return true;
  107. }
  108. return super.onTouchEvent(ev);
  109. }
  110. /**
  111. * 打开菜单
  112. */
  113. public void openMenu()
  114. {
  115. if (isOpen)
  116. return;
  117. this.smoothScrollTo(0, 0);
  118. isOpen = true;
  119. }
  120. /**
  121. * 关闭菜单
  122. */
  123. public void closeMenu()
  124. {
  125. if (isOpen)
  126. {
  127. this.smoothScrollTo(mMenuWidth, 0);
  128. isOpen = false;
  129. }
  130. }
  131. /**
  132. * 切换菜单状态
  133. */
  134. public void toggle()
  135. {
  136. if (isOpen)
  137. {
  138. closeMenu();
  139. } else
  140. {
  141. openMenu();
  142. }
  143. }
  144. }


用HorizontalScrollView,监听了ACTION_UP的事件,当用户抬起手指时,根据当前菜单显示的宽度值,判断是缩回还是完全展开;
给用户提供了一个rightPadding属性,用于设置菜单离右屏幕的距离;以及对外提供了打开,关闭,切换的几个方法;具体的讲解看下上篇博客了;

2、实现的思路

现在我们开始解决那3个区别,已经选择了使用属性动画,现在决定动画效果应该加在哪儿?

不用说,我用大腿想一想都应该是在ACTION_MOVE中,是的,ACTION_MOVE中的确可以,不断获取当前的getScrollX / mMenuWidth,不断改变菜单的透明度,缩放,X方向的偏移量;不断改变内容区域的宽度和高度;

说一下,起初我也是在MOVE中这么做的,但是呢,出现两个问题:

1、动画效果并不是很流畅,特别是菜单,有抖动的效果;

2、用户抬起后,还需要在UP里面,继续未完成的动画,就是说,你的透明度、缩放神马的,当用户抬起以后就需要自动变化了;

于是乎,我就开始换了个方向,既然是SrollView,肯定有一个ScrollChanged方法,功夫不负有心人,真心这么个方法:

[java] view plaincopy

  1. @Override
  2. protected void onScrollChanged(int l, int t, int oldl, int oldt)
  3. {
  4. }

这个方法只要scrollChanged就会触发,l就是我们需要的scrollX,太赞了~~~

3、动画比例的计算

我们在onScrollChanged里面,拿到 l 也就是个getScrollX,即菜单已经显示的宽度值;

[html] view plaincopy

  1. 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的效果的转变,只需要几行代码~~

[java] view plaincopy

  1. @Override
  2. protected void onScrollChanged(int l, int t, int oldl, int oldt)
  3. {
  4. super.onScrollChanged(l, t, oldl, oldt);
  5. float scale = l * 1.0f / mMenuWidth;
  6. float leftScale = 1 - 0.3f * scale;
  7. float rightScale = 0.8f + scale * 0.2f;
  8. ViewHelper.setScaleX(mMenu, leftScale);
  9. ViewHelper.setScaleY(mMenu, leftScale);
  10. ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));
  11. ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.6f);
  12. ViewHelper.setPivotX(mContent, 0);
  13. ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
  14. ViewHelper.setScaleX(mContent, rightScale);
  15. ViewHelper.setScaleY(mContent, rightScale);
  16. }

就这么几行。这里属性动画用的nineoldandroids为了保持向下的兼容;主要就是设置了各种动画,上面都详细说了~~~
然后,记得把我们的菜单和内容的布局,单独声明出来为我们的mMenu ,mContent ~没了,就改了这么几行~

3、效果图

是骡子是马,拉出来溜溜

菜单栏需要ListView的拖动也是不会冲突了,上篇已经测试了;

关于动画属性的范围:上面介绍的特别清楚,比如内容我们是最小显示0.8,你要是喜欢0.6,自己去修改一下;包括偏移量,透明度等范围;

因为上一篇已经写了如何把属性抽取成自定义的属性;所以这里就没有抽取了,不然总觉得是在重复~

嗯,最近还有写APP的侧滑,是这样的,就是菜单栏完全隐藏在内容区域下面,如果需要这样需求的:

其实我还满喜欢这样效果的。

实现呢,注释几行代码就实现了:

[java] view plaincopy

  1. @Override
  2. protected void onScrollChanged(int l, int t, int oldl, int oldt)
  3. {
  4. super.onScrollChanged(l, t, oldl, oldt);
  5. float scale = l * 1.0f / mMenuWidth;
  6. //      float leftScale = 1 - 0.3f * scale;
  7. //      float rightScale = 0.8f + scale * 0.2f;
  8. //
  9. //      ViewHelper.setScaleX(mMenu, leftScale);
  10. //      ViewHelper.setScaleY(mMenu, leftScale);
  11. //      ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));
  12. ViewHelper.setTranslationX(mMenu, mMenuWidth * scale );
  13. //      ViewHelper.setPivotX(mContent, 0);
  14. //      ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
  15. //      ViewHelper.setScaleX(mContent, rightScale);
  16. //      ViewHelper.setScaleY(mContent, rightScale);
时间: 2024-10-01 06:26:34

Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭的相关文章

Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭【学习鸿洋_视频博客笔记总结】

学习鸿洋博客:http://blog.csdn.net/lmj623565791/article/details/39257409 学习鸿洋视频:慕课网视频 看看Android 高仿 QQ5.0 侧滑菜单效果 自定义控件实现效果: 技术上,继承HorizontalScrollView 加上自定义ViewGroup来实现: 1.onMeasure:决定内部View(子View)的宽和高,以及自己的宽和高 2.onLayout:决定子View的放置位置 3.onTouchEvent[监听动作] 自定

仿QQ5.0侧滑菜单效果

慕课网视频 今天我们来继承 HorizontalScrollView 实现比较炫酷的侧滑菜单效果 继承HorizontalScrollView的好处有两点: 1.不用在写 MOVE 事件 2.不用解决 和 ListView 的冲突 以下是实现步骤: 自定义 ViewGroup,实现它的几个方法 1.onMeasure       决定内部 View (子 View) 的宽和高,以及呢,自己的宽和高 /** * 设置 自己的宽和高 子 View 的宽和高 * * @param widthMeasu

彷QQ5.0侧滑菜单(自定义控件--SlideMenu的实现)

一般的侧滑的实现 ViewGroup  Menu + Content onTouchEvent MOVE:ViewGroup的leftMargin UP:根据显示菜单的高度,决定将其隐藏或者显示 1.Scroller 2.LeftMargin + Thread 彷QQ5.0侧滑菜单的实现,使用另外的一种方法,继承HorizontalScrollView 一.自定义ViewGroup 1.构造方法的选择,获得一些需要用到的值 2.onMeasure 计算子View的宽和高,以及设置自己的宽和高 3

【案例分享】仿QQ5.0侧滑菜单ResideMenu

本文由孙国威 原创.如需转载,请注明出处! 为了后续对这个项目进行优化,比如透明度动画.背景图的位移动画,以及性能上的优化. 我把这个项目上传到github上面,请大家随时关注. github地址https://github.com/sunguowei 最近项目要做一个QQ5.0的侧滑菜单效果,和传统的侧滑菜单存在着一些差异.想必大家都已经见识过了. 为了不重复发明轮子,先去github上面搜索了一番. 发现了几个类似的,但是还是有一些不同. 下面是搜索到的类似的开源项目. RESideMenu

【转】仿QQ5.0侧滑菜单ResideMenu

本文由孙国威 原创.如需转载,请注明出处! 原文:http://blog.csdn.net/manoel/article/details/39013095 为了后续对这个项目进行优化,比如透明度动画.背景图的位移动画,以及性能上的优化. 我把这个项目上传到github上面,请大家随时关注. github地址https://github.com/sunguowei 最近项目要做一个QQ5.0的侧滑菜单效果,和传统的侧滑菜单存在着一些差异.想必大家都已经见识过了. 为了不重复发明轮子,先去githu

【Android 案例分享】仿QQ5.0侧滑菜单ResideMenu

Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,Base64编码可用于在HTTP环境下传递较长的标识信息.在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式.此时,采用Base64编码具有不可读性, 即所编码的数据不会被人用肉眼所直接看到.金融数据也常以base64编码格式提供....版本已升级至1.0.1源码地址:GitHub:https://github.com/way1989/WayHooOsChina:http://git.osch

AndroidDrawerLayout高仿QQ52双向侧滑菜单(转载)

AndroidDrawerLayout高仿QQ52双向侧滑菜单 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41531475,本文出自:[张鸿洋的博客] 1.概述 之前写了一个Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 ,恰逢QQ5.2又加了一个右侧菜单,刚好看了下DrawerLayout,一方面官方的东西,我都比较感兴趣:另一方面,这玩意用起来的确方便,于是简单写了个demo,高仿QQ5.2双向侧滑,分

Android QQ5.0侧滑菜单

背景 相信大家用过QQ的人,都会知道QQ有这样的一个功能,那就是他的菜单,感觉就像抽屉一样被拉出来的感觉,感觉很拉风啊,酷酷的,如果你有一种想要把它给弄清楚,想明白,这是一个好东西,你要把它变成自己的,那么现在就是你的机会,也在此恭喜你,你终于初步具有一个向中级工程师迈进的门票了,因为你已经跨出第一步了. 一:效果图,走一走,天下我有 二:实现步骤 1.菜单和内容布局的实现 2.自定义viewgroup 3.给注册监听事件,添加动画效果 三:示例源码 ①菜单布局 <?xml version=&quo

QQ5.0侧滑菜单

QQ5.0侧滑菜单 功能分类:社交    支持平台:Android    运行环境:Eclipse 开发语言:Java    开发工具:Eclipse     源码大小:1.06MB 源码简介 和 QQ 侧滑菜单类似效果,包括缩放.透明度变化.位置变化. 下载地址:http://www.dwz.cn/wYBof 源码运行截图