package com.sogouchat.ui; import com.sogouchat.SogouChatApp; import com.sogouchat.util.LayoutUtil; import android.content.Context; import android.graphics.Canvas; import android.os.Build; import android.support.v4.view.MotionEventCompat; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.Scroller; public class SlidingContent extends ViewGroup { private static final String TAG = "SlidingContent"; private FrameLayout mContainer; private Scroller mScroller; private VelocityTracker mVelocityTracker; public SogouChatApp mApp; private int mTouchSlop; private float mLastMotionX; private float mLastMotionY; private final static int TOUCH_STATE_REST = 0; private final static int TOUCH_STATE_SCROLLING = 1; // private static final int SNAP_VELOCITY = 1000; private final int MENU_WIDTH = LayoutUtil.dip2px(this.getContext(),200); private boolean mMenuOpen; public int mTouchState = TOUCH_STATE_REST; public SlidingContent(Context context) { super(context); init(); } public SlidingContent(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SlidingContent(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mContainer.measure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int width = r - l; final int height = b - t; mContainer.layout(0, 0, width, height); } private void init() { mMenuOpen = false; mContainer = new FrameLayout(getContext()); mScroller = new Scroller(getContext()); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); super.addView(mContainer); } public void setView(View v) { if (mContainer.getChildCount() > 0) { mContainer.removeAllViews(); } mContainer.addView(v); } @Override public void scrollTo(int x, int y) { Log.i(TAG, "scrollTo x="+x+" y="+y); super.scrollTo(x, y); if (x == -MENU_WIDTH){ mMenuOpen = true; } else if (x == 0){ mMenuOpen = false; } postInvalidate(); } @Override public void computeScroll() { if (!mScroller.isFinished()) { if (mScroller.computeScrollOffset()) { int oldX = getScrollX(); int oldY = getScrollY(); int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); if (oldX != x || oldY != y) { scrollTo(x, y); } // Keep on drawing until the animation has finished. invalidate(); return; } } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // Log.i(TAG, "onInterceptTouchEvent"); final int action = ev.getAction(); if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) { // Log.e(TAG, "return true"); return true; } final float x = ev.getX(); final float y = ev.getY(); switch (action) { case MotionEvent.ACTION_DOWN: // Log.i(TAG, "onInterceptTouchEvent-ACTION_DOWN"); // Remember location of down touch mLastMotionX = x; mLastMotionY = y; mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING; // Log.e("ad", "onInterceptTouchEvent ACTION_DOWN mTouchState==" // + (mTouchState == TOUCH_STATE_SCROLLING)); break; case MotionEvent.ACTION_MOVE: // Log.i(TAG, "onInterceptTouchEvent-ACTION_MOVE"); final int xDiff = (int) Math.abs(x - mLastMotionX); final int yDiff = (int) Math.abs(y - mLastMotionY); boolean moveLeft = mLastMotionX-x >0; boolean xMoved = xDiff > mTouchSlop; boolean yMoved = yDiff > mTouchSlop; if (xMoved && xDiff >yDiff*2) { // Scroll if the user moved far enough along the X axis mTouchState = TOUCH_STATE_SCROLLING; enableChildrenCache(); } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: // Log.i(TAG, "onInterceptTouchEvent-ACTION_UP"); // Release the drag clearChildrenCache(); mTouchState = TOUCH_STATE_REST; break; } return mTouchState != TOUCH_STATE_REST; } @Override public boolean onTouchEvent(MotionEvent ev) { Log.i(TAG, "onTouchEvent"); if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); final int action = ev.getAction(); final float x = ev.getX(); final float y = ev.getY(); switch (action) { case MotionEvent.ACTION_DOWN: Log.i(TAG, "onTouchEvent-ACTION_DOWN"); if (!mScroller.isFinished()) { mScroller.abortAnimation(); } mLastMotionX = x; mLastMotionY = y; if (getScrollX() == -MENU_WIDTH && mLastMotionX < MENU_WIDTH) { return false; } break; case MotionEvent.ACTION_MOVE: Log.i(TAG, "onTouchEvent-ACTION_MOVE"); final int xDiff = (int) Math.abs(x - mLastMotionX); final int yDiff = (int) Math.abs(y - mLastMotionY); final int touchSlop = mTouchSlop; boolean xMoved = xDiff > touchSlop; if (xMoved) { mTouchState = TOUCH_STATE_SCROLLING; enableChildrenCache(); } if (mTouchState == TOUCH_STATE_SCROLLING) { final float deltaX = mLastMotionX - x; mLastMotionX = x; float oldScrollX = getScrollX(); float scrollX = oldScrollX + deltaX; final float leftBound = 0; final float rightBound = -MENU_WIDTH; if (scrollX > leftBound) { scrollX = leftBound; } else if (scrollX < rightBound) { scrollX = rightBound; } scrollTo((int) scrollX, getScrollY()); } break; case MotionEvent.ACTION_UP: Log.i(TAG, "onTouchEvent-ACTION_UP"); if (mTouchState == TOUCH_STATE_SCROLLING) { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000); int velocityX = (int) velocityTracker.getXVelocity(); int oldScrollX = getScrollX(); int dx = 0; if (oldScrollX < -MENU_WIDTH/2) { dx = -MENU_WIDTH - oldScrollX; } else { dx = -oldScrollX; } smoothScrollTo(dx); if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } } mTouchState = TOUCH_STATE_REST; break; case MotionEvent.ACTION_CANCEL: Log.i(TAG, "onTouchEvent-ACTION_CANCEL"); mTouchState = TOUCH_STATE_REST; } return true; } void toggle() { int oldScrollX = getScrollX(); if (oldScrollX == 0) { mMenuOpen = true; smoothScrollTo(-MENU_WIDTH); } else if (oldScrollX == -MENU_WIDTH) { mMenuOpen = false; smoothScrollTo(MENU_WIDTH); } } void smoothScrollTo(int dx) { int duration = 500; int oldScrollX = getScrollX(); mScroller.startScroll(oldScrollX, getScrollY(), dx, getScrollY(), duration); invalidate(); } void enableChildrenCache() { final int count = getChildCount(); for (int i = 0; i < count; i++) { final View layout = (View) getChildAt(i); layout.setDrawingCacheEnabled(true); } } void clearChildrenCache() { final int count = getChildCount(); for (int i = 0; i < count; i++) { final View layout = (View) getChildAt(i); layout.setDrawingCacheEnabled(false); } } }