ViewDragHelper实例学习笔记

github上的一个开源项目:https://github.com/BlueMor/DragLayout,

效果图:

侧滑效果的实现主要用的是ViewDragHelper,实现了对TouchEvent中的action处理进行了封装,

使用者不必操心在侧滑的过程中如何处理TouchEvent中的ACTION_DOWN、ACTION_MOVE和ACTION_UP事件,

而只需实现回调接口ViewDragHelper.Callback()中的方法就ok了,在此项目中实现的接口:

private ViewDragHelper.Callback dragHelperCallback = new ViewDragHelper.Callback() {

   @Override
        public boolean tryCaptureView(View child, int pointerId) {//当前view是否允许拖动
            return true;
        }
    @Override
        public int getViewHorizontalDragRange(View child) {<span style="font-family: Arial, Helvetica, sans-serif;">//横向拖动的最大距离</span>
            return width; 
        }
  @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);//ACTION_UP事件后调用其方法
            if (xvel > 0) {
                open();
            } else if (xvel < 0) {
                close();
            } else if (releasedChild == vg_main && mainLeft > range * 0.3) {
                open();
            } else if (releasedChild == vg_left && mainLeft > range * 0.7) {
                open();
            } else {
                close();
            }
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {//返回横向坐标左右边界值
            if (mainLeft + dx < 0) { 
                return 0 ;//0
            } else if (mainLeft + dx > range) {
                return range;//
            } else {
                return left;
            }
        }

    @Override
        public void onViewPositionChanged(View changedView, int left, int top,
                int dx, int dy) {//view在拖动过程坐标发生变化时会调用此方法,包括两个时间段:手动拖动和自动滚动
        	
            if (changedView == vg_main) {
            	Log.d("draglayout","changedview is vg main");
                mainLeft = left;
            } else {
                mainLeft = mainLeft + left;
                Log.d("draglayout","changedview is vg left");
            }
            if (mainLeft < 0) {
                mainLeft = 0;
            } else if (mainLeft > range) {
                mainLeft = range;
            }


            if (isShowShadow) {
                iv_shadow.layout(mainLeft, 0, mainLeft + width, height);
            }
            if (changedView == vg_left) {
                vg_left.layout(0, 0, width, height);
                vg_main.layout(mainLeft, 0, mainLeft + width, height);
            }


            dispatchDragEvent(mainLeft);
        }
    };
在此接口中基本没有对touchevent事件的处理,那这些方法是怎么与touchevent时间联系起来的?

在touchevent事件处理中DragLayout是直接调用了ViewDragHelper中的processTouchEvent方法:

  public boolean onTouchEvent(MotionEvent e) {
        try {
            dragHelper.processTouchEvent(e);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }

在processTouchEvent中对ACTION_DOWN、ACTION_MOVE和ACTION_UP事件进行了处理:

1.在ACTION_DOWN中调用回调接口中的tryCaptureView方法,看当前touch的view是否允许拖动

    在此项目中的是直接return true,两个view都是允许拖动的

2.在ACTION_MOVE中,view的坐标发生改变,调用回调接口中的onViewPositionChanged方法,

  根据坐标信息对view进行layout,通过ViewHelper这个类中的setScaleX、setScaleY方法,实现在

  拖动的过程中view在XY坐标上进行相应比例的缩放;

3.在ACTION_UP后调用回调接口中的onViewReleased方法,此方法中一个重要的任务是在ACTION_UP事件

  后,实现view的自动滑动,这里主要是使用了ViewDragHelper中smoothSlideViewTo方法,start了ViewDragHelper

  中的mScroller:

        mScroller.startScroll(startLeft, startTop, dx, dy, duration);

        setDragState(STATE_SETTLING);
    然后通过方法ViewCompat.postInvalidateOnAnimation(this)调用view的 computeScroll() 方法:

    public void computeScroll() {
        if (dragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

  ViewDragHelper的中的continueSettling方法会调用的mScroller.computeScrollOffset();方法,

来判断滚动是否结束,并在获取mScroller.getCurrX() 的值后,调用回调接口的onViewPositionChanged方法对view进行layout,

自此完成了手动拖和ACTION_UP后自动滚动的两个过程,大致流程图如下:






发布了28 篇原创文章 · 获赞 8 · 访问量 7万+
展开阅读全文

ViewDragHelper做拖动,View会跳回到原位置,why?

10-29

使用ViewDragHelper做拖动,当动态addView的时候,原本已经拖动到另一位置的View会回到原位置,why? 我有一个简单的VHLayout,继承自FrameLayout,里面通过setDragableView方法可以指定哪个子View可以拖动 ``` import android.content.Context; import android.support.v4.view.MotionEventCompat; import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; public class VHLayout extends FrameLayout { private View mView; private ViewDragHelper mDragHelper; public VHLayout(Context context, AttributeSet attrs) { super(context, attrs); mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() { // 返回ture则表示可以捕获该view;可以根据传入的view参数决定哪些可以拖动 @Override public boolean tryCaptureView(View child, int pointerId) { return child == mView; } // 控制水平拖动的边界 @Override public int clampViewPositionHorizontal(View child, int left, int dx) { final int leftBound = getPaddingLeft(); final int rightBound = getWidth() - child.getWidth() - leftBound; final int newLeft = Math.min(Math.max(left, leftBound), rightBound); return newLeft; } // 控制垂直拖动的边界 @Override public int clampViewPositionVertical(View child, int top, int dy) { final int topBound = getPaddingTop(); final int bottomBound = getHeight() - child.getHeight() - topBound; final int newTop = Math.min(Math.max(top, topBound), bottomBound); return newTop; } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); } // 解决ViewDragHelper中添加button,在控制button拖动的同时又不影响button的点击事件! @Override public int getViewHorizontalDragRange(View child) { return mView == child ? child.getWidth() : 0; } @Override public int getViewVerticalDragRange(View child) { return mView == child ? child.getHeight() : 0; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); changedView.layout(left, top, left + changedView.getMeasuredWidth(), top + changedView.getMeasuredHeight()); } }); } @Override protected void onFinishInflate() { super.onFinishInflate(); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { final int action = MotionEventCompat.getActionMasked(event); if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { mDragHelper.cancel(); return false; } return mDragHelper.shouldInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { try { mDragHelper.processTouchEvent(event); } catch (Exception e) { // TODO: handle exception } return true; } public void setDragableView(View view) { mView = view; } } ``` 拖动一切没问题 但是当我实际使用的时候却有问题了,如下,我在布局里的一个叫container的LinearLayout动态添加一个View(addView),就出现所说的现象。事实上,只要弹出输入法,也会出现这种回到原位置的问题。怎么解决的? 使用方式: ``` public void addFloatView(int bottomMargin){ FrameLayout.LayoutParams params=new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT); params.gravity=Gravity.RIGHT|Gravity.BOTTOM;//让加入的View出现在右下角 params.bottomMargin=bottomMargin; ImageView iv=new ImageView(context); iv.setImageResource(R.drawable.ic_scan); iv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub onFloatViewClick(); } }); VHLayout rootView=(VHLayout)findViewById(R.id.rootView); rootView.setDragableView(iv); rootView.addView(iv,params); } ``` 布局: ``` <com.mb.goods.widget.VHLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/rootView" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <include layout="@layout/actionbar_comm" /> </LinearLayout> </com.mb.goods.widget.VHLayout> ``` 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览