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

一、效果演示

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

(向上滑动)

(向下滑动)

(向左滑动)

(向右滑动)

二、实现过程介绍

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

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

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

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

	private float mDownY;
private float mDownX;
@Override
public boolean onTouchEvent(MotionEvent event) {
int disY;
int disX;
float eventY = event.getY();
float eventX = event.getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownY = eventY;
mDownX = eventX;
break;
case MotionEvent.ACTION_UP:
disY = (int)(eventY - mDownY);
disX = (int)(eventX - mDownX);
if(Math.abs(disY) > Math.abs(disX)){
if(Math.abs(disY) > MIN_VIEW_HEIGHT / 2){
if(disY > 0){ //向下滑动
Log.d(TAG, "TO_BOTTOM");
changeToBottom();
}else{ //向上滑动
Log.d(TAG, "TO_TOP");
changeToTop();
}
}
}else{
if(Math.abs(disX) > MIN_VIEW_WIDTH / 2){
if(disX > 0){ //向右滑动
Log.d(TAG, "TO_RIGHT");
changeToRight();
}else{ //向左滑动
Log.d(TAG, "TO_LEFT");
changeToLeft();
}
}
}
break; default:
break;
}
return true;
}

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

	@Override
public void computeScroll() {
super.computeScroll();
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}

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

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

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

三、整个View的源码

package com.example.testmx4update;

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller; /**
* 自定义可以拖动的View
* @author 阳光小强 http://blog.csdn.net/dawanganban
*
*/
public class MyCanPullView extends ViewGroup{ private static final int MIN_VIEW_HEIGHT = 200;
private static final int MIN_VIEW_WIDTH = 400; private static final String TAG = "TEST"; private int mViewHeight;
private int mViewWidth; private View mTopView;
private View mBottomView;
private View mCenterView;
private View mLeftView;
private View mRightView; private Scroller mScroller; public MyCanPullView(Context context, AttributeSet attrs) {
super(context, attrs); initView(context); mScroller = new Scroller(context);
} private void initView(Context context) {
setTopView(context);
setBottomView(context);
setCenterView(context);
setLeftView(context);
setRightView(context);
} private float mDownY;
private float mDownX;
@Override
public boolean onTouchEvent(MotionEvent event) {
int disY;
int disX;
float eventY = event.getY();
float eventX = event.getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownY = eventY;
mDownX = eventX;
break;
case MotionEvent.ACTION_UP:
disY = (int)(eventY - mDownY);
disX = (int)(eventX - mDownX);
if(Math.abs(disY) > Math.abs(disX)){
if(Math.abs(disY) > MIN_VIEW_HEIGHT / 2){
if(disY > 0){ //向下滑动
Log.d(TAG, "TO_BOTTOM");
changeToBottom();
}else{ //向上滑动
Log.d(TAG, "TO_TOP");
changeToTop();
}
}
}else{
if(Math.abs(disX) > MIN_VIEW_WIDTH / 2){
if(disX > 0){ //向右滑动
Log.d(TAG, "TO_RIGHT");
changeToRight();
}else{ //向左滑动
Log.d(TAG, "TO_LEFT");
changeToLeft();
}
}
}
break; default:
break;
}
return true;
} private void changeToBottom(){
int[] location = new int[2];
mCenterView.getLocationOnScreen(location);
if(location[1] >= mViewHeight - MIN_VIEW_HEIGHT * 2) return;
int dy = (int)(mViewHeight - MIN_VIEW_HEIGHT);
mScroller.startScroll(0, getScrollY(), 0, -dy, 500);
invalidate();
} private void changeToTop(){
int[] location = new int[2];
mTopView.getLocationOnScreen(location);
if(location[1] <= -mViewHeight - MIN_VIEW_HEIGHT / 2) return;
int dy = (int)(mViewHeight - MIN_VIEW_HEIGHT);
mScroller.startScroll(0, getScrollY(), 0, dy, 500);
invalidate();
} private void changeToRight(){
int[] location = new int[2];
mCenterView.getLocationOnScreen(location);
if(location[0] >= mViewWidth - MIN_VIEW_WIDTH * 2) return;
int dx = (int)(mViewWidth - MIN_VIEW_WIDTH);
mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);
invalidate();
} private void changeToLeft(){
Log.d(TAG, "TO_LEFT");
int[] location = new int[2];
mLeftView.getLocationOnScreen(location);
if(location[0] <= -mViewWidth - MIN_VIEW_WIDTH / 2) return;
int dx = (int)(mViewWidth - MIN_VIEW_WIDTH);
mScroller.startScroll(getScrollX(), 0, dx, 0, 500);
invalidate();
} @Override
public void computeScroll() {
super.computeScroll();
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mTopView.layout(0, -mViewHeight, mViewWidth, 0);
mBottomView.layout(0, mViewHeight, mViewWidth, 2 * mViewHeight);
mCenterView.layout(0, 0, mViewWidth, mViewHeight);
mLeftView.layout(-mViewWidth, 0, 0, mViewHeight);
mRightView.layout(mViewWidth, 0, 2 * mViewWidth, mViewHeight);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取整个View的宽高
mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
mViewHeight = MeasureSpec.getSize(heightMeasureSpec);
} private void setTopView(Context context){
View topButton = new View(context);
topButton.setBackgroundColor(Color.RED);
mTopView = topButton;
this.addView(mTopView);
} private void setBottomView(Context context){
View bottomButton = new View(context);
bottomButton.setBackgroundColor(Color.GREEN);
mBottomView = bottomButton;
this.addView(mBottomView);
} private void setCenterView(Context context){
View centerButton = new View(context);
centerButton.setBackgroundColor(Color.WHITE);
mCenterView = centerButton;
this.addView(mCenterView);
} private void setLeftView(Context context){
View leftButton = new View(context);
leftButton.setBackgroundColor(Color.BLUE);
mLeftView = leftButton;
this.addView(mLeftView);
} private void setRightView(Context context){
View rightButton = new View(context);
rightButton.setBackgroundColor(Color.YELLOW);
mRightView = rightButton;
this.addView(mRightView);
}
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  7. Android自定义组件系列【17】——教你如何高仿微信录音Toast

    一.Toast介绍 平时我们在Android开发中会经常用到一个叫Toast的东西,官方解释如下 A toast is a view containing a quick little message ...

  8. Android自定义组件系列【13】——Android自定义对话框如此简单

    在我们的日常项目中很多地方会用到对话框,但是Android系统为我们提供的对话框样子和我们精心设计的界面很不协调,在这种情况下我们想很自由的定义对话框,或者有的时候我们的对话框是一个图片,没有标题和按 ...

  9. Android自定义组件系列【12】——非UI线程绘图SurfaceView

    一.SurfaceView的介绍 在前面我们已经会自定义View,使用canvas绘图,但是View的绘图机制存在一些缺陷. 1.View缺乏双缓冲机制. 2.程序必须重绘整个View上显示的图片,比 ...

