/*
* Copyright (C) 2012 www.amsoft.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ab.view.sliding;
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;
import com.ab.util.AbLogUtil;
// TODO: Auto-generated Javadoc
/**
* © 2012 amsoft.cn
* 名称:AbSlidingMenuView.java
* 描述:左右简单的侧边栏实现
* 滑动事件只在一个android:clickable="true"的View上.
*
* @author 还如一梦中
* @version v1.0
* @date:2013-05-17 下午6:46:29
*/
public class AbSlidingMenuView extends ViewGroup {
/** The m scroller. */
private Scroller mScroller;
/** The m velocity tracker. */
private VelocityTracker mVelocityTracker;
/** The m width. */
private int mWidth;
/** The Constant SCREEN_STATE_CLOSE. */
public static final int SCREEN_STATE_CLOSE = 0;
/** The Constant SCREEN_STATE_OPEN. */
public static final int SCREEN_STATE_OPEN = 1;
/** The Constant TOUCH_STATE_RESTART. */
public static final int TOUCH_STATE_RESTART = 0;
/** The Constant TOUCH_STATE_SCROLLING. */
public static final int TOUCH_STATE_SCROLLING = 1;
/** The Constant SCROLL_STATE_NO_ALLOW. */
public static final int SCROLL_STATE_NO_ALLOW = 0;
/** The Constant SCROLL_STATE_ALLOW. */
public static final int SCROLL_STATE_ALLOW = 1;
/** The m screen state. */
private int mScreenState = 0;
/** The m touch state. */
private int mTouchState = 0;
/** The m scroll state. */
private int mScrollState = 0;
/** The m velocity value. */
private int mVelocityValue = 0;
/** The m on click. */
private boolean mOnClick = false;
/**
* 构造.
* @param context the context
*/
public AbSlidingMenuView(Context context) {
super(context);
mScroller = new Scroller(context);
mWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,60, getResources().getDisplayMetrics());
}
/**
* 构造.
* @param context the context
* @param attrs the attrs
*/
public AbSlidingMenuView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 描述:View的位置设定.
*
* @param changed the changed
* @param l the l
* @param t the t
* @param r the r
* @param b the b
*/
@Override
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);
}
}
/**
* 描述:测量View的宽高.
*
* @param widthMeasureSpec the width measure spec
* @param heightMeasureSpec the height measure spec
* @see android.view.View#onMeasure(int, int)
*/
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);
}
}
/**
* 描述:执行触摸事件.
*
* @param ev the ev
* @return true, if successful
* @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
obtainVelocityTracker(ev);
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
AbLogUtil.d(AbSlidingMenuView.class, "--dispatchTouchEvent 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 {
AbLogUtil.d(AbSlidingMenuView.class, "--dispatchTouchEvent ACTION_DOWN return false--");
return false;
}
break;
case MotionEvent.ACTION_MOVE:
AbLogUtil.d(AbSlidingMenuView.class, "--dispatchTouchEvent ACTION_MOVE--");
mVelocityTracker.computeCurrentVelocity(1000,ViewConfiguration.getMaximumFlingVelocity());
if (mScrollState == SCROLL_STATE_ALLOW && getWidth() - (int) ev.getX() < mWidth) {
AbLogUtil.d(AbSlidingMenuView.class, "--dispatchTouchEvent ACTION_MOVE return true--");
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);
}
/**
* 描述:拦截的触摸事件.
*
* @param ev the ev
* @return true, if successful
* @see android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
*/
public boolean onInterceptTouchEvent(MotionEvent ev) {
obtainVelocityTracker(ev);
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
AbLogUtil.d(AbSlidingMenuView.class, "--onInterceptTouchEvent ACTION_DOWN--");
mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART : TOUCH_STATE_SCROLLING;
if (mTouchState==TOUCH_STATE_SCROLLING) {
AbLogUtil.d(AbSlidingMenuView.class, "--onInterceptTouchEvent ACTION_DOWN return false--");
return false;
}
break;
case MotionEvent.ACTION_MOVE:
AbLogUtil.d(AbSlidingMenuView.class, "--onInterceptTouchEvent ACTION_MOVE--");
mOnClick = false;
mVelocityTracker.computeCurrentVelocity(1000,ViewConfiguration.getMaximumFlingVelocity());
if (mScrollState == SCROLL_STATE_ALLOW && Math.abs(mVelocityTracker.getXVelocity()) > 200) {
AbLogUtil.d(AbSlidingMenuView.class, "--onInterceptTouchEvent ACTION_MOVE return true--");
return true;
}
break;
case MotionEvent.ACTION_UP:
releaseVelocityTracker();
if (mScrollState == SCROLL_STATE_ALLOW && mScreenState == SCREEN_STATE_OPEN) {
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
/**
* 描述:触摸事件.
*
* @param event the event
* @return true, if successful
* @see android.view.View#onTouchEvent(android.view.MotionEvent)
*/
public boolean onTouchEvent(MotionEvent event) {
obtainVelocityTracker(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
AbLogUtil.d(AbSlidingMenuView.class, "--onTouchEvent ACTION_DOWN--");
mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART : TOUCH_STATE_SCROLLING;
if (mTouchState==TOUCH_STATE_SCROLLING) {
AbLogUtil.d(AbSlidingMenuView.class, "--onTouchEvent ACTION_DOWN return false--");
return false;
}
break;
case MotionEvent.ACTION_MOVE:
AbLogUtil.d(AbSlidingMenuView.class, "--onTouchEvent 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);
}
/**
* 打开menu.
*/
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();
}
}
/**
* 关闭menu.
*/
public void close() {
mScreenState = SCREEN_STATE_CLOSE;
mScroller.startScroll(getChildAt(1).getScrollX(), 0, -getChildAt(1).getScrollX(), 0, 800);
invalidate();
}
/**
* 描述:滚动.
*
* @see android.view.View#computeScroll()
*/
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
getChildAt(1).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
/**
* 初始化速度检测.
*
* @param event the event
*/
private void obtainVelocityTracker(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
}
/**
* 释放速度检测.
*/
private void releaseVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
/**
* 获取当前状态.
* @return the screen state
*/
public int getScreenState() {
return mScreenState;
}
/**
* 设置主View.
*
* @param view the new content view
*/
public void setContentView(View view) {
removeViewAt(1);
addView(view, 1, getLayoutParams());
}
}