直接看效果图:
主要实现代码:
package com.way.view; import android.content.Context; import android.media.DeniedByServerException; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.WindowManager; import android.view.animation.AnimationUtils; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.Scroller; public class HomeCenterLayout extends RelativeLayout { private final static String TAG = "HomeCenterLayout"; public static final int LEFT = 0x001; public static final int RIGHT = 0x002; public static final int MIDDLE = 0x000; private int mCurState = MIDDLE;// 当前显示的view public int MENU_border_Width = 100; private Scroller mScroller; private RelativeLayout leftLayout, rightLayout, childLayout; private Context context; private boolean fling; private boolean mIsBeingDragged = false; private int mTouchSlop; /** * Position of the last motion event. */ private float mLastMotionX, mLastMotionY; /** * ID of the active pointer. This is used to retain consistency during * drags/flings if multiple pointers are used. */ private int mActivePointerId = INVALID_POINTER; /** * Sentinel value for no current active pointer. Used by * {@link #mActivePointerId}. */ private static final int INVALID_POINTER = -1; int menuWidth = 0; int moveWidth = 0; public HomeCenterLayout(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public HomeCenterLayout(Context context) { super(context); initView(context); } public Scroller getScroller() { return mScroller; } public void initView(Context context) { MENU_border_Width = DensityUtils.dp2px(context, 100); this.context = context; this.menuWidth = MENU_border_Width; this.mScroller = new Scroller(context, AnimationUtils.loadInterpolator( context, android.R.anim.overshoot_interpolator)); final ViewConfiguration configuration = ViewConfiguration.get(context); mTouchSlop = configuration.getScaledTouchSlop(); mCurState = MIDDLE; } public void addChildView(View child) { this.childLayout.addView(child); } /** * 获取屏幕宽度 * * @param context * @return */ private int getViewWidthInPix(Context context) { int viewWidthInPix = -1; if (viewWidthInPix == -1) { WindowManager manager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); viewWidthInPix = manager.getDefaultDisplay().getWidth(); } return viewWidthInPix; } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.layout(child.getLeft() + moveWidth, child.getTop(), child.getRight() + moveWidth, child.getBottom()); } } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), 0); postInvalidate(); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub // Log.i(TAG, "onInterceptTouchEvent------>" + ev.getAction()); final int action = ev.getAction(); if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) { return true;// 拦截不传递给child view } switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { final float x = ev.getX(); final float y = ev.getY(); if (!inChild((int) x, (int) y)) { mIsBeingDragged = false; break; // 超出边界,return false传递给子view处理 } /* * Remember location of down touch. ACTION_DOWN always refers to * pointer index 0. */ mLastMotionX = x; mLastMotionY = y; mActivePointerId = ev.getPointerId(0); /* * If being flinged and user touches the screen, initiate drag; * otherwise don't. mScroller.isFinished should be false when being * flinged. */ mIsBeingDragged = !mScroller.isFinished(); break; } case MotionEvent.ACTION_MOVE: { /* * mIsBeingDragged == false, otherwise the shortcut would have * caught it. Check whether the user has moved far enough from his * original down touch. */ /* * Locally do absolute value. mLastMotionY is set to the y value of * the down event. */ final int activePointerId = mActivePointerId; if (activePointerId == INVALID_POINTER) { // If we don't have a valid id, the touch down wasn't on // content. break; } final int pointerIndex = ev.findPointerIndex(activePointerId); final float x = ev.getX(pointerIndex); final float y = ev.getY(pointerIndex); final int xDiff = (int) Math.abs(x - mLastMotionX); final int yDiff = (int) Math.abs(y - mLastMotionY); if (xDiff > mTouchSlop && yDiff < xDiff) { mIsBeingDragged = true; } break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: mIsBeingDragged = false; mActivePointerId = INVALID_POINTER; scrollToScreen(); break; } return mIsBeingDragged; } @Override public boolean onTouchEvent(MotionEvent event) { // Log.i(TAG, "onTouchEvent ---->>>>>" + event.getAction()); if (event.getAction() == MotionEvent.ACTION_DOWN && !inChild((int) event.getX(), (int) event.getY())) { // Don't handle edge touches immediately -- they may actually belong // to one of our // descendants. return false; } switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: return true; // 本VIEW消化掉 case MotionEvent.ACTION_MOVE: final int activePointerIndex = event .findPointerIndex(mActivePointerId); final float x = event.getX(activePointerIndex); final float y = event.getY(activePointerIndex); final int distanceX = (int) /* Math.abs */-(x - mLastMotionX); // 在滑动过程中,就需要显示新的brotherView,不然显示的还是之前的brotherView,最后松开手时会突然变称新brotherView,影响体验 if (distanceX < 0 && getScrollX() < 0 && leftLayout != null) { setBrotherVisibility(LEFT); } else if (distanceX > 0 && getScrollX() > 0 && rightLayout != null) { setBrotherVisibility(RIGHT); } else { setBrotherVisibility(MIDDLE); } scrollBy((int) distanceX, 0); mLastMotionX = x; mLastMotionY = y; break; case MotionEvent.ACTION_UP: mIsBeingDragged = false; mActivePointerId = INVALID_POINTER; scrollToScreen(); break; default: return super.onTouchEvent(event); } return mIsBeingDragged; } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { // TODO Auto-generated method stub super.onScrollChanged(l, t, oldl, oldt); } private void scrollToScreen() { int scrollDistance = 0; if (Math.abs(getScrollX()) > getWidth() / 2) scrollDistance = (getScrollX() > 0) ? getWidth() - menuWidth - getScrollX() : -(getWidth() - menuWidth - Math .abs(getScrollX())); else scrollDistance = -getScrollX(); int distance = scrollDistance + getScrollX(); Log.i(TAG, " distance = " + distance); if (distance > 0) { mCurState = RIGHT; } else if (distance < 0) { mCurState = LEFT; } else { mCurState = MIDDLE; } mScroller.startScroll(getScrollX(), 0, scrollDistance, 0, Math.abs(scrollDistance) * 2); invalidate(); } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (Math.abs(velocityX) > ViewConfiguration.get(context) .getScaledMinimumFlingVelocity()) { fling = true; scrollToScreen(); } return fling; } private boolean inChild(int x, int y) { if (getChildCount() > 0) { final int scrollX = mScroller.getCurrX(); final View child = getChildAt(0); return !(scrollX + x < 0 || scrollX + x > getWidth() || y < 0 || y > getHeight()); } return false; } /** * 设置当前显示的view * * @param whichpg */ public void setPage(int whichpg) { int targetX = 0, moveDistance = 0; if (whichpg == LEFT) { targetX = -(getViewWidthInPix(context) - menuWidth); mCurState = LEFT; } else if (whichpg == RIGHT) { targetX = getViewWidthInPix(context) - menuWidth; mCurState = RIGHT; } else { mCurState = MIDDLE; } setBrotherVisibility(whichpg); moveDistance = targetX - getScrollX(); mScroller.startScroll(getScrollX(), 0, moveDistance, 0, Math.abs(moveDistance) * 2); invalidate(); } /** * 返回当前显示的view * * @return */ public int getPage() { return mCurState; } /** * 设置BrotherView * * @param left * @param right */ public void setBrotherLayout(RelativeLayout left, RelativeLayout right) { this.leftLayout = left; this.rightLayout = right; } /** * 根据当前状态显示或隐藏view * * @param state */ private void setBrotherVisibility(int state) { switch (state) { case LEFT: rightLayout.setVisibility(View.GONE); leftLayout.setVisibility(View.VISIBLE); break; case RIGHT: rightLayout.setVisibility(View.VISIBLE); leftLayout.setVisibility(View.GONE); break; case MIDDLE: break; default: break; } } }
xml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <FrameLayout android:layout_width="fill_parent" android:layout_height="fill_parent" > <RelativeLayout android:id="@+id/homeLeft" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/friend_list_bg_repeat" > <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="hhhhh" android:gravity="center" android:textSize="18sp" android:textColor="#fff"/> </RelativeLayout> <RelativeLayout android:id="@+id/homeRight" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginLeft="30dp" > <ImageView android:id="@+id/iv1" android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" android:scaleType="center" android:src="@drawable/bg" /> <ImageView android:id="@+id/iv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/bottom" /> </RelativeLayout> <com.way.view.HomeCenterLayout android:id="@+id/homeCenter" android:layout_width="fill_parent" android:layout_height="fill_parent" > <!-- 特别注意: HomeCenterLayout标签下面是不能放背景的,否则你看看效果--> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/darker_gray" > <include layout="@layout/common_title_bg" /> </LinearLayout> </com.way.view.HomeCenterLayout> </FrameLayout> </RelativeLayout>