随机推荐

  1. 脚本2,从1到99 ,添加用户user1,user2,。。。 user99

    脚本2,从1到99 ,添加用户user1,user2,... user99 如果用户user$存在,脚本显示用户存在,否则添加用户,并显示添加用户成功. 脚本如下 [root@localhost ho ...

  2. C++ Primer笔记13_运算符重载_总结

    总结: 1.不能重载的运算符: . 和 .* 和 ?: 和 ::  和 sizeof 和 typeid 2.重载运算符有两种基本选择: 类的成员函数或者友元函数, 建议规则例如以下: 运算符 建议使用 ...

  3. oracle新手随记10

    1. unpivot注意点:select new_col from (select ename,job,to_char(sal) as sal,null as c from emp)         ...

  4. [NOIP2015模拟10.27] [JZOJ4270] 魔道研究 解题报告(动态开点+权值线段树上二分)

    Description “我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力.”——<The Grimoire of Marisa>雾雨魔理 ...

  5. MySQL的登录和退出(五)

    如何使用MySQL? 如何实现MySQL的登录/退出 如何修改MySQL的提示符 如何实现MySQL的常用命令 如何规范MySQL语句 如何操作数据库 1.MYSQL常用参数及功能 mysql -V ...

  6. Hadoop框架基础(二)

    ** Hadoop框架基础(二) 上一节我们讨论了如何对hadoop进行基础配置已经运行一个简单的实例,接下来我们尝试使用eclipse开发. ** maven安装 简单介绍:maven是一个项目管理 ...

  7. jquery-validator中js校验及标签校验的使用

    jquery-validator中js校验及标签校验的使用: 1.项目中引入jquery.validate.js  官方网站:http://bassistance.de/  http://jquery ...

  8. Linux 下段错误 core文件

    什么是core dump? core的意思是内存,dump的意思是扔出来,堆出来:当一个程序奔溃时,在进程当前工作目录的core文件中复制了该进程的存储图像.core文件仅仅是一个内存映像(同时加上调 ...

  9. asp.net导出execl和图片

    个人常用导出execl方法: #region "导出文档" /// <summary> /// Export("application/ms-excel&qu ...

  10. UI Framework-1: Aura Multi-desktop

    Multi-desktop Aura now makes it possible for the same browser process to render to multiple desktops ...