android ViewDragHelper介绍

本文详细介绍如何使用ViewDragHelper实现自定义ViewGroup中的视图拖动功能。通过具体示例介绍了ViewDragHelper的基本用法,包括创建实例、实现回调接口中的方法,并解释了关键方法的作用。

我们平时在自定义ViewGroup来实现一些复杂的效果时,基本都逃不过要处理事件的传递和分发,而ios在控件上可以上做的非常好,基本上都给封装好了,只需要调用和实现自己的业务逻辑就可以,这就是为什么同样的效果ios实现起来很简单,而android就不一样呢?最傻逼的是一些产品经理老拿ios跟android程序员说做出这个效果,心想妈的不知道开发成本不一样么,ios几行代码搞定,android有那么轻易搞定么,而且自定义控件本来就是android一个大头,比较难搞,像什么网络请求,图片加载之类的都有第三方会用就行,但是google就是给我们android挖坑,还好Google在你这方面也慢慢学习了ios,比如自定义viewgroup处理事件分发就引入了ViewDragHelper,它在v4包下,我也是最近没事干,所以找了相关资料研究下,也就是研究下它几个方法以及方法中的参数都是干嘛用的,

使用ViewDragHelper有二步:

1:创建ViewDragHelper对象实例,ViewDragHelper是不能new 只能通过类似工厂方法那样,具体你是不是工厂方法内部实现,我也不清楚,没看过这个源码,知道怎么创建它的实例对象就行

2;覆盖ViewDragHelper.CallBack接口中的几个方法,CallBack是ViewDragHelper内部定义的接口

现在就写个例子玩玩,新建一个android项目ViewDragHelperDemo,

activity_main.xml  里面写个了自定义控件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.viewdraghelperdemo.MainActivity" >

    <com.example.viewdraghelperdemo.MyLinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
        <TextView
            android:id="@+id/tv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="20dp"
            android:text="东"
            android:background="#ff9999"
            />
           <TextView
            android:id="@+id/tv2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="20dp"
            android:text="西"
            android:background="#ff00ff"
            android:layout_marginTop="30dp"
            />
           <TextView
            android:id="@+id/tv3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="20dp"
            android:text="北"
            android:background="#ff0000"
            android:layout_marginTop="30dp"
            />
        </com.example.viewdraghelperdemo.MyLinearLayout>

</RelativeLayout>

MyLinearLayout.java

/**
 * AUTHOR:Zhou Guizhi
 *
 * DESCRIPTION:create the File, and add the content.
 *
 * Copyright © ZhiMore. All Rights Reserved
 *
 */
package com.example.viewdraghelperdemo;
import android.content.Context;
import android.support.v4.widget.ViewDragHelper;
import android.support.v4.widget.ViewDragHelper.Callback;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
 * Created in Mar 2, 2016 9:10:21 AM
 * @author Zhou Guizhi; 
 */
public class MyLinearLayout extends LinearLayout {
	protected static final String TAG = "MyLinearLayout";
	private ViewDragHelper mDragHelper;
	private TextView tv1,tv2,tv3;
	/**
	 * @param context
	 * @param attrs
	 * @param defStyleAttr
	 */
	public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}
	/**
	 * 
	 */
	View temp;
	private void init() {
		mDragHelper = ViewDragHelper.create(this, 1.0f, new Callback() {
			@Override
			public boolean tryCaptureView(View arg0, int arg1) {
				return arg0==tv1;
			}
			@Override
			public int clampViewPositionHorizontal(View child, int left, int dx) {
                 if(left<=0){
                	 left=0;
                 }
                 int w = getWidth()-child.getWidth();
                 if(left>w){
                	 left = w;
                 }
				return left;
			}
			@Override
			public int clampViewPositionVertical(View child, int top, int dy) {
				if(top<=0){
					top=0;
				}
				int h = getHeight()-child.getHeight();
				if(top>h){
					top = h;
				}
				return top;
			}
		});
	}
	/**
	 * @param context
	 * @param attrs
	 */
	public MyLinearLayout(Context context, AttributeSet attrs) {
		this(context, attrs,0);
	}
	/**
	 * @param context
	 */
	public MyLinearLayout(Context context) {
		this(context,null);
	}
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		mDragHelper.processTouchEvent(event);
		return true;
	}
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		return mDragHelper.shouldInterceptTouchEvent(ev);
	}
	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		tv1 = (TextView) getChildAt(0);
		tv2 = (TextView) getChildAt(1);
		tv3 = (TextView) getChildAt(2);
	}
}

