今天无意中实现了一个四个方向滑动的菜单,感觉挺好玩,滑动起来很顺手,既然已经做出来了就贴出来让大家也玩弄一下。

一、效果演示

(说明:目前没有安装Android模拟器,制作的动态图片太卡了,就贴一下静态图片吧,实际效果可以下载源代码查看)

(向上滑动)

(向下滑动)

(向左滑动)

(向右滑动)

二、实现过程介绍

1、放置5个View (分别是上下左右中)

  1. @Override
  2. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  3. mTopView.layout(0, -mViewHeight, mViewWidth, 0);
  4. mBottomView.layout(0, mViewHeight, mViewWidth, 2 * mViewHeight);
  5. mCenterView.layout(0, 0, mViewWidth, mViewHeight);
  6. mLeftView.layout(-mViewWidth, 0, 0, mViewHeight);
  7. mRightView.layout(mViewWidth, 0, 2 * mViewWidth, mViewHeight);
  8. }

转载请说明出处:http://blog.csdn.net/dawanganban

2、通过onTouchEvent事件来判断移动方向

  1. private float mDownY;
  2. private float mDownX;
  3. @Override
  4. public boolean onTouchEvent(MotionEvent event) {
  5. int disY;
  6. int disX;
  7. float eventY = event.getY();
  8. float eventX = event.getX();
  9. switch (event.getAction()) {
  10. case MotionEvent.ACTION_DOWN:
  11. mDownY = eventY;
  12. mDownX = eventX;
  13. break;
  14. case MotionEvent.ACTION_UP:
  15. disY = (int)(eventY - mDownY);
  16. disX = (int)(eventX - mDownX);
  17. if(Math.abs(disY) > Math.abs(disX)){
  18. if(Math.abs(disY) > MIN_VIEW_HEIGHT / 2){
  19. if(disY > 0){ //向下滑动
  20. Log.d(TAG, "TO_BOTTOM");
  21. changeToBottom();
  22. }else{        //向上滑动
  23. Log.d(TAG, "TO_TOP");
  24. changeToTop();
  25. }
  26. }
  27. }else{
  28. if(Math.abs(disX) > MIN_VIEW_WIDTH / 2){
  29. if(disX > 0){ //向右滑动
  30. Log.d(TAG, "TO_RIGHT");
  31. changeToRight();
  32. }else{        //向左滑动
  33. Log.d(TAG, "TO_LEFT");
  34. changeToLeft();
  35. }
  36. }
  37. }
  38. break;
  39. default:
  40. break;
  41. }
  42. return true;
  43. }

3、通过computerScroll()方法实现平滑移动

  1. @Override
  2. public void computeScroll() {
  3. super.computeScroll();
  4. if(mScroller.computeScrollOffset()){
  5. scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
  6. postInvalidate();
  7. }
  8. }

4、判断临界条件(否则会一直向一个方向滑动)

  1. int[] location = new int[2];
  2. mCenterView.getLocationOnScreen(location);
  3. if(location[1] >= mViewHeight - MIN_VIEW_HEIGHT * 2) return;

例如上面代码就是判断向下滑动的临界条件,location[1]代表中间View的y坐标(相对于屏幕)。

