您的位置:首页 > 移动开发 > Android开发

android ViewDragHelper介绍

2016-03-02 14:04 323 查看
我们平时在自定义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拖动时发生改变时回调
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: