<code>public class ViewDragHelper extends Object
java.lang.Object
↳
android.support.v4.widget.ViewDragHelper</code>
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.
ViewDragHelper是编写自定义ViewGroups一个实用工具类。
它定义了一组有用的操作和状态追踪,允许用户在父ViewGroup中拖动并且重新定位子View(child view)。
<ol>
<li>ViewDragHelper.Callback是连接ViewDragHelper与view之间的桥梁(这个view一般是指拥子view的容器即parentView);</li>
<li> ViewDragHelper的实例是通过静态工厂方法创建的;</li>
<li>能够指定拖动的方向;</li>
<li> ViewDragHelper可以检测到是否触及到边缘;</li>
<li> ViewDragHelper并不是直接作用于要被拖动的View,而是使其控制的视图容器中的子View可以被拖动,如果要指定某个子view的行为,需要在Callback中想办法;</li>
<li> ViewDragHelper的本质其实是分析onInterceptTouchEvent和onTouchEvent的MotionEvent参数,然后根据分析的结果去改变一个容器中被拖动子View的位置( 通过offsetTopAndBottom(int offset)和offsetLeftAndRight(int offset)方法 ),他能在触摸的时候判断当前拖动的是哪个子View;</li>
<li>ViewDragHelper的实例方法 ViewDragHelper create(ViewGroup forParent, Callback cb) 可以指定一个被ViewDragHelper处理拖动事件的对象 。</li>
</ol>
ViewDragHelper.Callback(ViewDragHelper与View之间的桥梁)
<code>public static abstract class ViewDragHelper.Callback
extends Object
java.lang.Object
↳
android.support.v4.widget.ViewDragHelper.Callback</code>
官网简介:
A Callback is used as a communication channel with the ViewDragHelper back to the parent view using it. on*
methods are invoked on significant events and several accessor methods are expected to provide the ViewDragHelper with more information about the state of the parent view upon request. The callback also makes decisions governing the range and draggability of child views.
Callback是连接ViewDragHelper与parentView之间的桥梁。
方法在重要的事件中被调用,几个访问方法会提供给ViewDragHelper更多关于parentView的状态信息。
Callback同时也决定了拖动的范围和子view的拖动能力。
<br />
为什么要使用ViewDragHelper
ViewDragHelper解决了android中手势处理过于复杂的问题,在DrawerLayout出现之前,侧滑菜单都是由第三方开源代码实现的,其中著名的当属 MenuDrawer ,MenuDrawer重写onTouchEvent方法来实现侧滑效果,代码量很大,实现逻辑也需要很大的耐心才能看懂。如果每个开发人员都从这么原始的步奏开始做起,那对于安卓生态是相当不利的。所以说ViewDragHelper等的出现反映了安卓开发框架已经开始向成熟的方向迈进。
ViewDragHelper实例
根据开源项目android-card-slide-panel 简化
创建自定义的ViewGroup
public class CardSlidePanel extends ViewGroup {
private ViewDragHelper mViewDragHelper;
public CardSlidePanel(Context context) {
this(context, null);
}
public CardSlidePanel(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CardSlidePanel(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 滑动相关类
mViewDragHelper = ViewDragHelper
.create(this, 10f, new DragHelperCallback());
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
}
@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));
}
@Override
protected void onLayout(boolean changed, int left, int t, int right, int b) {
int mTotalHeight = 0;
// 遍历所有子视图
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
// 获取在onMeasure中计算的视图尺寸
int measureHeight = childView.getMeasuredHeight();
int measuredWidth = childView.getMeasuredWidth();
childView.layout(left, mTotalHeight, measuredWidth, mTotalHeight + measureHeight);
mTotalHeight += measureHeight;
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
}
/**
* 这是viewdraghelper拖拽效果的主要逻辑
*/
private class DragHelperCallback extends ViewDragHelper.Callback {
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
}
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
@Override
public int getViewHorizontalDragRange(View child) {
return 256;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return top;
}
}
}
创建布局文件layout_drag.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:orientation="vertical">
<org.lethisis.weather.weatherl.ui.widget.cardslide.CardSlidePanel
android:id="@+id/image_slide_panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark">
<LinearLayout
android:id="@+id/card_bottom_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/card_left_btn"
android:layout_width="70dp"
android:layout_height="70dp" />
<Button
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="10dp" />
<Button
android:id="@+id/card_right_btn"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginLeft="10dp" />
</LinearLayout>
<org.lethisis.weather.weatherl.ui.widget.cardslide.CardItemView
android:layout_width="@dimen/card_image_width"
android:layout_height="100dp" />
<org.lethisis.weather.weatherl.ui.widget.cardslide.CardItemView
android:layout_width="@dimen/card_image_width"
android:layout_height="100dp" />
<org.lethisis.weather.weatherl.ui.widget.cardslide.CardItemView
android:layout_width="@dimen/card_image_width"
android:layout_height="wrap_content" />
<org.lethisis.weather.weatherl.ui.widget.cardslide.CardItemView
android:layout_width="@dimen/card_image_width"
android:layout_height="wrap_content" />
</org.lethisis.weather.weatherl.ui.widget.cardslide.CardSlidePanel>
</LinearLayout>
【待续】
参考:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0911/1680.html