Java tutorial
/* * Copyright (c) 2016. ouyangzn <email : ouyangzn@163.com> * 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.ouyangzn.view; import android.content.Context; import android.content.res.TypedArray; import android.support.v4.view.MotionEventCompat; import android.support.v4.view.ViewCompat; import android.support.v4.widget.ViewDragHelper; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ScrollView; import com.ouyangzn.R; import com.ouyangzn.utils.Log; /** * Created by ouyangzn on 2016/10/12.<br/> * Description?view??/layout */ public class DragLayout extends FrameLayout { public final static int DIRECTION_TOP = 0; public final static int DIRECTION_BOTTOM = 1; public final static int DIRECTION_LEFE = 2; public final static int DIRECTION_RIGHT = 3; private final static String TAG = DragLayout.class.getSimpleName(); private Context mContext; private int mLayoutWidth; private int mLayoutHeight; private ViewDragHelper mDragHelper; /** ?? */ private int mRemainDistance; /** ??? */ private int mThresholdDistance; /** ??view */ //private int mDraggedViewId; private View mDraggedView; /** ??? */ private int mDirection; // X?Y?? private float mDownX; private float mDownY; public DragLayout(Context context) { this(context, null); } public DragLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context, AttributeSet attrs) { mContext = context; mDragHelper = ViewDragHelper.create(this, new DragLayout.ViewDragCallback()); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DragLayout); mRemainDistance = ta.getDimensionPixelOffset(R.styleable.DragLayout_remain_distance, 0); mThresholdDistance = ta.getDimensionPixelOffset(R.styleable.DragLayout_threshold_distance, 0); //mDraggedViewId = ta.getResourceId(R.styleable.DragLayout_dragged_view_id, View.NO_ID); mDirection = ta.getInt(R.styleable.DragLayout_direction, DIRECTION_TOP); ta.recycle(); } @Override protected void onFinishInflate() { super.onFinishInflate(); //if (mDraggedViewId != View.NO_ID) { // mDraggedView = findViewById(mDraggedViewId); //} else { // mDraggedView = getChildAt(0); //} if (getChildCount() != 1) { throw new UnsupportedOperationException("DragLayout should has only one direct child"); } mDraggedView = getChildAt(0); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mLayoutWidth = w; mLayoutHeight = h; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean helpResult = mDragHelper.shouldInterceptTouchEvent(ev); switch (MotionEventCompat.getActionMasked(ev)) { case MotionEvent.ACTION_DOWN: mDownX = ev.getX(); mDownY = ev.getY(); break; } if (isHorizontalScrollView(mDraggedView)) { boolean intercept = false; switch (MotionEventCompat.getActionMasked(ev)) { case MotionEvent.ACTION_MOVE: if (mDirection == DIRECTION_TOP || mDirection == DIRECTION_BOTTOM) { // ?--->support-v4DrawerLayout?? intercept = mDragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_VERTICAL, ev.getPointerId(0)); } else { // ? if (ev.getX() - mDownX > 0) { // view????, if (mDirection == DIRECTION_LEFE && mDraggedView.getRight() == mRemainDistance) { intercept = true; } else if (mDirection == DIRECTION_RIGHT) { // view????view?? intercept = !ViewCompat.canScrollHorizontally(mDraggedView, -1); } } // else { // view?????, if (mDirection == DIRECTION_RIGHT && (mLayoutWidth - mDraggedView.getLeft()) == mRemainDistance) { intercept = true; } else if (mDirection == DIRECTION_LEFE) { // view???view?? intercept = !ViewCompat.canScrollHorizontally(mDraggedView, 1); } } } // ???view if (intercept) mDragHelper.captureChildView(mDraggedView, ev.getPointerId(0)); break; } return helpResult || intercept; } if (isVerticalScrollView(mDraggedView)) { boolean intercept = false; switch (MotionEventCompat.getActionMasked(ev)) { case MotionEvent.ACTION_MOVE: if (mDirection == DIRECTION_LEFE || mDirection == DIRECTION_RIGHT) { // ?--->support-v4DrawerLayout?? intercept = mDragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_HORIZONTAL, ev.getPointerId(0)); } else { // if (ev.getY() - mDownY > 0) { if (mDirection == DIRECTION_TOP && mDraggedView.getBottom() == mRemainDistance) { intercept = true; } else if (mDirection == DIRECTION_BOTTOM) { intercept = !ViewCompat.canScrollVertically(mDraggedView, -1); } } // else { // view???? if (mDirection == DIRECTION_BOTTOM && (mLayoutHeight - mDraggedView.getBottom()) == mRemainDistance) { intercept = true; } else if (mDirection == DIRECTION_TOP) { // view???view?? intercept = !ViewCompat.canScrollVertically(mDraggedView, 1); } } } break; } Log.d(TAG, "----------onInterceptTouchEvent.return = " + (helpResult || intercept)); // ???view if (intercept) mDragHelper.captureChildView(mDraggedView, ev.getPointerId(0)); return helpResult || intercept; } return helpResult; } private boolean isHorizontalScrollView(View view) { if (view instanceof RecyclerView) { RecyclerView recyclerView = (RecyclerView) view; RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) { LinearLayoutManager manager = (LinearLayoutManager) layoutManager; if (manager.getOrientation() == LinearLayoutManager.HORIZONTAL) { return true; } } } return view instanceof HorizontalScrollView || ViewCompat.canScrollHorizontally(view, -1) || ViewCompat.canScrollHorizontally(view, 1); } private boolean isVerticalScrollView(View view) { if (view instanceof RecyclerView) { RecyclerView recyclerView = (RecyclerView) view; RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) { LinearLayoutManager manager = (LinearLayoutManager) layoutManager; if (manager.getOrientation() == LinearLayoutManager.VERTICAL) { return true; } } } return view instanceof ScrollView || ViewCompat.canScrollVertically(view, -1) || ViewCompat.canScrollVertically(view, 1); } @Override public boolean onTouchEvent(MotionEvent event) { mDragHelper.processTouchEvent(event); return true; } @Override public void computeScroll() { if (mDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } class ViewDragCallback extends ViewDragHelper.Callback { /** ?null???? */ private Boolean mIsDragValid; private int mDragViewLeft; private int mDragViewRight; private int mDragViewTop; private int mDragViewBottom; //private int mDragLayoutWidth; //private int mDragLayoutHeight; @Override public boolean tryCaptureView(View child, int pointerId) { Log.d(TAG, "-----------tryCaptureView.pointerId = " + pointerId + " ,child = " + child); return child == mDraggedView; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { if (changedView != mDraggedView) { mIsDragValid = null; return; } //Log.d(TAG, "-----------onViewPositionChanged.left = " + left + " ,top = " + top + " ,dx = " + dx + " ,dy = " + dy); // ? if (mThresholdDistance == 0) { if (mDirection == DIRECTION_TOP || mDirection == DIRECTION_BOTTOM) { mIsDragValid = (Math.abs(top - mDragViewTop) / (float) mDraggedView.getHeight()) > 0.5; } else if (mDirection == DIRECTION_LEFE || mDirection == DIRECTION_RIGHT) { mIsDragValid = (Math.abs(left - mDragViewLeft) / (float) mDraggedView.getWidth()) > 0.5; } } else { if (mDirection == DIRECTION_TOP || mDirection == DIRECTION_BOTTOM) { mIsDragValid = Math.abs(top - mDragViewTop) > mThresholdDistance; } else if (mDirection == DIRECTION_LEFE || mDirection == DIRECTION_RIGHT) { mIsDragValid = Math.abs(left - mDragViewLeft) > mThresholdDistance; } } } @Override public void onViewCaptured(View capturedChild, int activePointerId) { super.onViewCaptured(capturedChild, activePointerId); // ?view?? mDragViewLeft = capturedChild.getLeft(); mDragViewRight = capturedChild.getRight(); mDragViewTop = capturedChild.getTop(); mDragViewBottom = capturedChild.getBottom(); //mDragLayoutWidth = DragLayout.this.getWidth(); //mDragLayoutHeight = DragLayout.this.getHeight(); Log.d(TAG, "-----------onViewCaptured.mDragViewLeft = " + mDragViewLeft + " ,mDragViewRight = " + mDragViewRight + " ,mDragViewTop = " + mDragViewTop + " ,mDragViewBottom = " + mDragViewBottom); } @Override public void onViewDragStateChanged(int state) { Log.d(TAG, "-----------onViewDragStateChanged----------------"); super.onViewDragStateChanged(state); } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { //if (releasedChild != mDraggedView) return; if (mIsDragValid == null) { return; } Log.d(TAG, "-----------onViewReleased.xvel = " + xvel + " ,yvel = " + yvel); // todo ???? if (mIsDragValid) { Log.d(TAG, "-------------------"); if (mDirection == DIRECTION_TOP) { if (mDragViewTop < 0) { // ??? mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, 0); } else { mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, mRemainDistance - releasedChild.getHeight()); } } else if (mDirection == DIRECTION_BOTTOM) { if (mDragViewBottom > mLayoutHeight) { mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, 0); } else { mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, mDragViewBottom - mRemainDistance); } } else if (mDirection == DIRECTION_LEFE) { if (mDragViewLeft < 0) { mDragHelper.smoothSlideViewTo(releasedChild, 0, mDragViewTop); } else { mDragHelper.smoothSlideViewTo(releasedChild, -releasedChild.getWidth() + mRemainDistance, mDragViewTop); } } else if (mDirection == DIRECTION_RIGHT) { if (mDragViewRight > mLayoutWidth) { mDragHelper.smoothSlideViewTo(releasedChild, 0, mDragViewTop); } else { mDragHelper.smoothSlideViewTo(releasedChild, releasedChild.getWidth() - mRemainDistance, mDragViewTop); } } } else { // ? Log.d(TAG, "-------------------"); if (mDirection == DIRECTION_TOP) { if (mDragViewTop < 0) { // ??? // mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, mDragViewTop); // ?mDragViewTop????? mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, mRemainDistance - releasedChild.getHeight()); } else { mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, 0); } } else if (mDirection == DIRECTION_BOTTOM) { if (mDragViewBottom > mLayoutHeight) { mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, mDragViewTop); } else { mDragHelper.smoothSlideViewTo(releasedChild, mDragViewLeft, 0); } } else if (mDirection == DIRECTION_LEFE) { if (mDragViewLeft < 0) { mDragHelper.smoothSlideViewTo(releasedChild, -releasedChild.getWidth() + mRemainDistance, mDragViewTop); } else { mDragHelper.smoothSlideViewTo(releasedChild, 0, mDragViewTop); } } else if (mDirection == DIRECTION_RIGHT) { if (mDragViewRight > mLayoutWidth) { mDragHelper.smoothSlideViewTo(releasedChild, releasedChild.getWidth() - mRemainDistance, mDragViewTop); } else { mDragHelper.smoothSlideViewTo(releasedChild, 0, mDragViewTop); } } } //ScrollerstartScroll ViewCompat.postInvalidateOnAnimation(DragLayout.this); } @Override public void onEdgeTouched(int edgeFlags, int pointerId) { Log.d(TAG, "-----------onEdgeTouched----------------"); super.onEdgeTouched(edgeFlags, pointerId); } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (child != mDraggedView || mDirection == DIRECTION_TOP || mDirection == DIRECTION_BOTTOM) { return mDragViewLeft; } //Log.d(TAG, "---------clampViewPositionHorizontal.left = " + left + " ,dx = " + dx); if (mDirection == DIRECTION_LEFE) { if (left > 0) left = 0; if (mDragViewLeft < 0 && left < mDragViewLeft) { left = mDragViewLeft; } } else { if (left < 0) left = 0; if (mDragViewRight > mLayoutWidth + mDraggedView.getWidth()) { left = mDragViewLeft; } } return left; } @Override public int clampViewPositionVertical(View child, int top, int dy) { if (child != mDraggedView || mDirection == DIRECTION_LEFE || mDirection == DIRECTION_RIGHT) { return mDragViewTop; } //Log.d(TAG, "---------clampViewPositionVertical.top = " + top + " ,dy = " + dy); if (mDirection == DIRECTION_TOP) { // ?? if (top > 0) { top = 0; } // view???? if (mDragViewTop < 0 && top < mDragViewTop) { top = mDragViewTop; } } else { // ???? //if (mScreenHeight - mDragViewTop == mDraggedView.getHeight()) { if (top < 0) { top = 0; } if (mDragViewTop >= mLayoutHeight) { top = mDragViewTop; } } return top; } } }