码迷,mamicode.com
首页 > 移动开发 > 详细

Android 侧滑菜单的实现

时间:2015-11-01 10:15:36      阅读:306      评论:0      收藏:0      [点我收藏+]

标签:path   源码   menu   

Android 侧滑菜单的实现,参考网上的代码,实现侧滑菜单。最重要的是这个动画类UgcAnimations,如何使用动画类来侧滑的封装FlipperLayout。

本文项目源码:点击

1、实现效果

技术分享

2、动画类UgcAnimations

package com.mmsx.base;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.OvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;

/**
 * Path动画类
 * 
 */
public class UgcAnimations {
	private static int xOffset = 15;
	private static int yOffset = -13;

	public static void initOffset(Context context) {
		xOffset = (int) (15 * context.getResources().getDisplayMetrics().density);
		yOffset = -(int) (13 * context.getResources().getDisplayMetrics().density);
	}

	public static Animation getRotateAnimation(float fromDegrees,
			float toDegrees, long durationMillis) {
		RotateAnimation rotate = new RotateAnimation(fromDegrees, toDegrees,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		rotate.setDuration(durationMillis);
		rotate.setFillAfter(true);
		return rotate;
	}

	public static Animation getAlphaAnimation(float fromAlpha, float toAlpha,
			long durationMillis) {
		AlphaAnimation alpha = new AlphaAnimation(fromAlpha, toAlpha);
		alpha.setDuration(durationMillis);
		alpha.setFillAfter(true);
		return alpha;
	}

	public static Animation getScaleAnimation(long durationMillis) {
		ScaleAnimation scale = new ScaleAnimation(1.0f, 1.5f, 1.0f, 1.5f,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		scale.setDuration(durationMillis);
		return scale;
	}

	public static Animation getTranslateAnimation(float fromXDelta,
			float toXDelta, float fromYDelta, float toYDelta,
			long durationMillis) {
		TranslateAnimation translate = new TranslateAnimation(fromXDelta,
				toXDelta, fromYDelta, toYDelta);
		translate.setDuration(durationMillis);
		translate.setFillAfter(true);
		return translate;
	}

	public static void startOpenAnimation(RelativeLayout relativeLayout,
			ImageView background, ImageView menu, long durationMillis) {
		background.setVisibility(View.VISIBLE);
		relativeLayout.setVisibility(View.VISIBLE);
		background.startAnimation(getAlphaAnimation(0f, 1f, durationMillis));
		menu.startAnimation(getRotateAnimation(0, 90, durationMillis));
		for (int i = 0; i < relativeLayout.getChildCount(); i++) {
			ImageView imageView = (ImageView) relativeLayout.getChildAt(i);
			imageView.setVisibility(View.VISIBLE);
			MarginLayoutParams params = (MarginLayoutParams) imageView
					.getLayoutParams();
			AnimationSet set = new AnimationSet(true);
			set.addAnimation(getRotateAnimation(-270, 0, durationMillis));
			set.addAnimation(getAlphaAnimation(0.5f, 1.0f, durationMillis));
			set.addAnimation(getTranslateAnimation(
					-params.leftMargin + xOffset, 0f, params.bottomMargin
							+ yOffset, 0f, durationMillis));
			set.setFillAfter(true);
			set.setDuration(durationMillis);
			set.setStartOffset((i * 100)
					/ (-1 + relativeLayout.getChildCount()));
			set.setInterpolator(new OvershootInterpolator(1f));
			imageView.startAnimation(set);
		}
	}

	public static void startCloseAnimation(final RelativeLayout relativeLayout,
			final ImageView background, ImageView menu, long durationMillis) {
		background.startAnimation(getAlphaAnimation(1f, 0f, durationMillis));
		menu.startAnimation(getRotateAnimation(90, 0, durationMillis));
		for (int i = 0; i < relativeLayout.getChildCount(); i++) {
			final ImageView imageView = (ImageView) relativeLayout
					.getChildAt(i);
			MarginLayoutParams params = (MarginLayoutParams) imageView
					.getLayoutParams();
			AnimationSet set = new AnimationSet(true);
			set.addAnimation(getRotateAnimation(0, -270, durationMillis));
			set.addAnimation(getAlphaAnimation(1.0f, 0.5f, durationMillis));
			set.addAnimation(getTranslateAnimation(0f, -params.leftMargin
					+ xOffset, 0f, params.bottomMargin + yOffset,
					durationMillis));
			set.setFillAfter(true);
			set.setDuration(durationMillis);
			set.setStartOffset(((relativeLayout.getChildCount() - i) * 100)
					/ (-1 + relativeLayout.getChildCount()));
			set.setInterpolator(new AnticipateInterpolator(1f));
			set.setAnimationListener(new Animation.AnimationListener() {
				public void onAnimationStart(Animation arg0) {
				}

				public void onAnimationRepeat(Animation arg0) {
				}

				public void onAnimationEnd(Animation arg0) {
					relativeLayout.setVisibility(View.GONE);
					background.setVisibility(View.GONE);
				}
			});
			imageView.startAnimation(set);
		}
	}

	public static Animation clickAnimation(long durationMillis) {
		AnimationSet set = new AnimationSet(true);
		set.addAnimation(getAlphaAnimation(1.0f, 0.3f, durationMillis));
		set.addAnimation(getScaleAnimation(durationMillis));
		set.setDuration(durationMillis);
		return set;
	}
}

3、封装使用动画类FlipperLayout

package com.mmsx.base;

import android.content.Context;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

/**
 * 自己重写的ViewGroup,用与滑动切换界面使用,代码不详解,慢点看的话应该能看懂的...
 */
public class FlipperLayout extends ViewGroup {

	private Scroller mScroller;
	private VelocityTracker mVelocityTracker;
	private int mWidth;

	public static final int SCREEN_STATE_CLOSE = 0;
	public static final int SCREEN_STATE_OPEN = 1;
	public static final int TOUCH_STATE_RESTART = 0;
	public static final int TOUCH_STATE_SCROLLING = 1;
	public static final int SCROLL_STATE_NO_ALLOW = 0;
	public static final int SCROLL_STATE_ALLOW = 1;
	private int mScreenState = 0;
	private int mTouchState = 0;
	private int mScrollState = 0;
	private int mVelocityValue = 0;
	private boolean mOnClick = false;
	private onUgcDismissListener mOnUgcDismissListener;
	private onUgcShowListener mOnUgcShowListener;

	public FlipperLayout(Context context) {
		super(context);
		mScroller = new Scroller(context);
		mWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
				54, getResources().getDisplayMetrics());

	}

	public FlipperLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public FlipperLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		for (int i = 0; i < getChildCount(); i++) {
			View child = getChildAt(i);
			int height = child.getMeasuredHeight();
			int width = child.getMeasuredWidth();
			child.layout(0, 0, width, height);
		}
	}

	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int width = MeasureSpec.getSize(widthMeasureSpec);
		int height = MeasureSpec.getSize(heightMeasureSpec);
		setMeasuredDimension(width, height);
		for (int i = 0; i < getChildCount(); i++) {
			getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
		}
	}

	public boolean dispatchTouchEvent(MotionEvent ev) {
		obtainVelocityTracker(ev);
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
					: TOUCH_STATE_SCROLLING;
			if (mTouchState == TOUCH_STATE_RESTART) {
				int x = (int) ev.getX();
				int screenWidth = getWidth();
				if (x <= mWidth && mScreenState == SCREEN_STATE_CLOSE
						&& mTouchState == TOUCH_STATE_RESTART
						|| x >= screenWidth - mWidth
						&& mScreenState == SCREEN_STATE_OPEN
						&& mTouchState == TOUCH_STATE_RESTART) {
					if (mScreenState == SCREEN_STATE_OPEN) {
						mOnClick = true;
					}
					mScrollState = SCROLL_STATE_ALLOW;
				} else {
					mOnClick = false;
					mScrollState = SCROLL_STATE_NO_ALLOW;
				}
			} else {
				return false;
			}
			break;
		case MotionEvent.ACTION_MOVE:
			mVelocityTracker.computeCurrentVelocity(1000,
					ViewConfiguration.getMaximumFlingVelocity());
			if (mScrollState == SCROLL_STATE_ALLOW
					&& getWidth() - (int) ev.getX() < mWidth) {
				return true;
			}
			break;
		case MotionEvent.ACTION_UP:
			releaseVelocityTracker();
			if (mOnClick) {
				mOnClick = false;
				mScreenState = SCREEN_STATE_CLOSE;
				mScroller.startScroll(getChildAt(1).getScrollX(), 0,
						-getChildAt(1).getScrollX(), 0, 800);
				invalidate();
			}
			break;
		}
		return super.dispatchTouchEvent(ev);
	}

	public boolean onInterceptTouchEvent(MotionEvent ev) {
		obtainVelocityTracker(ev);
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
					: TOUCH_STATE_SCROLLING;
			if (mTouchState == TOUCH_STATE_SCROLLING) {
				return false;
			}
			break;

		case MotionEvent.ACTION_MOVE:
			mOnClick = false;
			mVelocityTracker.computeCurrentVelocity(1000,
					ViewConfiguration.getMaximumFlingVelocity());
			if (mScrollState == SCROLL_STATE_ALLOW
					&& Math.abs(mVelocityTracker.getXVelocity()) > 200) {
				return true;
			}
			break;

		case MotionEvent.ACTION_UP:
			releaseVelocityTracker();
			if (mScrollState == SCROLL_STATE_ALLOW
					&& mScreenState == SCREEN_STATE_OPEN) {
				return true;
			}
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}

	public boolean onTouchEvent(MotionEvent event) {
		obtainVelocityTracker(event);
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
					: TOUCH_STATE_SCROLLING;
			if (mTouchState == TOUCH_STATE_SCROLLING) {
				return false;
			}
			break;

		case MotionEvent.ACTION_MOVE:
			mVelocityTracker.computeCurrentVelocity(1000,
					ViewConfiguration.getMaximumFlingVelocity());
			mVelocityValue = (int) mVelocityTracker.getXVelocity();
			getChildAt(1).scrollTo(-(int) event.getX(), 0);
			break;

		case MotionEvent.ACTION_UP:
			if (mScrollState == SCROLL_STATE_ALLOW) {
				if (mVelocityValue > 2000) {
					mScreenState = SCREEN_STATE_OPEN;
					mScroller
							.startScroll(
									getChildAt(1).getScrollX(),
									0,
									-(getWidth()
											- Math.abs(getChildAt(1)
													.getScrollX()) -

									mWidth), 0, 250);
					invalidate();

				} else if (mVelocityValue < -2000) {
					mScreenState = SCREEN_STATE_CLOSE;
					mScroller.startScroll(getChildAt(1).getScrollX(), 0,
							-getChildAt(1).getScrollX(), 0, 250);
					invalidate();
				} else if (event.getX() < getWidth() / 2) {
					mScreenState = SCREEN_STATE_CLOSE;
					mScroller.startScroll(getChildAt(1).getScrollX(), 0,
							-getChildAt(1).getScrollX(), 0, 800);
					invalidate();
				} else {
					mScreenState = SCREEN_STATE_OPEN;
					mScroller
							.startScroll(
									getChildAt(1).getScrollX(),
									0,
									-(getWidth()
											- Math.abs(getChildAt(1)
													.getScrollX()) -

									mWidth), 0, 800);
					invalidate();
				}
			}
			break;
		}
		return super.onTouchEvent(event);
	}

	public void open() {
		mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
				: TOUCH_STATE_SCROLLING;
		if (mTouchState == TOUCH_STATE_RESTART) {
			mScreenState = SCREEN_STATE_OPEN;
			mScroller.startScroll(getChildAt(1).getScrollX(), 0, -(getWidth()
					- Math.abs(getChildAt(1).getScrollX()) -

			mWidth), 0, 800);
			invalidate();
		}
	}

	//关闭当前的侧滑菜单,用view打开点击事件的页面
	public void close(View view) {
		mScreenState = SCREEN_STATE_CLOSE;
		mScroller.startScroll(getChildAt(1).getScrollX(), 0, -getChildAt(1)
				.getScrollX(), 0, 800);
		invalidate();
		setContentView(view);
	}

	public void computeScroll() {
		super.computeScroll();
		if (mScroller.computeScrollOffset()) {
			getChildAt(1).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
			postInvalidate();
		} else {
			if (mScreenState == SCREEN_STATE_OPEN) {
				if (mOnUgcDismissListener != null) {
					mOnUgcDismissListener.dismiss();
				}
			} else if (mScreenState == SCREEN_STATE_CLOSE) {
				if (mOnUgcShowListener != null) {
					mOnUgcShowListener.show();
				}
			}
		}
	}

	private void obtainVelocityTracker(MotionEvent event) {
		if (mVelocityTracker == null) {
			mVelocityTracker = VelocityTracker.obtain();
		}
		mVelocityTracker.addMovement(event);
	}

	private void releaseVelocityTracker() {
		if (mVelocityTracker != null) {
			mVelocityTracker.recycle();
			mVelocityTracker = null;
		}
	}

	public int getScreenState() {
		return mScreenState;
	}

	public void setContentView(View view) {
		removeViewAt(1);
		addView(view, 1, getLayoutParams());
	}

	public interface OnOpenListener {
		public abstract void open();
	}

	public interface OnCloseListener {
		public abstract void close();
	}

	public interface onUgcDismissListener {
		public abstract void dismiss();
	}

	public interface onUgcShowListener {
		public abstract void show();
	}

	public void setOnUgcDismissListener(
			onUgcDismissListener onUgcDismissListener) {
		mOnUgcDismissListener = onUgcDismissListener;
	}

	public void setOnUgcShowListener(onUgcShowListener onUgcShowListener) {
		mOnUgcShowListener = onUgcShowListener;
	}
}
4、主界面MainActivity
package com.mmsx.activity;