三、整个View的源码

  1. package com.example.testmx4update;
  2. import android.content.Context;
  3. import android.graphics.Color;
  4. import android.util.AttributeSet;
  5. import android.util.Log;
  6. import android.view.MotionEvent;
  7. import android.view.View;
  8. import android.view.ViewGroup;
  9. import android.widget.Scroller;
  10. /**
  11. * 自定义可以拖动的View
  12. * @author 阳光小强  http://blog.csdn.net/dawanganban
  13. *
  14. */
  15. public class MyCanPullView extends ViewGroup{
  16. private static final int MIN_VIEW_HEIGHT = 200;
  17. private static final int MIN_VIEW_WIDTH = 400;
  18. private static final String TAG = "TEST";
  19. private int mViewHeight;
  20. private int mViewWidth;
  21. private View mTopView;
  22. private View mBottomView;
  23. private View mCenterView;
  24. private View mLeftView;
  25. private View mRightView;
  26. private Scroller mScroller;
  27. public MyCanPullView(Context context, AttributeSet attrs) {
  28. super(context, attrs);
  29. initView(context);
  30. mScroller = new Scroller(context);
  31. }
  32. private void initView(Context context) {
  33. setTopView(context);
  34. setBottomView(context);
  35. setCenterView(context);
  36. setLeftView(context);
  37. setRightView(context);
  38. }
  39. private float mDownY;
  40. private float mDownX;
  41. @Override
  42. public boolean onTouchEvent(MotionEvent event) {
  43. int disY;
  44. int disX;
  45. float eventY = event.getY();
  46. float eventX = event.getX();
  47. switch (event.getAction()) {
  48. case MotionEvent.ACTION_DOWN:
  49. mDownY = eventY;
  50. mDownX = eventX;
  51. break;
  52. case MotionEvent.ACTION_UP:
  53. disY = (int)(eventY - mDownY);
  54. disX = (int)(eventX - mDownX);
  55. if(Math.abs(disY) > Math.abs(disX)){
  56. if(Math.abs(disY) > MIN_VIEW_HEIGHT / 2){
  57. if(disY > 0){ //向下滑动
  58. Log.d(TAG, "TO_BOTTOM");
  59. changeToBottom();
  60. }else{        //向上滑动
  61. Log.d(TAG, "TO_TOP");
  62. changeToTop();
  63. }
  64. }
  65. }else{
  66. if(Math.abs(disX) > MIN_VIEW_WIDTH / 2){
  67. if(disX > 0){ //向右滑动
  68. Log.d(TAG, "TO_RIGHT");
  69. changeToRight();
  70. }else{        //向左滑动
  71. Log.d(TAG, "TO_LEFT");
  72. changeToLeft();
  73. }
  74. }
  75. }
  76. break;
  77. default:
  78. break;
  79. }
  80. return true;
  81. }
  82. private void changeToBottom(){
  83. int[] location = new int[2];
  84. mCenterView.getLocationOnScreen(location);
  85. if(location[1] >= mViewHeight - MIN_VIEW_HEIGHT * 2) return;
  86. int dy = (int)(mViewHeight - MIN_VIEW_HEIGHT);
  87. mScroller.startScroll(0, getScrollY(), 0, -dy, 500);
  88. invalidate();
  89. }
  90. private void changeToTop(){
  91. int[] location = new int[2];
  92. mTopView.getLocationOnScreen(location);
  93. if(location[1] <= -mViewHeight - MIN_VIEW_HEIGHT / 2) return;
  94. int dy = (int)(mViewHeight - MIN_VIEW_HEIGHT);
  95. mScroller.startScroll(0, getScrollY(), 0, dy, 500);
  96. invalidate();
  97. }
  98. private void changeToRight(){
  99. int[] location = new int[2];
  100. mCenterView.getLocationOnScreen(location);
  101. if(location[0] >= mViewWidth - MIN_VIEW_WIDTH * 2) return;
  102. int dx = (int)(mViewWidth - MIN_VIEW_WIDTH);
  103. mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);
  104. invalidate();
  105. }
  106. private void changeToLeft(){
  107. Log.d(TAG, "TO_LEFT");
  108. int[] location = new int[2];
  109. mLeftView.getLocationOnScreen(location);
  110. if(location[0] <= -mViewWidth - MIN_VIEW_WIDTH / 2) return;
  111. int dx = (int)(mViewWidth - MIN_VIEW_WIDTH);
  112. mScroller.startScroll(getScrollX(), 0, dx, 0, 500);
  113. invalidate();
  114. }
  115. @Override
  116. public void computeScroll() {
  117. super.computeScroll();
  118. if(mScroller.computeScrollOffset()){
  119. scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
  120. postInvalidate();
  121. }
  122. }
  123. @Override
  124. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  125. mTopView.layout(0, -mViewHeight, mViewWidth, 0);
  126. mBottomView.layout(0, mViewHeight, mViewWidth, 2 * mViewHeight);
  127. mCenterView.layout(0, 0, mViewWidth, mViewHeight);
  128. mLeftView.layout(-mViewWidth, 0, 0, mViewHeight);
  129. mRightView.layout(mViewWidth, 0, 2 * mViewWidth, mViewHeight);
  130. }
  131. @Override
  132. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  133. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  134. //获取整个View的宽高
  135. mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
  136. mViewHeight = MeasureSpec.getSize(heightMeasureSpec);
  137. }
  138. private void setTopView(Context context){
  139. View topButton = new View(context);
  140. topButton.setBackgroundColor(Color.RED);
  141. mTopView = topButton;
  142. this.addView(mTopView);
  143. }
  144. private void setBottomView(Context context){
  145. View bottomButton = new View(context);
  146. bottomButton.setBackgroundColor(Color.GREEN);
  147. mBottomView = bottomButton;
  148. this.addView(mBottomView);
  149. }
  150. private void setCenterView(Context context){
  151. View centerButton = new View(context);
  152. centerButton.setBackgroundColor(Color.WHITE);
  153. mCenterView = centerButton;
  154. this.addView(mCenterView);
  155. }
  156. private void setLeftView(Context context){
  157. View leftButton = new View(context);
  158. leftButton.setBackgroundColor(Color.BLUE);
  159. mLeftView = leftButton;
  160. this.addView(mLeftView);
  161. }
  162. private void setRightView(Context context){
  163. View rightButton = new View(context);
  164. rightButton.setBackgroundColor(Color.YELLOW);
  165. mRightView = rightButton;
  166. this.addView(mRightView);
  167. }
  168. }

获取全部源代码,请加群在群共享中获取(142979499)

