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

一、效果演示

(说明:目前没有安装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. php -- 取整数

    PHP取整数函数常用的四种方法,下面收集了四个函数: 经常用到取整的函数,今天小小的总结一下!其实很简单,就是几个函数而已--主要是:ceil,floor,round,intval ceil — 进一 ...

  2. spark 源码阅读博客

    http://blog.csdn.net/oopsoom/article/details/38257749

  3. php 获取某文件内容

    获取某文件下 的文件夹和文件 public function dirRead($dir=''){ //$dir = './upload/images'; $result = ''; if (is_di ...

  4. [转]jmeter 自定义测试脚本

    http://blog.csdn.net/kash_chen007/article/details/37690411 http://wangym.iteye.com/blog/731729 1.创建一 ...

  5. Java编程思想学习笔记——初始化与清理

    初始化 构造器保证初始化 构造器采用与类相同的名称. 默认构造器(default constructor):不接受任何参数的构造器,也叫无参构造器. 构造器也能带有形式参数,就能在初始化对象时提供实际 ...

  6. Window 10 :我的性能优化:那效果,杠杠的!

    微软的 windows 10,不错! 当全新安装后,性能总觉得别别扭扭,不那么干净利落. 下面就是我的个人优化措施,期间有很多技术性的操作,如果你没有动手能力,或者是技术小白,可以不用再看了! (1) ...

  7. Android : Your APK does not seem to be designed for tablets.

    1. 解决办法: Add these config in AndroidManifest.xml <supports-screens android:smallScreens="tru ...

  8. notepad++ 文本替换功能,解决excel批量修改数据库的数据操作

    ^ \(' 开始\t ',' 制表符$ '\) 行末 复制出来之后,使用文本替换功能,转换为SQL,添加到临时表中.然后多表关联修改. SELECT COUNT(*) FROM orderno; # ...

  9. Spring学习总结五——SpringIOC容器五

    一:spring组件扫描 可以使用注解的方式,代替在xml配置文件配置bean,可以减少配置文件的书写,只需要在spring容器配置 文件中配置<context:component-scan b ...

  10. Python 常用类库

    python除了关键字(keywords)和内置的类型和函数(builtins),更多的功能是通过libraries(即modules)来提供的. 常用的libraries(modules)如下: 1 ...