Android ViewDragHelper 使用详解
来源:互联网 发布:国产cad软件哪款好用 编辑:程序博客网 时间:2024/05/18 02:45
一、简介
对于编写一个自定义的viewgroup ViewDragHelper是一个实用的类。它提供了很多有用的操作和状态,实现监听用户在父ViewGroup拖拽和重新定位子view。
二、详解
1. 使用步骤
(1)、自定义一个View
(2)、创建一个ViewDragHelper的实例
dragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() { });
其中1.0f是敏感度参数参数越大越敏感。this为当前的ViewGroup,他是ViewDragHelper的拖动处理对象,必须为ViewGroup。
(3)、触摸相关的方法的调用
@Override public boolean onInterceptTouchEvent(MotionEvent event) { return dragHelper.shouldInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { dragHelper.processTouchEvent(event); return true; }
将Tonch事件交给ViewDragHelper处理
(4)、实现ViewDragHelper.CallCack相关方法
2. 类介绍
(1)、ViewDragHelper常用方法介绍
dragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT | ViewDragHelper.EDGE_TOP | ViewDragHelper.EDGE_RIGHT | ViewDragHelper.EDGE_BOTTOM);
设置边界触摸回调是否被激活,分别为上下左右边界的设置
dragHelper.smoothSlideViewTo(view, getPaddingLeft(), getPaddingTop())
使用动画平滑的移动到指定位置,但是一定要添加下边代码
@Override public void computeScroll() { if (dragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } }
还有一些其他功能方法,如(取消、状态跟踪)的方法,比较好理解这里不做介绍。
(2)、ViewDragHelper.Callback的类介绍,在下边示例注释中已经非常完善,这里不做重复介绍了。
3. 相关问题
(1)、如果ViewGroup的子控件会消耗点击事件,例如按钮,在触摸屏幕的时候就会先走onInterceptTouchEvent方法,判断是否可以捕获,而在判断的过程中会去判断另外两个回调的方法:getViewHorizontalDragRange和getViewVerticalDragRange,只有这两个方法返回大于0的值才能正常的捕获,否则会出现子控件不能拖动的问题。
(2)、如果需要使用边界检测需要添加上
dragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT | ViewDragHelper.EDGE_TOP | ViewDragHelper.EDGE_RIGHT | ViewDragHelper.EDGE_BOTTOM);
(3)、如果你当前布局的根布局不是DragLayout,可能会遇到DragLayout遮挡其他布局Touch事件的问题。这时你可以考虑onTouchEvent(),onInterceptTouchEvent()方法,根据需求动态返回true,false。
三、示例
1. 示例效果
2. 代码分析
DragLayout.java
import android.content.Context;import android.support.v4.view.ViewCompat;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;import android.widget.Toast;public class DragLayout extends LinearLayout { private static final String TAG = "DragLayout"; private ViewDragHelper dragHelper; private TextView mDragView1; private View mDragView2; private View mDragView3; public DragLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { dragHelper = ViewDragHelper.create(this, callback); // 设置边界触摸回调被激活 dragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT | ViewDragHelper.EDGE_TOP | ViewDragHelper.EDGE_RIGHT | ViewDragHelper.EDGE_BOTTOM); } private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { /** * 指定View是否可拖拽 * @param child 用户捕获的view * @param pointerId * @return 捕获的view是否可拖动 */ @Override public boolean tryCaptureView(View child, int pointerId) { return child == mDragView1 || child == mDragView3; } /** * @param state 拖拽的状态 * * @see # STATE_IDLE 拖拽结束 * @see # STATE_DRAGGING 正在拖拽 * @see # STATE_SETTLING 正在被放置,这个状态不会出现 */ @Override public void onViewDragStateChanged(int state) { if (state == ViewDragHelper.STATE_DRAGGING) { mDragView1.setText("正在拖拽"); } else if (state == ViewDragHelper.STATE_IDLE) { mDragView1.setText("拖拽结束"); } } /** * 当View的位置发生改变是回调 * @param changedView 当前发生位置改变的View * @param left view左上角新X坐标 * @param top view左上角新Y坐标 * @param dx 俩次回调X轴方向移动的距离 * @param dy 俩次回调Y轴方向移动的距离 */ @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { Log.d(TAG, "onViewPositionChanged left" + left); Log.d(TAG, "onViewPositionChanged top" + top); Log.d(TAG, "onViewPositionChanged dx" + dx); Log.d(TAG, "onViewPositionChanged dy" + dy); Log.d(TAG, "----------------------"); } /** * 当view被捕获时回调 * * @param capturedChild 被捕获的view * @param activePointerId */ @Override public void onViewCaptured(View capturedChild, int activePointerId) { } /** * 手指释放时候回调该方法 * @param releasedChild 被释放的子view * @param xvel 手指的X轴速度,以像素每秒钟离开屏幕 * @param yvel 手指的Y轴速度,以像素每秒钟离开屏幕 */ @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { // 向下,向右为正,否则为负 if (yvel > 0) { if (releasedChild == mDragView3) { smoothToBottom(releasedChild); } Toast.makeText(getContext(), "释放时,速度向下大于0", Toast.LENGTH_SHORT).show(); } else if (yvel < 0) { if (releasedChild == mDragView3) { smoothToTop(releasedChild); } Toast.makeText(getContext(), "释放时,速度向上大于0", Toast.LENGTH_SHORT).show(); } } /** * 当触摸到父布局边界时回调(必须调用ViewDragHelper.setEdgeTrackingEnabled才会生效) * * @param edgeFlags * @param pointerId */ @Override public void onEdgeTouched(int edgeFlags, int pointerId) { if (edgeFlags == ViewDragHelper.EDGE_TOP) { Toast.makeText(getContext(), "到上边界了", Toast.LENGTH_SHORT).show(); } else if (edgeFlags == ViewDragHelper.EDGE_BOTTOM) { Toast.makeText(getContext(), "到下边界了", Toast.LENGTH_SHORT).show(); } else if (edgeFlags == ViewDragHelper.EDGE_LEFT) { Toast.makeText(getContext(), "到左边界了", Toast.LENGTH_SHORT).show(); } else if (edgeFlags == ViewDragHelper.EDGE_RIGHT) { Toast.makeText(getContext(), "到右边界了", Toast.LENGTH_SHORT).show(); } } @Override public boolean onEdgeLock(int edgeFlags) { return false; } /** * 当没有捕获到子view时,通过触摸边界拖拽子view(场景:当view在屏幕外,无法捕获view,只能通过触摸屏幕边界先让他滚回来) * @param edgeFlags * @param pointerId */ @Override public void onEdgeDragStarted(int edgeFlags, int pointerId) { dragHelper.captureChildView(mDragView2, pointerId);// dragHelper.captureChildView(mDragView3, pointerId); } /** * 返回捕获的view Z轴的坐标(即当前view在布局的第几层) * @param index * @return */ @Override public int getOrderedChildIndex(int index) { Log.d(TAG, "getOrderedChildIndex index" + index); return index; } /** * 该view水平方向拖动的范围(子控件消耗点击事件时候才回调(例如:按钮)) * @param child * @return */ @Override public int getViewHorizontalDragRange(View child) { return getMeasuredWidth() - child.getMeasuredWidth(); } /** * 该view垂直方向拖动的范围(子控件消耗点击事件时候才回调(例如:按钮)) * @param child * @return */ @Override public int getViewVerticalDragRange(View child) { return getMeasuredHeight() - child.getMeasuredHeight(); } /** * 垂直方向限制View的拖动范围 * @param child 被拖动的子View * @param top 移动过程中Y轴的坐标 * @param dy * @return view的新位置 */ @Override public int clampViewPositionVertical(View child, int top, int dy) { // 限定view上下边界(以view左上角坐标点为准) final int topBound = getPaddingTop(); final int bottomBound = getHeight() - child.getHeight(); final int newTop = Math.min(Math.max(top, topBound), bottomBound); return newTop; } /** * 水平方向限制View的拖动范围 * @param child 被拖动的子View * @param left 移动过程中X轴的坐标 * @param dx * @return view的新位置 */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { return left; } }; @Override public boolean onInterceptTouchEvent(MotionEvent event) { return dragHelper.shouldInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { dragHelper.processTouchEvent(event); return true; } @Override protected void onFinishInflate() { super.onFinishInflate(); mDragView1 = (TextView) getChildAt(0); mDragView2 = getChildAt(1); mDragView3 = getChildAt(2); } public void smoothToTop(View view) { // 动画平滑的移动到指定位置 if (dragHelper.smoothSlideViewTo(view, getPaddingLeft(), getPaddingTop())) { ViewCompat.postInvalidateOnAnimation(this); } } public void smoothToBottom(View view) { // 动画平滑的移动到指定位置 if (dragHelper.smoothSlideViewTo(view, getPaddingLeft(), getHeight() - view.getHeight())) { ViewCompat.postInvalidateOnAnimation(this); } } @Override public void computeScroll() { if (dragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } }}
XML文件
<com.wyj.viewdraglayout.DragLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/textview1" android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center" android:layout_margin="10dp" android:background="#FFDCD665" android:gravity="center" android:text="可直接拖动的View" /> <TextView android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center" android:layout_margin="10dp" android:background="#FFDCD665" android:gravity="center" android:text="触摸边界可拖动的View" /> <Button android:id="@+id/button" android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="10dp" android:background="#FFDCD665" android:gravity="center" android:text="Button" /></com.wyj.viewdraglayout.DragLayout>
3. 示例代码下载
github地址 https://github.com/Ya-Jun/SmallSampleCollection
- Android ViewDragHelper 使用详解
- Android 之 ViewDragHelper 详解
- android ViewDragHelper详解
- Android ViewDragHelper详解
- ViewDragHelper使用详解
- ViewDragHelper的使用详解
- ViewDragHelper使用详解
- android viewdraghelper使用
- Android ViewDragHelper简单使用
- Android ViewDragHelper使用总结
- android关于ViewDragHelper的使用
- Android之ViewDragHelper的使用
- android ViewDragHelper介绍与使用
- ViewDragHelper详解
- ViewDragHelper详解
- ViewDragHelper详解
- ViewDragHelper详解
- ViewDragHelper详解
- 九大经典排序算法整理及其源代码分享(C/C++版)
- 正则表达式简介
- 腾讯云lnmp的安装
- 上传图片跟微信头像
- UVA 1583 打表 数论
- Android ViewDragHelper 使用详解
- Android系列之SQLite与Android Studio的数据交互
- Python 2
- 1130 数字反转
- QT入门语法——signal,slot
- JavaScript基本概念(一)
- Win32_Printer class 从WMI取到的打印机的属性信息,这一定是你想要找的 The Win32_Printer WMI class represents a device conne
- Python中import语句的使用教程
- 记录在windows10上安装FensorFlow1.2