Android ViewDragHelper实现京东、淘宝拖拽详情功能的实现

 更新时间:2018年04月21日 14:37:02   作者:人言落日是天涯  
这篇文章主要介绍了Android ViewDragHelper实现京东、淘宝拖拽详情,实现这种效果大概分为三种方式,具体哪三种方式大家通过本文了解下吧

先上效果图,如果大家感觉不错,请参考实例代码,效果图如下所述:

要实现这个效果有三种方式:

① 手势

② 动画
③ ViewDragHelper

这里我使用的是ViewDragHelper类.

public class ViewDragLayout extends ViewGroup {
  //垂直方向的滑动速度
  private static final int VEL_THRESHOLD = 300;
  //垂直方向的滑动距离
  private static final int DISTANCE_THRESHOLD = 300;
  //上面可见的View
  private View mTopView;
  //下面详情View
  private View mBottomView;
  //ViewDragHelper实例
  private ViewDragHelper mViewDragHelper;
  private GestureDetectorCompat mGestureDetectorCompat;
  private int mFirstHeight;
  public ViewDragLayout(Context context) {
    super(context);
    init();
  }
  public ViewDragLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
  }
  public ViewDragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
  }
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  public ViewDragLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    init();
  }
  private void init() {
    mViewDragHelper = ViewDragHelper.create(this, 1.0f, new DragHelperCallback());
    mGestureDetectorCompat = new GestureDetectorCompat(getContext(), new YScrollDetector());
  }
  @Override
  protected void onFinishInflate() {
    super.onFinishInflate();
    mTopView = getChildAt(0);
    mBottomView = getChildAt(1); 
  }
  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if (mTopView.getTop() == 0) {
      mTopView.layout(l, 0, r, b-t );
      mBottomView.layout(l, 0, r, b-t );
      mFirstHeight = mTopView.getMeasuredHeight();
      mBottomView.offsetTopAndBottom(mFirstHeight);
    }else{   
      mTopView.layout(l, mTopView.getTop(), r, mTopView.getBottom());
      mBottomView.layout(l, mBottomView.getTop(), r, mBottomView.getBottom());
    }
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    measureChildren(widthMeasureSpec,heightMeasureSpec);
    int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
    int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
    setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0),
        resolveSizeAndState(maxHeight, heightMeasureSpec, 0));
  }
  private class DragHelperCallback extends ViewDragHelper.Callback {
    @Override
    public boolean tryCaptureView(View child, int pointerId) {
      return true;
    }
    /**
     * @param child
     * @param top
     * @param dy
     * @return
     */
    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
      int finalTop=top;
      if (child == mTopView) {
        if (top > 0) {
          finalTop=0;
        }
      }else if(child==mBottomView){       
        if(top<0){
          finalTop=0;
        }
      }
      return finalTop;
    }
    @Override
    public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
      if (changedView == mTopView) {
        mBottomView.offsetTopAndBottom(dy);
      }else if (changedView==mBottomView){
        mTopView.offsetTopAndBottom(dy);
      }
      ViewCompat.postInvalidateOnAnimation(ViewDragLayout.this);
    }
    /**
     *
     * @param releasedChild
     * @param xvel 水平方向的速度(向右为正)
     * @param yvel 竖直方向的速度(向下为正)
     */
    @Override
    public void onViewReleased(View releasedChild, float xvel, float yvel) {
      animTopOrBottom(releasedChild, yvel);
    }
  }
  //动画实现滚动
  private void animTopOrBottom(View releasedChild, float yvel) {
    int finalTop=0;
    if (releasedChild == mTopView) {
      if (yvel < -VEL_THRESHOLD || (releasedChild.getTop() < -DISTANCE_THRESHOLD)) {
        finalTop=-mFirstHeight;
      }
    } else if (releasedChild == mBottomView) {
      if (yvel > VEL_THRESHOLD || (releasedChild.getTop() > DISTANCE_THRESHOLD)) {
        finalTop=mFirstHeight;
      }
    }
    if (mViewDragHelper.smoothSlideViewTo(releasedChild, 0, finalTop)) {
      ViewCompat.postInvalidateOnAnimation(this);
    }
  }
  @Override
  public void computeScroll() {
    if (mViewDragHelper.continueSettling(true)) {
      ViewCompat.postInvalidateOnAnimation(this);
    }
  }
  //是否拦截手势操作
  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (mTopView.getTop() < 0 && mTopView.getBottom() > 0) {
      return false;
    }
    boolean isCanTouch = mGestureDetectorCompat.onTouchEvent(ev);
    boolean shouldIntercept = mViewDragHelper.shouldInterceptTouchEvent(ev);
    if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
      mViewDragHelper.processTouchEvent(ev);
    }
    return isCanTouch&&shouldIntercept;
  }
  //将touch事件交给ViewDragHelper处理
  @Override
  public boolean onTouchEvent(MotionEvent event) {
     mViewDragHelper.processTouchEvent(event);
    return true;
  }
  //垂直方向上才滚动
  private class YScrollDetector extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
      return Math.abs(distanceY) > Math.abs(distanceX);
    }
  }
}

使用ViewDragLayout

<gesture.com.cn.widget.ViewDragLayout
    android:id="@+id/view_drag_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <FrameLayout
      android:id="@+id/top_fragment_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      />
    <FrameLayout
      android:id="@+id/bottom_fragment_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>