import com.mmsx.activity.SideslipMenu.onChangeViewListener;
import com.mmsx.activity.SideslipOther.onDataListener;
import com.mmsx.base.FlipperLayout;
import com.mmsx.base.FlipperLayout.OnOpenListener;
import com.mmsx.base.ViewUtil;
import android.os.Bundle;
import android.app.Activity;
import android.view.ViewGroup.LayoutParams;
import android.widget.Toast;

public class MainActivity extends Activity implements OnOpenListener{

	//侧滑主要控制类,设置跟布局
	private FlipperLayout mRoot;
	//侧滑的默认界面,主界面
	private SideslipHome mHome;
	//侧滑的菜单,进行选择的
	private SideslipMenu mSideslipMenu;
	//其他菜单列表选择的效果
	private SideslipOther mOther;
	//退出时间间隔变量
	private long mExitTime;
	//时间间隔2s
	private static final int INTERVAL = 2000;
	//侧滑菜单选中的item
	private int mViewPosition;
	//侧滑传递的标题
	private String mstrTitle;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		 //创建容器,并设置全屏大小
		mRoot = new FlipperLayout(this);
		//布局的参数
		LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.FILL_PARENT);
		mRoot.setLayoutParams(params);
		//创建菜单界面和内容首页界面,并添加到容器中,用于初始显示
		mHome = new SideslipHome(this, this);
		mSideslipMenu = new SideslipMenu(this);
		mRoot.addView(mSideslipMenu.getView(), params);
		mRoot.addView(mHome.getView(), params);
		//设置跟布局
		setContentView(mRoot);
		//设置监听
		setListener();
	}

	//设置监听
	private void setListener() {
		mHome.setOnOpenListener(this);
		 //监听菜单界面切换显示内容(onChangeViewListener接口在SideslipMenu中定义)
		mSideslipMenu.setOnChangeViewListener(new onChangeViewListener() {
			
			public void onChangeView(int arg0) {
				mViewPosition = arg0;
				mOther = new SideslipOther(MainActivity.this);
				switch (arg0) {
				case ViewUtil.HOME:
					mRoot.close(mHome.getView());
					break;
				case ViewUtil.MESSAGE:
					mstrTitle = "消息";
					//设置数据接口监听
					mOther.setDataTitle(new DataTitle());
					mRoot.close(mOther.getView());
					break;
				case ViewUtil.FRIENDS:
					mstrTitle = "好友";
					mOther.setDataTitle(new DataTitle());
					mRoot.close(mOther.getView());
					break;
				case ViewUtil.PHOTO:
					mstrTitle = "照片";
					mOther.setDataTitle(new DataTitle());
					mRoot.close(mOther.getView());
					break;
				case ViewUtil.VIEWED:
					mstrTitle = "转帖";
					mOther.setDataTitle(new DataTitle());
					mRoot.close(mOther.getView());
					break;
				case ViewUtil.GIFTS:
					mstrTitle = "礼物";
					mOther.setDataTitle(new DataTitle());
					mRoot.close(mOther.getView());
					break;
				case ViewUtil.RECOMMEND:
					mstrTitle = "游戏";
					mOther.setDataTitle(new DataTitle());
					mRoot.close(mOther.getView());
					break;
				case ViewUtil.LBS:
					mstrTitle = "附近 ";
					mOther.setDataTitle(new DataTitle());
					mRoot.close(mOther.getView());
					break;
				default:
					break;
				}
			}
		});
	}
	
	//传递数据到侧滑选中的页面
	private class DataTitle implements onDataListener{
		@Override
		public String getDataTitle() {
			return mstrTitle;
		}
		
	}

	@Override
	public void open() {
		if (mRoot.getScreenState() == FlipperLayout.SCREEN_STATE_CLOSE) {
			mRoot.open();
		}
	}
	
	/**
	 * 返回键监听
	 */
	public void onBackPressed() {
		/**
		 * 如果界面的path菜单没有关闭时,先将path菜单关闭,否则则判断两次返回时间间隔,小于两秒则退出程序
		 */
		if (mRoot.getScreenState() == FlipperLayout.SCREEN_STATE_OPEN) {
			if (mSideslipMenu.getUgcIsShowing()) {
				mSideslipMenu.closeUgc();
			} else {
				exit();
			}
		} else {
			switch (mViewPosition) {
			case ViewUtil.HOME:
				if (mHome.getUgcIsShowing()) {
					mHome.closeUgc();
				} else {
					exit();
				}
				break;
			default:
				exit();
				break;
			}

		}

	}	
	

	/**
	 * 判断两次返回时间间隔,小于两秒则退出程序
	 */
	private void exit() {
		if (System.currentTimeMillis() - mExitTime > INTERVAL) {
			Toast.makeText(this, "再按一次返回键,可直接退出程序", Toast.LENGTH_SHORT).show();
			mExitTime = System.currentTimeMillis();
		} else {
			finish();
			android.os.Process.killProcess(android.os.Process.myPid());
			System.exit(0);
		}
	}
}

