这里实现两种侧滑菜单效果,第一种拖拽内容部分,菜单像是被拖出来的感觉的这种效果,第二种是拖拽内容部分,菜单在内容后面不动,感觉有一种层次感的效果,如下
第一种效果的代码实现如下:
package com.tenghu.customsideslip.menu.view;
import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
/**
* Created by Arvin_Li on 2014/11/19.
*/
public class ScrollSideslipMenu extends LinearLayout{
private static final int SNAP_VELOCITY=200;//速度阈值
private View mMenu;//菜单布局
private View mContent;//内容布局
private int screenWidth;//屏幕宽度
private int menuWidth;//菜单宽度
private int leftEdge;//左边界
private int rightEdge=0;//右边界,值恒为0
private float xUp;//手指抬起时记录横坐标
private float xDown;//手指按下时记录横坐标
private float xMove;//手指移动时记录横坐标
private int toRightPaddingWidth=50;//菜单完全显示时,留给内容的宽度
private LayoutParams menuParams;//菜单布局参数
private boolean once=false;//初始化数据只加载一次
private boolean isShowMenu;//是否显示菜单
private VelocityTracker velocityTracker;//速度跟踪器
public ScrollSideslipMenu(Context context) {
super(context);
initWindowWidth(context);
}
public ScrollSideslipMenu(Context context, AttributeSet attrs) {
super(context, attrs);
initWindowWidth(context);
}
/**
* 初始化获取屏幕宽度
*/
private void initWindowWidth(Context context){
WindowManager windowManager= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics=new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
//获取屏幕宽度
screenWidth=displayMetrics.widthPixels;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(!once){
mMenu=this.getChildAt(0);//获取菜单布局
mContent=this.getChildAt(1);//获取内容布局
menuParams= (LayoutParams) mMenu.getLayoutParams();//获取菜单布局参数
menuWidth=menuParams.width=screenWidth-toRightPaddingWidth;//设置菜单宽度
mContent.getLayoutParams().width=screenWidth;//设置内容宽度
leftEdge=-menuWidth;//左边界
menuParams.leftMargin=leftEdge;//默认菜单不显示
once=true;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
createVelocityTracker(event);
switch (event.getAction()){
//按下
case MotionEvent.ACTION_DOWN:
xDown=event.getRawX();//记录按下时的横坐标
break;
//移动
case MotionEvent.ACTION_MOVE:
//记录移动时的横坐标
xMove=event.getRawX();
//计算移动时与按下时的距离
int moveDistanceX= (int) (xMove-xDown);
if(isShowMenu){
menuParams.leftMargin=moveDistanceX;
}else{
menuParams.leftMargin=leftEdge+moveDistanceX;
}
if(menuParams.leftMargin<leftEdge){
menuParams.leftMargin=leftEdge;
}
if(menuParams.leftMargin>rightEdge){
menuParams.leftMargin=rightEdge;
}
mMenu.setLayoutParams(menuParams);//设置参数
break;
//抬起
case MotionEvent.ACTION_UP:
//记录抬起时的横坐标
xUp=event.getRawX();
//计算抬起时与按下时的距离
int upDistanceX= (int) (xUp-xDown);
if(upDistanceX>0&&!isShowMenu){
if(upDistanceX>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){
scrollToMenu();
}else{
scrollToContent();
}
}else if(upDistanceX<0&&isShowMenu){
if(Math.abs(upDistanceX)>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){
scrollToContent();
}else{
scrollToMenu();
}
}
mMenu.setLayoutParams(menuParams);
break;
}
return true;
}
/**
* 滚动内容部分
*/
private void scrollToContent(){
new ScrollTask().execute(-30);
}
/**
* 滚动菜单部分
*/
private void scrollToMenu(){
new ScrollTask().execute(30);
}
/**
* 创建速度阈值
*/
private void createVelocityTracker(MotionEvent event){
if(null==velocityTracker){
velocityTracker=VelocityTracker.obtain();
}
velocityTracker.addMovement(event);
}
/**
* 获取滚动时的速度
* @return
*/
private int getScrollVelocity(){
velocityTracker.computeCurrentVelocity(1000);
int velocity= (int) velocityTracker.getXVelocity();//获取横向速度
return Math.abs(velocity);
}
/**
* 创建一个异步滚动任务
*/
class ScrollTask extends AsyncTask<Integer,Integer,Integer>{
@Override
protected Integer doInBackground(Integer... params) {
int leftMargin=menuParams.leftMargin;
while(true){
leftMargin=leftMargin+params[0];
if(leftMargin<leftEdge){
leftMargin=leftEdge;
break;
}
if(leftMargin>rightEdge){
leftMargin=rightEdge;
break;
}
publishProgress(leftMargin);
sleep(20);
}
if(params[0]>0){
isShowMenu=true;
}else{
isShowMenu=false;
}
return leftMargin;
}
/**
* 执行结束
* @param integer
*/
@Override
protected void onPostExecute(Integer integer) {
menuParams.leftMargin=integer;
mMenu.setLayoutParams(menuParams);
}
/**
* 执行doInBackground中的publishProgress调用该方法
* @param values
*/
@Override
protected void onProgressUpdate(Integer... values) {
menuParams.leftMargin=values[0];
mMenu.setLayoutParams(menuParams);
}
}
/**
* 当前线程睡眠多少毫秒
* @param millis
*/
private void sleep(long millis){
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<com.tenghu.customsideslip.menu.view.ScrollSideslipMenu xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="@drawable/bg_01">
<!--引用菜单布局文件-->
<include layout="@layout/left_menu"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_02"></LinearLayout>
</com.tenghu.customsideslip.menu.view.ScrollSideslipMenu>
package com.tenghu.customsideslip.menu.view;
import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.WindowManager;
import android.widget.RelativeLayout;
/**
* Created by Arvin_Li on 2014/11/19.
*/
public class CustomSideslipMenu extends RelativeLayout {
private static final int SNAP_VELOCITY=200;//手势滑动的速度
//屏幕宽度
private int mScreenWidth;
//菜单布局
private View mMenu;
//主体内容部分
private View mContent;
//声明菜单宽度
private int menuWidth;
//菜单完全显示时,留给内容部分的宽度
private int toRightPaddingWidth=50;
//主体内容布局参数
private LayoutParams contentParams;
//主体内容滑动到左边缘,由菜单宽度来决定
private int leftEdge;
//菜单显示时,主体内容到右边界,值恒为0
private int rightEdge=0;
private VelocityTracker velocityTracker;//声明速度跟踪器
private float xDown;//记录手指按下的横坐标
private float xUp;//记录手指抬起时的横坐标
private float xMove;//记录手指移动时的横坐标
private boolean once=false;//只执行一次
private boolean isShowMenu=true;//是否显示菜单
public CustomSideslipMenu(Context context) {
super(context);
init(context);
}
public CustomSideslipMenu(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
/**
* 初始化
*/
private void init(Context context){
//获取窗口管理类
WindowManager windowManager= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
//创建DisplayMetrics
DisplayMetrics displayMetrics=new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
//获取屏幕宽度
mScreenWidth=displayMetrics.widthPixels;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(!once){
//获取菜单布局
mMenu=this.getChildAt(0);
//获取主体内容布局
mContent=this.getChildAt(1);
contentParams= (LayoutParams) mContent.getLayoutParams();//获取主体菜单参数
//菜单宽度
menuWidth=mMenu.getLayoutParams().width=mScreenWidth-toRightPaddingWidth;
//设置主体内容的宽度
mContent.getLayoutParams().width=mScreenWidth;
leftEdge=menuWidth;//设置左边界
once=true;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//调用创建速度跟踪器
createVelocityTracker(event);
switch (event.getAction()){
//手指按下
case MotionEvent.ACTION_DOWN:
xDown=event.getRawX();
break;
//手指移动
case MotionEvent.ACTION_MOVE:
xMove=event.getRawX();
//计算移动距离
int distanceX= (int) (xMove-xDown);
if(isShowMenu){
contentParams.leftMargin=distanceX;
contentParams.rightMargin=-distanceX;
}else{
contentParams.leftMargin=leftEdge+distanceX;
}
if(contentParams.leftMargin>leftEdge){
contentParams.leftMargin=leftEdge;
contentParams.rightMargin=-leftEdge;
}
if(contentParams.leftMargin<rightEdge){
contentParams.leftMargin=rightEdge;
contentParams.rightMargin=rightEdge;
}
mContent.setLayoutParams(contentParams);//测试参数
break;
//手指抬起
case MotionEvent.ACTION_UP:
xUp=event.getRawX();//手指抬起时横坐标
//计算抬起时与按下时的距离
int upDistanceX=(int) (xDown-xUp);
if(upDistanceX>0&&!isShowMenu){
if(upDistanceX>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){
scrollToMenu();
}else{
scrollToContent();
}
}else if(upDistanceX<0&&isShowMenu){
if(Math.abs(upDistanceX)>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){
scrollToContent();
}else{
scrollToMenu();
}
//手指抬起时销毁
recycleVelocityTracker();
}
break;
}
return true;
}
/**
* 滚动菜单
*/
private void scrollToMenu(){
new ScrollTask().execute(-30);
}
/**
* 滚动内容
*/
private void scrollToContent(){
new ScrollTask().execute(30);
}
/**
* 获取速度
* @return
*/
private int getScrollVelocity(){
velocityTracker.computeCurrentVelocity(1000);
int velocity= (int) velocityTracker.getXVelocity();
return Math.abs(velocity);
}
/**
* 销毁速度跟踪器
*/
private void recycleVelocityTracker(){
if (null != velocityTracker) {
velocityTracker.recycle();
velocityTracker = null;
}
}
/**
* 创建速度跟踪器
*/
private void createVelocityTracker(MotionEvent event){
if(null==velocityTracker){
velocityTracker=velocityTracker.obtain();
}
velocityTracker.addMovement(event);
}
/**
* 创建异步滚动任务类
*/
class ScrollTask extends AsyncTask<Integer,Integer,Integer>{
@Override
protected Integer doInBackground(Integer... params) {
int leftMargin=contentParams.leftMargin;
while(true){
leftMargin=leftMargin+params[0];
if(leftMargin>leftEdge){
leftMargin=leftEdge;
break;
}
if(leftMargin<rightEdge){
leftMargin=rightEdge;
break;
}
if(params[0]<0){
isShowMenu=true;
// leftMargin=rightEdge;
}else{
isShowMenu=false;
}
publishProgress(leftMargin);
sleep(20);
}
return leftMargin;
}
@Override
protected void onProgressUpdate(Integer... values) {
contentParams.leftMargin=values[0];
contentParams.rightMargin=-values[0];
mContent.setLayoutParams(contentParams);
}
@Override
protected void onPostExecute(Integer integer) {
contentParams.leftMargin=integer;
contentParams.rightMargin=-integer;
mContent.setLayoutParams(contentParams);
}
}
/**
* 当前线程睡眠多少毫秒
* @param millis
*/
private void sleep(long millis){
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
<com.tenghu.customsideslip.menu.view.CustomSideslipMenu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_01"
tools:context=".MainActivity">
<include layout="@layout/left_menu" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_02"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="testScrollMenu"
android:text="测试第二种侧滑菜单"/>
</LinearLayout>
</LinearLayout>
</com.tenghu.customsideslip.menu.view.CustomSideslipMenu>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:orientation="vertical">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginBottom="10dp">
<ImageView
android:id="@+id/iv_img_01"
android:layout_width="50dp"
android:layout_height="match_parent"
android:src="@drawable/app_01" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/iv_img_01"
android:gravity="center_vertical"
android:text="第一个Item" />
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginBottom="10dp">
<ImageView
android:id="@+id/iv_img_02"
android:layout_width="50dp"
android:layout_height="match_parent"
android:src="@drawable/app_02" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/iv_img_02"
android:gravity="center_vertical"
android:text="第二个Item" />
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginBottom="10dp">
<ImageView
android:id="@+id/iv_img_03"
android:layout_width="50dp"
android:layout_height="match_parent"
android:src="@drawable/app_03" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/iv_img_03"
android:gravity="center_vertical"
android:text="第三个Item" />
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginBottom="10dp">
<ImageView
android:id="@+id/iv_img_04"
android:layout_width="50dp"
android:layout_height="match_parent"
android:src="@drawable/app_04" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/iv_img_04"
android:gravity="center_vertical"
android:text="第四个Item" />
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginBottom="10dp">
<ImageView
android:id="@+id/iv_img_05"
android:layout_width="50dp"
android:layout_height="match_parent"
android:src="@drawable/app_05" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/iv_img_05"
android:gravity="center_vertical"
android:text="第五个Item" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_02"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="testScrollMenu"
android:text="测试第二种侧滑菜单"/>
</LinearLayout>
</LinearLayout>如果将背景设置到第一层的LinearLayout上,那么自定义侧滑菜单那里设置背景就显示不出来,设置到第二层就可以,不知道是肿么回事,如果各位大师找到了,麻烦告诉小弟。原文:http://blog.csdn.net/u011109042/article/details/41283245