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

一、效果演示

(说明:目前没有安装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. Linux 程序包管理-RPM

    程序简介:  POSIX(Portable Openratin System)跨平台系统:不同操作系统平台的标准C库(glibc)都是遵循POSIX规范的,这样基于标准库开发程序的源代码可以夸平台编译 ...

  2. Union File System

    目录 Union File System AUFS Docker是如何使用AUFS的 image layer 和 AUFS (docker版本不同可能会有区别,我的是在/var/lib/docker下 ...

  3. hdu 4771 求一点遍历全部给定点的最短路(bfs+dfs)

    题目如题.题解如题. 因为目标点最多仅仅有4个,先bfs出俩俩最短路(包含起点).再dfs最短路.)0s1A;(当年弱跪杭州之题,现看如此简单) #include<iostream> #i ...

  4. 面试题:Student s = new Student();在内存中做了哪些事情?即创建一个对象做了哪些事情

    lStudent s = new Student();在内存中做了哪些事情? •载入Student.class文件进内存(方法区) •在栈内存为s开辟空间 •在堆内存为学生对象开辟空间 •对学生对象的 ...

  5. Domino 使用递归算法获取视图值

    在关系数据库中,有两字段是父子关系.通过递归算法,输入一个父ID,能够获取全部相应的子ID.这种数据结构在组织架构中常常使用.显示一般使用树形结构.在Domino中相同能够处理这种情况,下面是个小de ...

  6. hdu_1698线段树成段更新

    #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #d ...

  7. Fast Flux技术——本质就是跳板,控制多个机器,同一域名指向极多的IP(TTL修改为0),以逃避追踪

    转自:http://ytuwlg.iteye.com/blog/355718 通过病毒邮件和欺诈网站学到的对付网络封锁的好东西:Fast Flux技术 收到一封邮件,引起我的好奇了: 邮件标题是:Ha ...

  8. Xfce4里添加登录后程序自动运行

    Xfce4里添加登录后程序自动运行 (注意该方法在登录桌面环境后才会自动运行程序. 在XUbuntu下测试过, Ubuntu下应该是类似的) 方法1: 找到这个东西, 自动添加一下 方法2: 在 .c ...

  9. 4.bind绑定

    #include <iostream> #include <string> #include <boost/bind.hpp> #include <boost ...

  10. 8.queue

    #include <iostream> #include <stack> #include <algorithm> #include <list> #i ...