Android之 左右滑动菜单
近来学习了极客学院有关于界面左右滑动的视频,就在这里写个博客,巩固一下知识点,以免忘了。
这里主要介绍界面是如何左右滑动的:
1.首先我们应该设置好将要滑动的三个界面,即leftMenu、middleMenu、rightMenu三个布局,并且放置好它们的位置,这段大家自己在源码中看
2.当位置放好后,就可以开始关于滑动方面的代码。
页面的滑动是通过点的坐标变化距离来进行来实现的。首先我们定义了20dp来确保最小下限滑动的距离,来确定是否进行了滑动;接着就可以进行判断页面的滑动方向,ACTION_DOWN、ACTION_MOVE、ACTION-UP分别对应了手指点击时的按下,移动,抬起时的事件。当按下时,我们获取此时点击点的坐标,随后我们实时获取活动过程中点的滑动坐标,后者减去前者就得到了滑动的距离。当滑动的距离大于TEST_DIS时,如果此时在左右滑动的距离大于在上下滑动距离,就置isLeftRightFragment为true,用于下面的判断。
private Point point = new Point();
private boolean isLeftRightFragment;
//设置比较值20;当移动小于20dp时,默认没有移动
private static final int TEST_DIS = 20;
private void getTypeEvent(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
point.x = (int) ev.getX();
point.y = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
int dX = Math.abs((int)ev.getX() - point.x);
int dY = Math.abs((int)ev.getY() - point.y);
if (dX>TEST_DIS&&dX>dY) { //左右滑动
isLeftRightFragment = true;
isTestCompete = true;
point.x = (int) ev.getX();
point.y = (int) ev.getY();
}else if (dY>TEST_DIS&&dY>dX) { //上下滑动
isLeftRightFragment = false;
isTestCompete = true;
point.x = (int) ev.getX();
point.y = (int) ev.getY();
} break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
default:
break;
}
}
3.这部分一些地方我也不太明白,大家看我写的注释吧,没有的地方我也不太懂(比如回调的方法是干嘛的,Action_move下面的两行代码,知道的给我留言啊)。
public boolean isTestCompete;
public int finalX=0;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!isTestCompete) {
getTypeEvent(ev);
return true;
}
if (isLeftRightFragment) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
int curScrollX = getScrollX(); //获取滑动的距离,向左为负,向右为正
int dis_x = (int) (ev.getX() - point.x);
int expectX = -dis_x + curScrollX;
if (expectX<0) {
//向左滑动
finalX = Math.max(expectX, -leftMenu.getMeasuredWidth());
}else {
//向右滑动
finalX = Math.min(expectX, rightMenu.getMeasuredWidth());
}
//跟随点的滑动,页面滑动
scrollTo(finalX, 0);
point.x= (int) ev.getX();
break; case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
curScrollX = getScrollX();
if (Math.abs(curScrollX) > leftMenu.getMeasuredWidth() >> 1) {
//当滑动的距离大于外布局宽度的一半时
if (curScrollX < 0) {
//向左滑动,前两个参数是开始时坐标,中间是将要移动的距离,200是动画的时间单位毫秒
mScroller.startScroll(curScrollX, 0, -leftMenu.getMeasuredWidth()-curScrollX, 0 ,200);
}else {
//向右滑动
mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth()-curScrollX, 0,200);
}
}else {
//小于宽度的一半,自动返回原位
mScroller.startScroll(curScrollX, 0, -curScrollX, 0,200);
}
invalidate(); //view的重绘
isLeftRightFragment = false;
isTestCompete = false;
break;
}
}else {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_UP:
isLeftRightFragment = false;
isTestCompete = false;
break;
default:
break;
}
}
return super.dispatchTouchEvent(ev);
} //回调的方法
@Override
public void computeScroll() {
super.computeScroll();
if (!mScroller.computeScrollOffset()) {
return;
}
int tempX = mScroller.getCurrX();
scrollTo(tempX, 0);
}
4.三完成后,就可以实现页面滑动了,第四步是在页面滑动时,中间的那个布局会变暗。思路是在定义一个布局middleMask,将它的位置和颜色设置完毕。初始化中设置透明度middleMask.setAlpha(0);
再在重写的ScrollTo方法中设置middleMask的透明度跟随移动渐变。
@Override
public void scrollTo(int x, int y) { super.scrollTo(x, y);
// 设置middlemask的透明度随移动距离渐变
int curX = Math.abs(getScrollX());
//scale的范围为0-1
float scale = curX/ (float)leftMenu.getMeasuredWidth();
middleMask.setAlpha(scale);
}
源码:
MainActivity:
public class MainActivity extends ActionBarActivity { private MenuUI menuUI;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
menuUI=new MenuUI(this);
setContentView(menuUI);
}
}
MenuUI:
public class MenuUI extends RelativeLayout{
private Context context;
private FrameLayout leftMenu;
private FrameLayout middleMenu;
private FrameLayout rightMenu;
private FrameLayout middleMask;
private Scroller mScroller; public MenuUI(Context context) {
super(context);
initView(context); } public MenuUI(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
//初始化
private void initView(Context context){
this.context=context;
mScroller = new Scroller(context, new DecelerateInterpolator()); //第二个参数为渲染器
leftMenu = new FrameLayout(context);
middleMenu = new FrameLayout(context);
rightMenu = new FrameLayout(context);
middleMask = new FrameLayout(context);
leftMenu.setBackgroundColor(Color.YELLOW);
middleMenu.setBackgroundColor(Color.GREEN);
rightMenu.setBackgroundColor(Color.YELLOW);
middleMask.setBackgroundColor(0x88000000);
addView(leftMenu);
addView(middleMenu);
addView(rightMenu);
addView(middleMask);
//设置透明度
middleMask.setAlpha(0);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
middleMenu.measure(widthMeasureSpec, heightMeasureSpec);
middleMask.measure(widthMeasureSpec, heightMeasureSpec);
//得到菜单的宽的大小
int realWidth = MeasureSpec.getSize(widthMeasureSpec);
//令tempRealtempwidth等于菜单0.8倍的宽,用于设置左右菜单的宽度
int tempRealWidth = MeasureSpec.makeMeasureSpec((int)(realWidth*0.8f),
MeasureSpec.EXACTLY);
//设置左右菜单的大小
leftMenu.measure(tempRealWidth, heightMeasureSpec);
rightMenu.measure(tempRealWidth, heightMeasureSpec);
} public float onMiddleMask(){
System.out.println("透明度:"+middleMask.getAlpha());
return middleMask.getAlpha();
} @Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
// 设置middlemask的透明度随移动距离渐变
int curX = Math.abs(getScrollX());
//scale的范围为0-1
float scale = curX/ (float)leftMenu.getMeasuredWidth();
middleMask.setAlpha(scale);
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//设置各个布局菜单的位置
super.onLayout(changed, l, t, r, b);
//将中间界面的位置设置为l,t,r,b
middleMenu.layout(l, t, r, b);
middleMask.layout(l, t, r, b);
//根据middleMenu的位置确定其他菜单的位置
leftMenu.layout(l-leftMenu.getMeasuredWidth(), t, r-middleMenu.getMeasuredWidth(), b);
rightMenu.layout(l+middleMenu.getMeasuredWidth(), t, l+rightMenu.getMeasuredWidth()+middleMenu.getMeasuredWidth(), b);
} public boolean isTestCompete;
public int finalX=0;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!isTestCompete) {
getTypeEvent(ev);
return true;
}
if (isLeftRightFragment) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
int curScrollX = getScrollX(); //获取滑动的距离,向左为负,向右为正
int dis_x = (int) (ev.getX() - point.x);
int expectX = -dis_x + curScrollX;
if (expectX<0) {
finalX = Math.max(expectX, -leftMenu.getMeasuredWidth());
}else {
finalX = Math.min(expectX, rightMenu.getMeasuredWidth());
}
scrollTo(finalX, 0);
point.x= (int) ev.getX();
break; case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
curScrollX = getScrollX();
if (Math.abs(curScrollX) > leftMenu.getMeasuredWidth() >> 1) {
//当滑动的距离大于外布局宽度的一半时
if (curScrollX < 0) {
//向左滑动
mScroller.startScroll(curScrollX, 0, -leftMenu.getMeasuredWidth()-curScrollX, 0 ,200);
}else {
//向右滑动
mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth()-curScrollX, 0,200);
}
}else {
//小于宽度的一半,自动返回原位
mScroller.startScroll(curScrollX, 0, -curScrollX, 0,200);
}
invalidate(); //view的重绘
isLeftRightFragment = false;
isTestCompete = false;
break;
}
}else {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_UP:
isLeftRightFragment = false;
isTestCompete = false;
break;
default:
break;
}
}
return super.dispatchTouchEvent(ev);
} //回调的方法
@Override
public void computeScroll() {
super.computeScroll();
if (!mScroller.computeScrollOffset()) {
return;
}
int tempX = mScroller.getCurrX();
scrollTo(tempX, 0);
}
private Point point = new Point();
private boolean isLeftRightFragment;
private static final int TEST_DIS = 20;
private void getTypeEvent(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
point.x = (int) ev.getX();
point.y = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
int dX = Math.abs((int)ev.getX() - point.x);
int dY = Math.abs((int)ev.getY() - point.y);
if (dX>TEST_DIS&&dX>dY) { //左右滑动
isLeftRightFragment = true;
isTestCompete = true;
point.x = (int) ev.getX();
point.y = (int) ev.getY();
}else if (dY>TEST_DIS&&dY>dX) { //上下滑动
isLeftRightFragment = false;
isTestCompete = true;
point.x = (int) ev.getX();
point.y = (int) ev.getY();
} break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
default:
break;
}
}
}
Android之 左右滑动菜单的更多相关文章
- Android 侧滑(双向滑动菜单)效果
下面看看我们如何使用它,达到我们想要的效果 public class MainActivity extends Activity { /** * 双向滑动菜单布局 */ private SliderM ...
- 超酷的Android 侧滑(双向滑动菜单)效果
下面看看我们如何使用它,达到我们想要的效果 public class MainActivity extends Activity { /** * 双向滑动菜单布局 */ private SliderM ...
- android实现左右滑动菜单
直接看效果图: 主要实现代码: package com.way.view; import android.content.Context; import android.media.Den ...
- Android 3D滑动菜单完全解析,实现推拉门式的立体特效
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/10471245 在上一篇文章中,我们学习了Camera的基本用法,并借助它们编写了一 ...
- Android双向滑动菜单完全解析,教你如何一分钟实现双向滑动特效
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9671609 记得在很早之前,我写了一篇关于Android滑动菜单的文章,其中有一个 ...
- Android 学习笔记之AndBase框架学习(七) SlidingMenu滑动菜单的实现
PS:努力的往前飞..再累也无所谓.. 学习内容: 1.使用SlidingMenu实现滑动菜单.. SlidingMenu滑动菜单..滑动菜单在绝大多数app中也是存在的..非常的实用..Gith ...
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu
示意图就不展示了,和上一节的一样,滑动菜单SlidingMenu效果如何大家都比较熟悉,在这里我简单说明一下用自定义ViewGroup来实现. 实现方法:我们自定义一个ViewGroup实现左右滑动, ...
- Android 滑动菜单SlidingMenu
首先我们看下面视图: 这种效果大家都不陌生,网上好多都说是仿人人网的,估计人家牛逼出来的早吧,我也参考了一一些例子,实现起来有三种方法,我下面简单介绍下: 方法一:其实就是对GestureDetect ...
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu[转]
http://blog.csdn.net/jj120522/article/details/8095852 示意图就不展示了,和上一节的一样,滑动菜单SlidingMenu效果如何大家都比较熟悉,在这 ...
随机推荐
- 编写高质量JS代码的68个有效方法(五)
No.21.使用apply方法通过不同数量的参数调用函数 Tips: 使用apply方法自定一个可计算的参数数组来调用可变参数的函数 使用apply方法的第一个参数给可变参数的方法提供一个接收者 // ...
- 加快MySQL逻辑恢复速度的方法和参数总结
日常工作中经常会有需要从mysqldump导出的备份文件恢复数据库的情况,相比物理备份恢复这种方式在恢复时间上往往显得力不从心. 本文就总结了几个对于逻辑备份恢复有加速作用的参数和操作 注意:我们的大 ...
- Android 学习笔记 Service服务与远程通信...(AIDL)
PS:这一章节看的我有几分迷茫,不是很容易理解...不过还好总算是明白了一大半了...基本的迷惑是解决了... 学习内容: 1.跨应用启动服务... 2.跨应用绑定服务... 3.跨应用实现通信... ...
- 移动端前端常见的触摸相关事件touch、tap、swipe等整理
前端的很多事件在PC端和浏览器端可公用,但有些事件却只在移动端产生,如触摸相关的事件 本文整理了移动端常见的一些事件,包括原生支持的click.touch.tap.swipe事件,也有定义型的gest ...
- 计算html标签textarea字符长度
今天学习jQuery,做练习计算html标签textarea字符长度,先添加一个视图操作(Action): 创建一个视图,并按下面顺序标记1,2,3进行写html或javascript脚本: 其中标记 ...
- Unity3D入门基本概念整理
1. (1)在场景中添加资源 只需单击工程视图 (Project View) 中的网格(Mesh)并拖动至层级视图 (Hierarchy) 或场景视图 (Scene View),便可将其添加至场景 ( ...
- 重新想象 Windows 8 Store Apps (65) - 后台任务: 音乐的后台播放和控制
[源码下载] 重新想象 Windows 8 Store Apps (65) - 后台任务: 音乐的后台播放和控制 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 后台 ...
- 当kfreebsd 用户遇见openSUSE系统
openSuse的系统工具集覆盖了四大主流桌面环境,是针对每一种桌面环境定制的独立的桌面体验.
- Linux修改命令提示符(关于环境参量PS1)
关乎环境参量的四个文件/etc/profile /etc/bashrc ~/.bashrc ~/.bash_profile $$$:/etc/profile:此文件为系统的每个用户设置环境信息,当 ...
- isEmpty与null、""的区别
前一段时间我阅读别人的代码,发现有的时候用isEmpty,有的时候用null,有的时候用"".我很困惑三者之间的区别,于是我就自己写了一个程序来验证一下 public class ...