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

一、效果演示

(说明:目前没有安装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. Android中的缩略图加载-不浪费一点多余的内存

    1. Why,为什么要加载缩略图? 有的时候不需要展示原图,只需展示图片的缩略图,可以节省内存.比如:网易新闻中的图片浏览,左边展示的小狮子图片就是一个缩略图,点击这个图片,才会展示原图.   2. ...

  2. EF5+MVC4系列(8) ActionResult的返回值

    我们在MVC的代码中,经常会看到这样的一个 代码 可能有人会有疑问,既然我定义的是ActionResult,为什么返回值会是View方法呢? 其实这个View方法的返回值的类型是ActionResul ...

  3. 用js实现table内容从下到上连续滚动

    网上有很多用ul实现新闻列表滚动的例子,但是很少有直接用table实现列表内容滚动的例子,而Marquee标签滚动的效果不是很好,于是就自己写了一个,提供给攻城师朋友们参考 实现思路:由于table包 ...

  4. QtCore.QMetaObject.connectSlotsByName:根据objectName和signal自动绑定slot

    from PyQt5.QtWidgets import (QWidget , QVBoxLayout , QHBoxLayout, QLineEdit, QPushButton) from PyQt5 ...

  5. php + crontab 执行定时任务

    1.yii2中的console <?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yi ...

  6. maven2中snapshot快照库和release发布库的应用

    在之前的文章中介绍了maven2中snapshot快照库和release发布库的区别和作用,我今天这里要介绍的是如何在项目中应用snapshot和release库,应用snapshot和release ...

  7. u3d 发布的程序 窗口位置的改变

    using System; using System.Runtime.InteropServices; using UnityEngine; public class WindowMOD : Mono ...

  8. android 自己定义TextView&quot;会发脾气的TextView&quot;

    转载请注明出处王亟亟的大牛路 Git上看到的一个自己定义控件就搞来研究研究.蛮可爱的. 项目结构: 执行效果:非常Q谈.谈的图片什么都 都能够换哦 自己定义View: public class Jel ...

  9. 如何在Sql Server中读取最近一段时间的记录,比如取最近3天的或最近3个月的记录。

    如何在Sql Server中读取最近一段时间的记录,比如取最近3天的或最近3个月的记录. 主要用到DATEADD函数,下面是详细语句 取最近3天 select * from 表名where rq> ...

  10. 基于HBase Hadoop 分布式集群环境下的MapReduce程序开发

    HBase分布式集群环境搭建成功后,连续4.5天实验客户端Map/Reduce程序开发,这方面的代码网上多得是,写个测试代码非常容易,可是真正运行起来可说是历经挫折.下面就是我最终调通并让程序在集群上 ...