Android 记录3 Android滑动菜单特效实现
来源:互联网 发布:xnview mac 破解 编辑:程序博客网 时间:2024/06/05 05:14
Android滑动菜单特效实现
首先谢谢大牛的开源精神,参考:http://blog.csdn.net/guolin_blog/article/details/8714621。
废话少说,开始记录今天的学习情况。
今天主要学习滑动菜单,在主页面手指向右边滑动,就可以将菜单显示出来,而主界面会被隐藏大部分,但是仍有左侧的一小部分同菜单一起展示。
在贴代码之前,先去了解以下知识点:
1. MotionEvent 的getX()和getRawX()的区别在哪里?
getX()是表示Widget相对于自身左上角的x坐标,而getRawX()是表示相对于屏幕左上角的x坐标值(注意:这个屏幕左上角是手机屏幕左上角,不管activity是否有titleBar或是否全屏幕),getY(),getRawY()一样的道理
开始整个功能的实现过程:
1. 实现原理:在一个Activity的布局中需要有两部分,一个是菜单(menu)的布局,一个是内容(content)的布局。两个布局横向排列,菜单布局在左,内容布局在右。初始化的时候将菜单布局向左偏移,以至于能够完全隐藏,这样内容布局就会完全显示在Activity中。然后通过监听手指滑动事件,来改变菜单布局的左偏移距离,从而控制菜单布局的显示和隐藏。
2. 新建一个Android项目,修改layout文件 activity_main.xml,改为如下代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" tools:context=".MainActivity" > <LinearLayout android:id="@+id/menu" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" android:background="@drawable/menu"> </LinearLayout> <LinearLayout android:id="@+id/content" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" android:background="@drawable/content"> </LinearLayout></LinearLayout>
这个布局文件的最外层布局是一个LinearLayout,排列方向是水平方向排列。这个LinearLayout下面嵌套了两个子LinearLayout,分别就是菜单的布局和内容的布局。这里为了要让布局尽量简单,菜单布局和内容布局里面没有加入任何控件,只是给这两个布局各添加了一张背景图片。
3. 在Activity 的加入如下代码:
package com.wty.demo.slidemenudemo;import android.os.AsyncTask;import android.os.Bundle;import android.app.Activity;import android.content.Context;import android.util.DisplayMetrics;import android.view.Menu;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.View.OnTouchListener;import android.view.WindowManager;import android.widget.LinearLayout;public class MainActivity extends Activity implements OnTouchListener{/* *屏幕宽度值 */private int screenWidth;/* * 主内容的布局 */private View content;/* * menu布局 */private View menu;private View main;/* * menu的布局参数,通过此参数来更改leftMargin的值 */private LinearLayout.LayoutParams menuParams; /* * menu完全显示时,menu右边边缘距离屏幕右边边缘的距离 */private int menuPadding = 100;/* * menu最多可以滑到的左边缘。由menu布局的宽度来定。 marginleft到达此值之后,不能再减少, 为负数 */private int leftEdge;/* * menu最多可以滑到的右边缘。值恒定为0,当marginleft到达0之后不能增加 */private int rightEdge = 0;/* * 手指按下时的横坐标 */private float xDown;/* * 手指移动时的横坐标 */private float xMove;/* * 手指抬起时的横坐标 */private float xUp;/* * 滚动显示和隐藏menu时,手指滑动需要达到的速度 */public static final int SNAP_VELOCITY = 200;/* * 用于计算手指滑动速度 */private VelocityTracker mVelocityTracker; /* * menu当前是显示还是隐藏 */ private boolean isMenuVisible; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initValues();content.setOnTouchListener(this);//main.setOnTouchListener(this);//这样设置当显示menu的时候也可以在menu表面滑动}/* * 初始化一些关键数据,包括获取屏幕的宽度 * 给content布局重新设置宽度,给menu布局重新设置宽度以及偏移度等 * */private void initValues() {// TODO Auto-generated method stubWindowManager window = (WindowManager)getSystemService(Context.WINDOW_SERVICE);DisplayMetrics dm = new DisplayMetrics();window.getDefaultDisplay().getMetrics(dm);screenWidth = dm.widthPixels;main= findViewById(R.id.main_layout);content = findViewById(R.id.content);menu = findViewById(R.id.menu);menuParams = (LinearLayout.LayoutParams)menu.getLayoutParams();//将menu的宽度设置为屏幕宽度减去menupanddingmenuParams.width=screenWidth-menuPadding;// 左边缘的值赋值为menu宽度的负数leftEdge = -menuParams.width;// menu的leftmargin设置为左边缘的值,这样menu初始化就不可见menuParams.leftMargin = leftEdge;// content 宽度设置为屏幕宽度content.getLayoutParams().width = screenWidth;}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onTouch(View v, MotionEvent event) {if(/*v.getId()==R.id.content*/true){createVelocityTracker(event);switch (event.getAction()){case MotionEvent.ACTION_DOWN://手指按下时,记录按下的横坐标xDown = event.getRawX();break;case MotionEvent.ACTION_MOVE://手指移动时,对比按下时的横坐标,计算出移动的距离,//来调整menu的leftMargin值,从而显示或者隐藏menuxMove = event.getRawX();//移动的距离,从左到右为正,从右到左为负int distanceX=(int)(xMove-xDown);if(isMenuVisible){ //当menu是显示时,menu左边缘的距离就是rightEdge+distanceXmenuParams.leftMargin = rightEdge+distanceX;} else {//当menu隐藏的时候,左边缘的距离就是leftEdge+distanceXmenuParams.leftMargin = leftEdge+distanceX;}//对menu的左边缘距离进行有效性判断if(menuParams.leftMargin<leftEdge){ //menu左边缘已经滑动到最左边,不能再左了menuParams.leftMargin = leftEdge;} else if(menuParams.leftMargin>rightEdge){ //menu已经整个完全显示,menu不能再右menuParams.leftMargin=rightEdge;}menu.setLayoutParams(menuParams);break;case MotionEvent.ACTION_UP://手指抬起时,判断当前手势的意图,从而决定是滚动到menu界面还是滚动到content界面xUp = event.getRawX();if(wantToShowMenu()){if(shouldScrollToMenu()){scrollToMenu();}else{scrollToContent();}} else if(wantToShowContent()){if(shouldScrollToContent()){scrollToContent();}else{scrollToMenu();}}break;}}else if(v.getId()==R.id.menu){}// TODO Auto-generated method stubreturn true;}/* * 将屏幕滚动到content界面,滚动速度设定为-30 */private void scrollToContent() {// TODO Auto-generated method stubnew ScrollTask().execute(-30);}/* * 将屏幕滚动到menu界面,滚动速度设定为30. */private void scrollToMenu() {// TODO Auto-generated method stubnew ScrollTask().execute(30);}class ScrollTask extends AsyncTask<Integer, Integer, Integer> { @Override protected Integer doInBackground(Integer... speed) { int leftMargin = menuParams.leftMargin; // 根据传入的速度来滚动界面,当滚动到达左边界或右边界时,跳出循环。 while (true) { leftMargin = leftMargin + speed[0]; if (leftMargin > rightEdge) { leftMargin = rightEdge; break; } if (leftMargin < leftEdge) { leftMargin = leftEdge; break; } publishProgress(leftMargin); // 为了要有滚动效果产生,每次循环使线程睡眠20毫秒,这样肉眼才能够看到滚动动画。 sleep(20); } if (speed[0] > 0) { isMenuVisible = true; } else { isMenuVisible = false; } return leftMargin; } @Override protected void onProgressUpdate(Integer... leftMargin) { menuParams.leftMargin = leftMargin[0]; menu.setLayoutParams(menuParams); } @Override protected void onPostExecute(Integer leftMargin) { menuParams.leftMargin = leftMargin; menu.setLayoutParams(menuParams); } } /** * 使当前线程睡眠指定的毫秒数。 * * @param millis * 指定当前线程睡眠多久,以毫秒为单位 */ private void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } }/* * 判断是否应该滚动将menu显示出来。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于定义的SNAP_VELOCITY * 就认为应该滚动将menu展示出来 * * @return 如果应该滚动将menu显示出来就返回true,否则返回false */private boolean shouldScrollToMenu() {// TODO Auto-generated method stubreturn xUp-xDown>screenWidth/2 || getScrollVelocity()>SNAP_VELOCITY;}/* * 判断是否应该滚动将content显示出来。如果手指移动距离加上menuPadding大于屏幕的1/2,或者手指移动速度大于定义的SNAP_VELOCITY * 就认为应该滚动将content展示出来 * * @return 如果应该滚动将content显示出来就返回true,否则返回false */private boolean shouldScrollToContent() {// TODO Auto-generated method stubreturn xDown-xUp+menuPadding>screenWidth/2 || getScrollVelocity()>SNAP_VELOCITY;}/* * 判断当前手势的意图是不是想显示menu.如果手指移动的距离是正数(从左到右滑),并且当前menu是不可见的, * 则认为当前手势是想要显示menu * * @return 当前手势想显示menu返回true,否则返回false */private boolean wantToShowMenu(){return xUp - xDown >0 && !isMenuVisible;}/* * 判断当前手势的意图是不是想显示content.如果手指移动的距离是负数(从右到左滑),并且当前menu是可见的, * 则认为当前手势是想要显示content * * @return 当前手势想显示content返回true,否则返回false */private boolean wantToShowContent(){return xUp-xDown <0 && isMenuVisible;}/* * 创建VelocityTracker对象,并将触摸content界面的滑动事件加入到VelocityTracker当中 * * @param event * content界面的滑动事件 */private void createVelocityTracker(MotionEvent event) {// TODO Auto-generated method stubif(mVelocityTracker == null ){ mVelocityTracker = VelocityTracker.obtain();}mVelocityTracker.addMovement(event);}/* * 获得手指在content界面滑动的速度 * @return 滑动速度,以每秒钟移动多少个像素值为单位 */private int getScrollVelocity(){if(mVelocityTracker != null){//设置单位mVelocityTracker.computeCurrentVelocity(1000);int velocity = (int) mVelocityTracker.getXVelocity();return Math.abs(velocity);}return 0;}/* * 回收VelocityTracker对象 */private void recycleVelocityTracker(){if(mVelocityTracker != null){mVelocityTracker.recycle();mVelocityTracker = null;}}}
解释一下代码流程:
初始化的时候调用initValues方法,在这里面将内容布局的宽度设定为屏幕的宽度,菜单布局的宽度设定为屏幕的宽度减去menuPadding值,这样可以保证在菜单布局展示的时候,仍有一部分内容布局可以看到。如果不在初始化的时候重定义两个布局宽度,就会按照layout文件里面声明的一样,两个布局都是fill_parent,这样就无法实现滑动菜单的效果了。然后将菜单布局的左偏移量设置为负的菜单布局的宽度,这样菜单布局就会被完全隐藏,只有内容布局会显示在界面上。
之后给内容布局注册监听事件,这样当手指在内容布局上滑动的时候就会触发onTouch事件。在onTouch事件里面,根据手指滑动的距离会改变菜单布局的左偏移量,从而控制菜单布局的显示和隐藏。当手指离开屏幕的时候,会判断应该滑动到菜单布局还是内容布局,判断依据是根据手指滑动的距离或者滑动的速度,细节可以看代码中的注释。
这里可以看到我们仅仅是针对 content进行了监听,所以当我们划出menu之后,在menu上滑动的话是不会有任何反应的。所以如果想在menu上滑动也有反应的话,可以监听整个layout
main.setOnTouchListener(this);//这样设置当显示menu的时候也可以在menu表面滑动关于这个到此结束,今天记录到这里。
- Android 记录3 Android滑动菜单特效实现
- Android滑动菜单特效实现
- Android滑动菜单特效实现
- Android滑动菜单特效实现
- Android滑动菜单特效实现
- Android滑动菜单框架一分钟实现滑动菜单特效
- Android滑动菜单特效实现,侧滑菜单实现
- Android双向滑动菜单 实现双向滑动特效
- Android双向滑动菜单特效
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效
- hiho一下 第四十八周
- poj1065 wooden sticks
- HDU 2023 求平均成绩
- 在嵌入式软件中使用断言的一点想法
- Web缓存技术-Memcached
- Android 记录3 Android滑动菜单特效实现
- Wampserver配置方法
- bzoj 2006
- OC 中的方法重载?
- 独立成分分析http://blog.sina.com.cn/s/blog_73402e3c0101gqy0.html
- $.ajax()方法详解
- [LeetCode] Maximum Depth of Binary Tree
- 解决:生成api文档出现的编码GBK的不可映射字符的问题
- 结巴分词源代码解析(二)