Android自定义组件系列【15】——四个方向滑动的菜单实现
今天无意中实现了一个四个方向滑动的菜单,感觉挺好玩,滑动起来很顺手,既然已经做出来了就贴出来让大家也玩弄一下。
一、效果演示
(说明:目前没有安装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】——四个方向滑动的菜单实现的更多相关文章
- Android自定义组件——四个方向滑动的菜单实现
今天无意中实现了一个四个方向滑动的菜单,感觉挺好玩,滑动起来很顺手,既然已经做出来了就贴出来让大家也玩弄一下. 一.效果演示 (说明:目前没有安装Android模拟器,制作的动态图片太卡了,就贴一下静 ...
- Android自定义组件系列【7】——进阶实践(4)
上一篇<Android自定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识,这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpan ...
- Android自定义组件系列【6】——进阶实践(3)
上一篇<Android自定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计划 ...
- Android自定义组件系列【5】——进阶实践(2)
上一篇<Android自定义组件系列[5]--进阶实践(1)>中对任老师的<可下拉的PinnedHeaderExpandableListView的实现>前一部分进行了实现,这一 ...
- Android自定义组件系列【4】——自定义ViewGroup实现双侧滑动
在上一篇文章<Android自定义组件系列[3]--自定义ViewGroup实现侧滑>中实现了仿Facebook和人人网的侧滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布局示 ...
- Android自定义组件系列【3】——自定义ViewGroup实现侧滑
有关自定义ViewGroup的文章已经很多了,我为什么写这篇文章,对于初学者或者对自定义组件比较生疏的朋友虽然可以拿来主义的用了,但是要一步一步的实现和了解其中的过程和原理才能真真脱离别人的代码,举一 ...
- Android自定义组件系列【17】——教你如何高仿微信录音Toast
一.Toast介绍 平时我们在Android开发中会经常用到一个叫Toast的东西,官方解释如下 A toast is a view containing a quick little message ...
- Android自定义组件系列【13】——Android自定义对话框如此简单
在我们的日常项目中很多地方会用到对话框,但是Android系统为我们提供的对话框样子和我们精心设计的界面很不协调,在这种情况下我们想很自由的定义对话框,或者有的时候我们的对话框是一个图片,没有标题和按 ...
- Android自定义组件系列【12】——非UI线程绘图SurfaceView
一.SurfaceView的介绍 在前面我们已经会自定义View,使用canvas绘图,但是View的绘图机制存在一些缺陷. 1.View缺乏双缓冲机制. 2.程序必须重绘整个View上显示的图片,比 ...
随机推荐
- Zabbix分布式配置
Zabbix是一个分布式监控系统,它可以以一个中心点.多个分节点的模式运行,使用Proxy能大大的降低Zabbix Server的压力,Zabbix Proxy可以运行在独立的服务器上,安装Zabbi ...
- 紫书 例题 11-6 UVa 658 (状态压缩+隐式图搜索+最短路)
这道题用到了很多知识点, 是一道好题目. 第一用了状态压缩, 因为这里最多只有20位, 所以可以用二进制来储存状态 (要对数据范围敏感), 然后 涉及到了一些位运算. 第二这里是隐式 ...
- HDU 4965 Fast Matrix Calculation(矩阵高速幂)
HDU 4965 Fast Matrix Calculation 题目链接 矩阵相乘为AxBxAxB...乘nn次.能够变成Ax(BxAxBxA...)xB,中间乘n n - 1次,这样中间的矩阵一个 ...
- BAPC2014 K&&HUNNU11591:Key to Knowledge(中途相遇法)
题意: 有N个学生.有M题目 然后相应N行分别有一个二进制和一个整数 二进制代表该同学给出的每道题的答案.整数代表该同学的答案与标准答案相符的个数 要求推断标准答案有几个,假设标准答案仅仅有一种.则输 ...
- jsp出现错误can not find the tag directory /web-inf/tags
百度google了一大圈没找到中文答案,无奈之下硬着头皮看了一个英文答案http://stackoverflow.com/questions/11502703/eclipse-can-not-find ...
- LBP(Local Binary Patterns)局部二进制模式
1. LBP 用于人脸识别 为了预测每个像素属于哪个脸部器官(眼睛.鼻子.嘴.头发),通常的作法是在该像素周围取一个小的区域,提取纹理特征(例如局部二值模式),再基于该特征利用支持向量机等浅层模型分类 ...
- CSS中关于vertical-align垂直对齐
一向以来,我对vertical-align的属性都搞的不是太清楚,今天刚好碰到有朋友问我相关的问题,于是自己潜心研究了一番,发现这玩意还真不是个简单的东西,在此我分享的东西都是抛弃脑残的IE的,如果你 ...
- Windows 绝赞应用(该网站收集了日常好用的工具和软件)
在我们的电脑使用过程中,或多或少的被流氓软件恶心过.流氓软件之所以这么流氓全是靠他那恐怖的用户数量,基本上形成垄断后,各种流氓行为就一点点体现出来了. 我们也可以选择不用,但对流氓软件来说多你一个不多 ...
- P3157 [CQOI2011]动态逆序对 CDQ分治
一道CDQ分治模板题简单来说,这道题是三维数点对于离线的二维数点,我们再熟悉不过:利用坐标的单调递增性,先按更坐标排序,再按纵坐标排序更新和查询时都直接调用纵坐标.实际上,我们是通过排序将二维中的一维 ...
- include、require、include_once和require_once的区别
/*** * 1.include 和 require 的文件可以有返回值 * 2.include 包含的文件不存在,会发出一个警告,但是不会停止执行代码. * require 在这种情况下会抛出错误并 ...