Android自定义组件——四个方向滑动的菜单实现的更多相关文章

  1. Android自定义组件系列【15】——四个方向滑动的菜单实现

    今天无意中实现了一个四个方向滑动的菜单,感觉挺好玩,滑动起来很顺手,既然已经做出来了就贴出来让大家也玩弄一下. 一.效果演示 (说明:目前没有安装Android模拟器,制作的动态图片太卡了,就贴一下静 ...

  2. Android自定义组件系列【4】——自定义ViewGroup实现双侧滑动

    在上一篇文章<Android自定义组件系列[3]--自定义ViewGroup实现侧滑>中实现了仿Facebook和人人网的侧滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布局示 ...

  3. Android自定义组件系列【7】——进阶实践(4)

    上一篇<Android自定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识,这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpan ...

  4. Android自定义视图四:定制onMeasure强制显示为方形

    这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三: ...

  5. Android自定义组件之自动换行及宽度自适应View:WordWrapView

    目的: 自定义一个ViewGroup,里面的子view都是TextView,每个子view  TextView的宽度随内容自适应且每行的子View的个数自适应,并可以自动换行 一:效果图 二:代码 整 ...

  6. Android自定义组件系列【5】——进阶实践(2)

    上一篇<Android自定义组件系列[5]--进阶实践(1)>中对任老师的<可下拉的PinnedHeaderExpandableListView的实现>前一部分进行了实现,这一 ...

  7. Android自定义组件系列【6】——进阶实践(3)

    上一篇<Android自定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计划 ...

  8. Android自定义组件系列【3】——自定义ViewGroup实现侧滑

    有关自定义ViewGroup的文章已经很多了,我为什么写这篇文章,对于初学者或者对自定义组件比较生疏的朋友虽然可以拿来主义的用了,但是要一步一步的实现和了解其中的过程和原理才能真真脱离别人的代码,举一 ...

  9. Android 自定义组件之如何实现自定义组件

    参考链接:http://blog.csdn.net/jjwwmlp456/article/details/41076699 简介 Android提供了用于构建UI的强大的组件模型.两个基类:View和 ...

随机推荐

  1. Java 訪问权限控制:你真的了解 protected keyword吗?

    摘要: 在一个类的内部,其成员(包含成员变量和成员方法)是否能被其它类所訪问,取决于该成员的修饰词:而一个类是否能被其它类所訪问,取决于该类的修饰词.Java的类成员訪问权限修饰词有四类:privat ...

  2. ViewBag和ViewDate以及TempDate的区别

    简单的说,就是   ViewBag 和  ViewData 是数据共享的(他们都是共享 ViewData 的数据),ViewBag 实际就是对 ViewData的一个操作的封装.  区别 : View ...

  3. php中的func_num_args、func_get_arg与func_get_args函数

    From: http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/09/21/2183157.html php的的func_num_args.f ...

  4. List&Map&Set的操作和遍历

    Java的三大集合即:Set.List.Map. Set:代表无序.不可重复的集合,常用的有HashSet(哈希表实现).TreeSet(红黑树实现): List:代表有序.可以重复的集合,比较常用的 ...

  5. Git介绍及安装配置

    一.概述 1.1git概念 Git是一个开源的分布式版本控制系统,用于敏捷高效处理任意规模的项目,其作者为Linux创造者Linus Torvalds为管理Linux内核而开放的一个开源的版本控制柔软 ...

  6. 简单理解IoC与DI

    为了理解Spring的IoC与DI从网上查了很多资料,作为初学者,下面的描述应该是最详细,最易理解的方式了. 首先想说说IoC(Inversion of Control,控制倒转).这是spring的 ...

  7. 安装yeoman报没有权限的错误

    新的ubuntu服务器, 不小心先装了npm, 再装的node, 再用meanjs装的yeoman(即不是自己npm install -g yo装的, 是用meanjs的stack一步到位的),而正常 ...

  8. linux shell搜索某个字符串,然后在后面加上字符串?字符串后面插入字符串?sed字符串后面插入字符串?

    需求描述: 今天在配置nrpe.cfg这个文件,里面有allowed_hosts的IP地址,需要加上监控主机的地址,所以首先要搜索 到这个地址,然后呢,加上监控主机的地址,考虑通过sed命令来实现 操 ...

  9. mysql数据库中,如何对json数据类型的值进行修改?通过json_set函数对json字段值进行修改?

    需求描述: 今天在看mysql中存放json数据类型的问题,对于json数据进行修改的操作, 在此记录下. 操作过程: 1.创建包含json数据类型的表,插入基础数据 mysql> create ...

  10. 第五种方式,python使用组合来添加类方法和属性(二),以selenium的webdriver为例

    组合优点多,但经常比继承需要额外的代码. 上一篇是 介绍装饰器.继承.元类.mixin,四种給类动态添加类属性和方法的四种方式. 此篇介绍直接把被组合的类的属性直接加入到类里面,前面的四个例子很简单, ...