如图:



现在可以实现这三个view随意在屏幕上拖动,也许会说这个太简单了,不用ViewDragHelper也能实现,是的,技术上实现方式很多种,但是你要考虑实现的时间成本,性能等各方面,当然了我们也是从简单往深点方面探索,

现在对实现CallBack中的三个方法做一个介绍

tryCaptureView(View arg0, int arg1) 是决定你铺货ViewGroup中那个子view,让这个子view可以在父view上有touch事件,比如你要一个子view可以有touch的话,就这样写

@Override
public boolean tryCaptureView(View arg0, int arg1) {
 return arg0==tv1;
}

它的第一个参数就是你拖动那个子view,如果你要想所有的子view都有touch事件的话,你可以直接返回true,当然了还有一个更傻逼的做法,就是获取viewGroup中所有的子view,然后

@Override
public boolean tryCaptureView(View arg0, int arg1) {
return arg0==tv1||arg0==tv2;
}

这种写法几乎不使用,但是比如你ViewGroup中有3个子view,想让其中二个子view可以有touch事件的话,就可以这样写了,如果你返回false的话,所有子view都不能接受touch事件

public int clampViewPositionHorizontal(View child, int left, int dx) 表示view水平方向滑动,第一个参数就是你当然拖动的子view,left是水平滑动的距离,自己可以打log看看它的值就知道了,如果你不想子view滑动超过屏幕的话,就要做些简单的逻辑判断了,

 if(left<=0){
     left=0;
}
int w = getWidth()-child.getWidth();
if(left>w){
    left = w;
 }

最后返回left就行,这就是限制view在滑动的过程中超过屏幕边缘,

public int clampViewPositionVertical(View child, int top, int dy) 表示的是view垂直滑动,第一个参数不用多说,第二个参数表示的是滑动时候离父view多少像素,第三个参数,没研究,

ViewDragHelper创建实例对象ViewDragHelper.create(this, 1.0f, new Callback())

第一个参数是ViewGroup,

第二个参数是是关于子view在滑动的灵敏度,它是这样计算的

mDragHelper.getTouchSlop()*(1/传递的第二个参数); 

第三个参数是CallBack的实现类,它是一个类,之前说它是一个接口,说错了,因为它里面很多方法,而不要求我们要实现它所有的方法所以是一个类,它里面大概有这么多方法 如下:


根据我们自己的需要 可以针对实现哪个方法,当然最好是每个方法都去研究分析下,

当然了还有二个很重要的方法,一个是onTouchEvent() 把touch事件交给ViewDragHelper处理,还有一个就是onInterceptTouchEvent()方法表示处理子view和父view的事件拦截

通常是这样写的

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		mDragHelper.processTouchEvent(event);
		return true;
	}
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		return mDragHelper.shouldInterceptTouchEvent(ev);
	}

现在对CallBack类中的其他方法也玩下,  打log分析

public void onViewReleased(View releasedChild, float xvel, float yvel)  这个方法从字面上都能看的懂他是干嘛用的,就是当你滑动过程中手指释放时候回调用的,

xvel:表示x方向每秒拖动的像素

yvel:同xvel参数

public void onEdgeTouched(int edgeFlags, int pointerId) 表示拖动到边缘时回调

public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) 子view拖动时发生改变时回调













评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值