下面列出了android.view.GestureDetector.SimpleOnGestureListener#androidx.customview.widget.ViewDragHelper 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Method for increasing a Navigation Drawer's edge size.
*/
public static void increaseNavigationDrawerEdge(DrawerLayout aDrawerLayout, Context context) {
// Increase the area from which you can open the navigation drawer.
try {
Field mDragger = aDrawerLayout.getClass().getDeclaredField("mLeftDragger");
mDragger.setAccessible(true);
ViewDragHelper draggerObj = (ViewDragHelper) mDragger.get(aDrawerLayout);
Field mEdgeSize = draggerObj.getClass().getDeclaredField("mEdgeSize");
mEdgeSize.setAccessible(true);
int edgeSize = mEdgeSize.getInt(draggerObj) * 3;
mEdgeSize.setInt(draggerObj, edgeSize); //optimal value as for me, you may set any constant in dp
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
final boolean drawContent = child == mCapturedView;
int index = indexOfChild(child);
if (mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE && index == getChildCount() - 2) {
View lastChild = getChildAt(getChildCount() - 1);
canvas.save();
canvas.clipRect(0, 0, lastChild.getLeft(), getHeight());
}
boolean ret = super.drawChild(canvas, child, drawingTime);
if (mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE && index == getChildCount() - 2) {
canvas.restore();
}
if (mTabBar != null && drawContent) {
drawTabBar(canvas, child);
}
if (mScrimOpacity > 0 && drawContent
&& mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE) {
drawScrim(canvas, child);
}
return ret;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 如果符合条件直接截获事件由自己在onTouchEvent方法中处理
// 如果在释放自动滑动的过程中点击,会导致停止动画
boolean result = mViewDragHelper.shouldInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
// 这里是为了防止在滑动的过程中,突然点击,导致被点击的页面停止滑动的的情况发生
if (!result && mViewDragHelper.getViewDragState() == ViewDragHelper.STATE_DRAGGING && ev.getAction() == MotionEvent.ACTION_UP) {
if (getChildAt(2).getLeft() < range / 2) {
closeMenu();
} else {
openMenu();
}
}
return result;
}
/**
* 设置拖动范围
*
* @param px 单位像素
*/
private void setEdgeSize(int px) {
try {
Field leftDragger = getClass().getSuperclass().getDeclaredField(
"mLeftDragger");
leftDragger.setAccessible(true);
ViewDragHelper viewDragHelper = (ViewDragHelper) leftDragger
.get(this);
Field edgeSize = viewDragHelper.getClass().getDeclaredField(
"mEdgeSize");
edgeSize.setAccessible(true);
edgeSize.setInt(viewDragHelper, px);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* Method for increasing a Navigation Drawer's edge size.
*/
public static void increaseNavigationDrawerEdge(DrawerLayout aDrawerLayout, Context context) {
// Increase the area from which you can open the navigation drawer.
try {
Field mDragger = aDrawerLayout.getClass().getDeclaredField("mLeftDragger");
mDragger.setAccessible(true);
ViewDragHelper draggerObj = (ViewDragHelper) mDragger.get(aDrawerLayout);
Field mEdgeSize = draggerObj.getClass().getDeclaredField("mEdgeSize");
mEdgeSize.setAccessible(true);
int edgeSize = mEdgeSize.getInt(draggerObj) * 3;
mEdgeSize.setInt(draggerObj, edgeSize); //optimal value as for me, you may set any constant in dp
} catch (Exception e) {
e.printStackTrace();
}
}
private void init(@NonNull Context context) {
if (!isInEditMode()) {
ViewConfiguration vc = ViewConfiguration.get(context);
minFlingVelocity = (float) vc.getScaledMinimumFlingVelocity();
dragHelper = ViewDragHelper.create(this, new PullDismissLayout.ViewDragCallback(this));
}
}
public boolean onInterceptTouchEvent(MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
boolean pullingDown = false;
switch (action) {
case MotionEvent.ACTION_DOWN:
verticalTouchSlop = event.getY();
case MotionEvent.ACTION_MOVE:
final float dy = event.getY() - verticalTouchSlop;
if (dy > dragHelper.getTouchSlop()) {
pullingDown = true;
mTouchCallbacks.touchPull();
}else{
mTouchCallbacks.touchDown(event.getX(), event.getY());
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
verticalTouchSlop = 0.0f;
mTouchCallbacks.touchUp();
break;
}
if (!dragHelper.shouldInterceptTouchEvent(event) && pullingDown) {
if (dragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE &&
dragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_VERTICAL)) {
View child = getChildAt(0);
if (child != null && !listener.onShouldInterceptTouchEvent()) {
dragHelper.captureChildView(child, event.getPointerId(0));
return dragHelper.getViewDragState() == ViewDragHelper.STATE_DRAGGING;
}
}
}
return false;
}
public void onViewDragStateChanged(int state) {
if (capturedView != null && dismissed && state == ViewDragHelper.STATE_IDLE) {
pullDismissLayout.removeView(capturedView);
if (pullDismissLayout.listener != null) {
pullDismissLayout.listener.onDismissed();
}
}
}
public SwipeBackLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
mDragHelper = ViewDragHelper.create(this, new ViewDragCallback());
final float density = getResources().getDisplayMetrics().density;
final float minVelocity = MIN_FLING_VELOCITY * density;
mDragHelper.setMinVelocity(minVelocity);
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!mListener.shouldSwipeBack()) {
return super.onTouchEvent(event);
}
mDragHelper.processTouchEvent(event);
return mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE;
}
@Override
public boolean tryCaptureView(@NonNull View view, int pointerId) {
if (view.getAnimation() != null) {
return false;
}
boolean ret = mDragHelper.isEdgeTouched(ViewDragHelper.EDGE_LEFT, pointerId);
boolean directionCheck = !mDragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_VERTICAL, pointerId);
return mDragHelper.getViewDragState() != ViewDragHelper.STATE_SETTLING && (ret & directionCheck);
}
@Override
public void onViewDragStateChanged(int state) {
if (state == ViewDragHelper.STATE_IDLE) {
mCapturedView = null;
mLeft = 0;
int count = getChildCount();
if (count > 1) {
View underlying = getChildAt(count - 2);
underlying.setX(0);
}
}
mListener.onViewDragStateChanged(state, mScrollPercent);
}
@Override
protected void onFinishInflate() {
if (draggedViewId != 0) {
draggedView = findViewById(draggedViewId);
}
if (staticLeftViewId != 0) {
staticLeftView = findViewById(staticLeftViewId);
}
if (staticRightViewId != 0) {
staticRightView = findViewById(staticRightViewId);
}
if (draggedView == null) {
throw new RuntimeException("'draggedItem' must be specified");
} else if (isTogether && currentDirection == LEFT && staticRightView == null) {
throw new RuntimeException("If 'isTogether = true' 'rightItem' must be specified");
} else if (isTogether && currentDirection == RIGHT && staticLeftView == null) {
throw new RuntimeException("If 'isTogether = true' 'leftItem' must be specified");
} else if (currentDirection == LEFT && !isContinuousSwipe && staticRightView == null) {
throw new RuntimeException("Must be specified 'rightItem' or flag isContinuousSwipe = true");
} else if (currentDirection == RIGHT && !isContinuousSwipe && staticLeftView == null) {
throw new RuntimeException("Must be specified 'leftItem' or flag isContinuousSwipe = true");
} else if (currentDirection == HORIZONTAL && (staticRightView == null || staticLeftView == null)) {
throw new RuntimeException("'leftItem' and 'rightItem' must be specified");
}
dragHelper = ViewDragHelper.create(this, 1.0f, dragHelperCallback);
gestureDetector = new GestureDetectorCompat(getContext(), gestureDetectorCallBack);
setupPost();
super.onFinishInflate();
}
private void reset() {
activePointerId = ViewDragHelper.INVALID_POINTER;
if (velocityTracker != null) {
velocityTracker.recycle();
velocityTracker = null;
}
}
public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// 如果水平方向的偏移量大于竖直方向的偏移量,就消化该事件,
return Math.abs(distanceX) > Math.abs(distanceY) || super.onScroll(e1, e2, distanceX, distanceY);
}
});
// 永远要记得,该工具实现的拖拉是基于控件位置的改变来实现的
mViewDragHelper = ViewDragHelper.create(this, new DragViewCallBack());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 如果符合条件直接截获事件由自己在onTouchEvent方法中处理
// 如果在释放自动滑动的过程中点击,会导致停止动画
if (isIntercept()) {
return false;
}
boolean result = mViewDragHelper.shouldInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
// 这里是为了防止在滑动的过程中,突然点击,导致被点击的页面停止滑动的的情况发生
if (!result && mViewDragHelper.getViewDragState() == ViewDragHelper.STATE_DRAGGING && ev.getAction() == MotionEvent.ACTION_UP) {
if (mode == LEFT_MODE) {
if (content.getLeft() < range / 2) {
closeMenu();
} else {
openMenu();
}
} else {
if (content.getRight() < range / 2) {
openMenu();
} else {
closeMenu();
}
}
}
return result;
}
public MainDragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// 如果水平方向的偏移量大于竖直方向的偏移量,就消化该事件,
return Math.abs(distanceX) > Math.abs(distanceY) || super.onScroll(e1, e2, distanceX, distanceY);
}
});
// 永远要记得,该工具实现的拖拉是基于控件位置的改变来实现的
mViewDragHelper = ViewDragHelper.create(this, new DragViewCallBack());
}
private void initialize() {
mLayoutInflater = LayoutInflater.from(getContext());
mViewDragCallback = new ViewDragCallback();
mViewDragHelper = ViewDragHelper.create(this, 1.0f, mViewDragCallback);
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
this.setFocusableInTouchMode(true);
this.setClipChildren(false);
this.requestFocus();
}
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
mIsEdgeDrag = true;
if (tryCaptureView(mContentView, pointerId) && edgeFlags == ViewDragHelper.EDGE_LEFT) {
mViewDragHelper.captureChildView(mContentView, pointerId);
}
}
@Override
public boolean onLayoutChild( CoordinatorLayout parent, V child, int layoutDirection ) {
// First let the parent lay it out
if (mState != STATE_DRAGGING && mState != STATE_SETTLING) {
if (parent.getFitsSystemWindows() &&
!child.getFitsSystemWindows()) {
child.setFitsSystemWindows(true);
}
parent.onLayoutChild(child, layoutDirection);
}
// Offset the bottom sheet
mParentHeight = parent.getHeight();
mMinOffset = Math.max(0, mParentHeight - child.getHeight());
mMaxOffset = Math.max(mParentHeight - mPeekHeight, mMinOffset);
/**
* New behavior
*/
if (mState == STATE_ANCHOR_POINT) {
ViewCompat.offsetTopAndBottom(child, mAnchorPoint);
} else if (mState == STATE_EXPANDED) {
ViewCompat.offsetTopAndBottom(child, mMinOffset);
} else if (mHideable && mState == STATE_HIDDEN) {
ViewCompat.offsetTopAndBottom(child, mParentHeight);
} else if (mState == STATE_COLLAPSED) {
ViewCompat.offsetTopAndBottom(child, mMaxOffset);
}
if ( mViewDragHelper == null ) {
mViewDragHelper = ViewDragHelper.create( parent, mDragCallback );
}
mViewRef = new WeakReference<>(child);
mNestedScrollingChildRef = new WeakReference<>( findScrollingChild( child ) );
return true;
}
@Override
public boolean onTouchEvent( CoordinatorLayout parent, V child, MotionEvent event ) {
if ( ! child.isShown() ) {
return false;
}
int action = event.getActionMasked();
if ( mState == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN ) {
return true;
}
// Detect scroll direction for ignoring collapsible
if(mLastStableState == STATE_ANCHOR_POINT && action==MotionEvent.ACTION_MOVE) {
if(event.getY()>mInitialY && !mCollapsible) {
reset();
return false;
}
}
if (mViewDragHelper == null) {
mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
}
mViewDragHelper.processTouchEvent(event);
if ( action == MotionEvent.ACTION_DOWN ) {
reset();
}
// The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it
// to capture the bottom sheet in case it is not captured and the touch slop is passed.
if ( action == MotionEvent.ACTION_MOVE && ! mIgnoreEvents ) {
if ( Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop() ) {
mViewDragHelper.captureChildView( child, event.getPointerId(event.getActionIndex()) );
}
}
return ! mIgnoreEvents;
}
public SwipeBackLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWillNotDraw(false);
mDragHelper = ViewDragHelper.create(this, 1f, new DragHelperCallback());
mTouchSlop = mDragHelper.getTouchSlop();
setSwipeBackListener(defaultSwipeBackListener);
init(context, attrs);
}
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
if (state == ViewDragHelper.STATE_IDLE) {
if (mSwipeBackListener != null) {
if (swipeBackFraction == 0) {
mSwipeBackListener.onViewSwipeFinished(mDragContentView, false);
} else if (swipeBackFraction == 1) {
mSwipeBackListener.onViewSwipeFinished(mDragContentView, true);
}
}
}
}
public NowPlayingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDragHelper = ViewDragHelper.create(this, 1f, new BottomDragCallbackHelper());
mPlaybackServiceState = PlaybackService.PLAYSTATE.STOPPED;
mLastTrack = new TrackModel();
mServiceConnection = new PlaybackServiceConnection(getContext().getApplicationContext());
mServiceConnection.setNotifier(new ServiceConnectionListener());
}
/**
* Called when a layout is requested from the graphics system.
*
* @param changed If the layout is changed (size, ...)
* @param l Left position
* @param t Top position
* @param r Right position
* @param b Bottom position
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// Calculate the maximal range that the view is allowed to be dragged
mDragRange = (getMeasuredHeight() - mHeaderView.getMeasuredHeight());
// New temporary top position, to fix the view at top or bottom later if state is idle.
int newTop = mTopPosition;
// fix height at top or bottom if state idle
if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) {
newTop = (int) (mDragRange * mDragOffset);
}
// Request the upper part of the NowPlayingView (header)
mHeaderView.layout(
0,
newTop,
r,
newTop + mHeaderView.getMeasuredHeight());
// Request the lower part of the NowPlayingView (main part)
mMainView.layout(
0,
newTop + mHeaderView.getMeasuredHeight(),
r,
newTop + b);
}
private void reset() {
activePointerId = ViewDragHelper.INVALID_POINTER;
if (velocityTracker != null) {
velocityTracker.recycle();
velocityTracker = null;
}
}
private void ensureViewDragHelper(ViewGroup parent) {
if (viewDragHelper == null) {
viewDragHelper =
sensitivitySet
? ViewDragHelper.create(parent, sensitivity, dragCallback)
: ViewDragHelper.create(parent, dragCallback);
}
}
private void reset() {
activePointerId = ViewDragHelper.INVALID_POINTER;
if (velocityTracker != null) {
velocityTracker.recycle();
velocityTracker = null;
}
}
public QuickAttachmentDrawer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
dragHelper = ViewDragHelper.create(this, 1.f, new ViewDragHelperCallback());
initializeView();
updateHalfExpandedAnchorPoint();
onConfigurationChanged();
}
@Override
public void onViewDragStateChanged(int state) {
if (dragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) {
setDrawerState(drawerState);
slideOffset = getTargetSlideOffset();
requestLayout();
}
}