</gesture.com.cn.widget.ViewDragLayout>

bottom_fragment_view中使用了ScrollView,但是原生是不行的,所以这里我又将ScrollView重写了一下

这里主要是处理dispatchTouchEvent(MotionEvent ev)方法,判断将touch事件交给自己处理还是交给父View处理

public class CustomScrollView extends ScrollView { 
  //滚动临界值
  private int mTouchSlop;
  //获取初始X坐标
  private float mRawX;
  //获取初始Y坐标
  private float mRawY;
  //是否向上滑动
  private boolean mCanScrollUp;
  //是否向下滑动
  private boolean mCanScrollDown;
  public CustomScrollView(Context context) {
    super(context);
    init();
  }
  public CustomScrollView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init();
  }
  public CustomScrollView(Context context, @Nullable AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
  }
  private void init() {
    ViewConfiguration configuration = ViewConfiguration.get(getContext());
    mTouchSlop = configuration.getScaledTouchSlop();
  }
  @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    switch (ev.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:
        mRawX = ev.getRawX();
        mRawY = ev.getRawY();
        mCanScrollUp = canScrollingUp();
        mCanScrollDown = canScrollingDown();
        //表示子View要自己消费这次事件,告诉父View不拦截这次的事件。
        getParent().requestDisallowInterceptTouchEvent(true);
        break;
      case MotionEvent.ACTION_MOVE:
        float xDis = Math.abs(mRawX - ev.getRawX());
        float yDis = Math.abs(mRawY - ev.getRawY());
        if (yDis > xDis && yDis > mTouchSlop) {
          if (mRawY < ev.getRawY() && mCanScrollUp) {
            //表示子View不消费这次事件,告诉父View拦截这次的事件。
            getParent().requestDisallowInterceptTouchEvent(false);
            return false;
          }
          if (mRawY > ev.getRawY() && mCanScrollDown) {
            //表示子View不消费这次事件,告诉父View拦截这次的事件。
            getParent().requestDisallowInterceptTouchEvent(false);
            return false;
          }
        }
        break;
    }
    return super.dispatchTouchEvent(ev);
  }
  /**
   * 手指向下滑动(内容向上滑动)
   * @return
   */
  private boolean canScrollingUp() {
    if (ViewCompat.canScrollVertically(this, -1)) {
      return false;
    } else {
      return true;
    }
  }
  /**
   * 手指向上滑动(内容向下滑动)
   * @return
   */
  private boolean canScrollingDown() {
    if (ViewCompat.canScrollVertically(this, 1)) {
      return false;
    } else {
      return true;
    }
  }
}

好了,具体拖拽代码就是这些了,界面我用的两个Fragment,相信大家也看出来了。里面大家换成自己的业务UI就可以了。

以上所述是小编给大家介绍的Android ViewDragHelper实现京东、淘宝拖拽详情功能的实现,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

相关文章

  • Android SeekBar实现滑动条效果

    Android SeekBar实现滑动条效果

    这篇文章主要为大家详细介绍了Android SeekBar实现滑动条效果,可以改变并显示当前进度的拖动,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • 智能指针与弱引用详解

    智能指针与弱引用详解

    智能指针有很多实现方式,android 中的sp 句柄类实际上就是google 实现的一种强引用的智能指针。我没有仔细看android sp 的实现方式,但其基本原理是固定的,现在我们从一个相对简单的例子来看智能指针的实现
    2013-09-09
  • Android获取其他包的Context实例代码

    Android获取其他包的Context实例代码

    这篇文章主要介绍了Android获取其他包的Context实例代码,有需要的朋友可以参考一下
    2014-01-01
  • AndroidQ(10)分区存储完美适配方法

    AndroidQ(10)分区存储完美适配方法

    这篇文章主要介绍了AndroidQ(10)分区存储完美适配方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • android显示TextView文字的倒影效果实现代码

    android显示TextView文字的倒影效果实现代码

    这篇文章主要介绍了android显示TextView文字的倒影效果实现代码,需要的朋友可以参考下
    2014-02-02
  • Flutter Reusable Lottie Animations技巧

    Flutter Reusable Lottie Animations技巧

    这篇文章主要为大家介绍了Flutter Reusable Lottie Animations技巧,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • 基于Android Flutter编写贪吃蛇游戏

    基于Android Flutter编写贪吃蛇游戏

    贪吃蛇是一款足够经典的游戏。本文将利用Android中的Flutter编写这一经典的小游戏,文中的示例代码讲解详细,感兴趣的可以了解一下
    2022-03-03
  • Android开发实现加载网络图片并下载至本地SdCard的方法

    Android开发实现加载网络图片并下载至本地SdCard的方法

    这篇文章主要介绍了Android开发实现加载网络图片并下载至本地SdCard的方法,涉及Android图片文件的读取、保存及权限相关操作技巧,需要的朋友可以参考下
    2018-01-01
  • React Native开发中自动打包脚本的实例代码

    React Native开发中自动打包脚本的实例代码

    这篇文章主要介绍了React Native开发中自动打包脚本的实例代码,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-09-09
  • android 有阻尼下拉刷新列表的实现方法

    android 有阻尼下拉刷新列表的实现方法

    下面小编就为大家分享一篇android 有阻尼下拉刷新列表的实现方法,具有很好的参考价值,希望对大家有所帮助,一起跟随小编过来看看吧
    2018-01-01

最新评论