Android之ViewDragHelper的使用

Android之ViewDragHelper的使用

关于ViewDragHelper

官方文档的介绍是:
ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number of useful operations and state tracking for allowing a user to drag and reposition views within their parent ViewGroup.
这段话很容易理解,不重复啰嗦了。

实例

使用步骤:
1.使用ViewDragHelper的静态方法create创建,需要传人一个ViewDragHelper.CallBack对象;
2.实现ViewDragHelper.CallBack中的方法,来实现对视图的一些操作,如拖拽等
3.onInterceptTouchEvent和onTouchEvent回调ViewDragHelper中对应方法

下面通过实例来简单了解一下一些主要方法的使用:

  • tryCaptureView
  • clampViewPositionHorizontal
  • clampViewPositionVertical
  • onEdgeDragStarted
  • onViewReleased
  • getViewHorizontalDragRange/getViewVerticalDragRange

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<c.viewdraghpdemo.ViewDrag xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="16dp"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="c.viewdraghpdemo.MainActivity">

    <TextView
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:text="Hello World!"
        android:background="@android:color/holo_blue_dark"/>
</c.viewdraghpdemo.ViewDrag>

自定义的View

package c.viewdraghpdemo;

import android.content.Context;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * Created by Administrator on 2016/9/26.
 */

public class ViewDrag extends LinearLayout {
    private static final String TAG = "hly";
    private ViewDragHelper mViewDrag;
    private TextView tv;

    public ViewDrag(Context context) {
        super(context, null);
    }

    public ViewDrag(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ViewDrag(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        //Step1:使用静态方法构造ViewDragHelper,其中需要传入一个ViewDragHelper.Callback回调对象.
        mViewDrag = ViewDragHelper.create(this, 1.0f, mViewDragCB);
        //setEdgeTrackingEnabled设置的边界滑动时触发
        mViewDrag.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
    }

    ViewDragHelper.Callback mViewDragCB = new ViewDragHelper.Callback() {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            //返回ture则表示可以捕获该view
            return true;
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            //手指触摸移动时实时回调, left就是child.getLeft()的值
            return left;
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            //同理
            return top;
        }
    };

    //重写onInterceptTouchEvent回调ViewDragHelper中对应的方法.
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDrag.shouldInterceptTouchEvent(ev);
    }

    //重写onTouchEvent回调ViewDragHelper中对应的方法.
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDrag.processTouchEvent(event);
        return true;
    }

    //得到child实例
    @Override
    protected void onFinishInflate() {
        tv = (TextView) getChildAt(0);
    }
}

相关方法的用处已经在代码里注释了,应该很好理解

MainActivity.java

package c.viewdraghpdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

简单运行一下,看看效果:
这里写图片描述

可以看见现在TextView可以被拖动了,但是这里发现可以被拖到屏幕外面,这时候就要在ViewDragHelper.CallBack里面处理一下了,具体修改如下:


        @Override
        //手指触摸移动时实时回调, left就是child.getLeft()的值
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            //可左右滑动的空间
            int spaceX = getWidth()  - getPaddingRight() - child.getWidth();
            return Math.min(Math.max(getPaddingLeft(), left), spaceX);
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            //同理
            int spaceY = getHeight() - getPaddingBottom() - child.getHeight();
            return Math.min(Math.max(getPaddingTop(), top), spaceY);
        }
    };

运行一下,发现不会移动到屏幕外了:
这里写图片描述

在上面的代码里面还有一句

mViewDrag.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);

这个是滑动到边界的时候触发的,还需要在CallBack中实现一个方法

 @Override
        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
            //当tryCaptureView为false时也可以生效
            mViewDrag.captureChildView(tv, pointerId);
            }

     具体效果:
     ![这里写图片描述](https://img-blog.csdn.net/20160926173405240)

当我们释放手指时,想让子View滑到一个指定位置,可以用CallBack中的onViewReleased方法:

 @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            if (releasedChild == tv) {
                mViewDrag.settleCapturedViewAt(300,300);
                invalidate();
            }
       }

当onViewReleased中的invalidate()被调用之后,会不断调用调用computeScroll(),因此,要在ViewDrag类中重写一下这个方法:

@Override
    public void computeScroll() {
        if (mDragHelper.continueSettling(true)) {
            invalidate();
        }
    }

运行效果:
这里写图片描述

当给tv设置了clickable为ture时,或者子view为Button时,发现根据上述的代码,拖拽子view是没反应的,原因是拖动的时候onInterceptTouchEvent方法,判断是否可以捕获,而在判断的过程中会去判断另外两个回调的方法getViewHorizontalDragRange和getViewVerticalDragRange,只有这两个方法返回大于0的值才能正常的捕获。如果未能正常捕获就会导致手势down后面的move以及up都没有进入到onTouchEvent。
解决方法:

@Override
        public int getViewHorizontalDragRange(View child) {
            return getMeasuredWidth() - child.getWidth();
        }

        @Override
        public int getViewVerticalDragRange(View child) {
            return getMeasuredHeight() - child.getHeight();
        }

参考资料 :
http://blog.csdn.net/u012551350/article/details/51601985

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值