5、SideslipHome

package com.mmsx.activity;


import com.mmsx.base.FlipperLayout.OnOpenListener;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class SideslipHome {
	private Context mContext;
	private Activity mActivity;
	private View mHomeView;
	private boolean mUgcIsShowing = false;	
	private OnOpenListener mOnOpenListener;
	public SideslipHome(Context context, Activity activity) {
		mContext = context;
		mActivity = activity;
		mHomeView = LayoutInflater.from(context).inflate(R.layout.sideslip_home, null);
		
		initUI();
	}

	private void initUI() {
		TextView ivTitleName = (TextView)mHomeView.findViewById(R.id.ivTitleName); 
		ivTitleName.setText("主页动态");
		
	}
	
	public void setOnOpenListener(OnOpenListener onOpenListener) {
		mOnOpenListener = onOpenListener;
	}

	public View getView() {
		return mHomeView;
	}
	
	/**
	 * 获取Path菜单显示状态
	 */
	public boolean getUgcIsShowing() {
		return mUgcIsShowing;
	}

	/**
	 * 关闭Path菜单
	 */
	public void closeUgc() {
		mUgcIsShowing = false;
	}

}

还有部分源码为贴出,有兴趣可以下载。

本文项目源码:点击

版权声明:本文为博主原创文章,未经博主允许不得转载。

Android 侧滑菜单的实现

标签:path   源码   menu   

原文地址:http://blog.csdn.net/qq_16064871/article/details/49556025

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!