ViewDragHelper详解

神奇的 ViewDragHelper,让你轻松定制拥有拖拽能力的 ViewGroup 为了吸引大家的注意力,先给大家看一张动图: 相信这种效果大家都见过吧?我第一次见到这样的效果时,心里也痒痒的,急于想实现这种功能,后来因为拖延症的问题,就一直没有去弄这件事。现在这段时间,工作比较轻闲,所以对自己几年 Android 生涯所运用的技术做一些总结与思考。拖拽这种功能正好可以形成一个主题。如题目所示,今天博文的目标就是介绍与分析 ViewDragHelper 这个类。 读者阅读本 阅读详情

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0911/1680.html


编辑推荐:稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识、前端、后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过!

2013年谷歌i/o大会上介绍了两个新的layout: SlidingPaneLayout和DrawerLayout,现在这俩个类被广泛的运用,其实研究他们的源码你会发现这两个类都运用了ViewDragHelper来处理拖动。ViewDragHelper是framework中不为人知却非常有用的一个工具。

ViewDragHelper解决了android中手势处理过于复杂的问题,在DrawerLayout出现之前,侧滑菜单都是由第三方开源代码实现的,其中著名的当属 MenuDrawer ,MenuDrawer重写onTouchEvent方法来实现侧滑效果,代码量很大,实现逻辑也需要很大的耐心才能看懂。如果每个开发人员都从这么原始的步奏开始做起,那对于安卓生态是相当不利的。所以说ViewDragHelper等的出现反映了安卓开发框架已经开始向成熟的方向迈进。

本文先介绍ViewDragHelper的基本用法,然后介绍一个能真正体现ViewDragHelper实用性的例子。

ViewDragHelper

其实ViewDragHelper并不是第一个用于分析手势处理的类,gesturedetector也是,但是在和拖动相关的手势分析方面gesturedetector只能说是勉为其难。

关于ViewDragHelper有如下几点:

   ViewDragHelper.Callback是连接ViewDragHelper与view之间的桥梁(这个view一般是指拥子view的容器即parentView);

   ViewDragHelper的实例是通过静态工厂方法创建的;

   你能够指定拖动的方向;

   ViewDragHelper可以检测到是否触及到边缘;

   ViewDragHelper并不是直接作用于要被拖动的View,而是使其控制的视图容器中的子View可以被拖动,如果要指定某个子view的行为,需要在Callback中想办法;

   ViewDragHelper的本质其实是分析onInterceptTouchEvent和onTouchEvent的MotionEvent参数,然后根据分析的结果去改变一个容器中被拖动子View的位置( 通过offsetTopAndBottom(int offset)和offsetLeftAndRight(int offset)方法 ),他能在触摸的时候判断当前拖动的是哪个子View;

   虽然ViewDragHelper的实例方法 ViewDragHelper create(ViewGroup forParent, Callback cb) 可以指定一个被ViewDragHelper处理拖动事件的对象 。

用法:

下面部分内容基本是Each Navigation Drawer Hides a ViewDragHelper 一文的翻译。

1.ViewDragHelper的初始化

ViewDragHelper一般用在一个自定义ViewGroup的内部,比如下面自定义了一个继承于LinearLayout的DragLayout,DragLayout内部有一个子view mDragView作为成员变量:

1
2
3
4
5
6
7
8
9
10
11
12
public class DragLayout extends LinearLayout {
private final ViewDragHelper mDragHelper;
private View mDragView;
public DragLayout(Context context) {
   this (context,  null );
}
public DragLayout(Context context, AttributeSet attrs) {
   this (context, attrs, 0);
}
public DragLayout(Context context, AttributeSet attrs, int defStyle) {
   super (context, attrs, defStyle);
}

创建一个带有回调接口的ViewDragHelper

1
2
3
4
public DragLayout(Context context, AttributeSet attrs, int defStyle) {
   super (context, attrs, defStyle);
   mDragHelper = ViewDragHelper.create( this , 1.0f,  new  DragHelperCallback());
}

其中1.0f是敏感度参数参数越大越敏感。第一个参数为this,表示该类生成的对象,他是ViewDragHelper的拖动处理对象,必须为ViewGroup。

要让ViewDragHelper能够处理拖动需要将触摸事件传递给ViewDragHelper,这点和gesturedetector是一样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
   final int action = MotionEventCompat.getActionMasked(ev);
   if  (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
       mDragHelper.cancel();
       return  false ;
   }
   return  mDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
   mDragHelper.processTouchEvent(ev);
   return  true ;
}

接下来,你就可以在回调中处理各种拖动行为了。

2.拖动行为的处理

处理横向的拖动:

在DragHelperCallback中实现clampViewPositionHorizontal方法, 并且返回一个适当的数值就能实现横向拖动效果,clampViewPositionHorizontal的第二个参数是指当前拖动子view应该到达的x坐标。所以按照常理这个方法原封返回第二个参数就可以了,但为了让被拖动的view遇到边界之后就不在拖动,对返回的值做了更多的考虑。

1
2
3
4
5
6
7
8
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
   Log.d( "DragLayout" ,  "clampViewPositionHorizontal "  + left +  ","  + dx);
   final int leftBound = getPaddingLeft();
   final int rightBound = getWidth() - mDragView.getWidth();
   final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
   return  newLeft;
}

同上,处理纵向的拖动:

在DragHelperCallback中实现clampViewPositionVertical方法,实现过程同clampViewPositionHorizontal

1
2
3
4
5
6
7
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
   final int topBound = getPaddingTop();
   final int bottomBound = getHeight() - mDragView.getHeight();
   final int newTop = Math.min(Math.max(top, topBound), bottomBound);
   return  newTop;
}

clampViewPositionHorizontal 和 clampViewPositionVertical必须要重写,因为默认它返回的是0。事实上我们在这两个方法中所能做的事情很有限。 个人觉得这两个方法的作用就是给了我们重新定义目的坐标的机会。

通过DragHelperCallback的tryCaptureView方法的返回值可以决定一个parentview中哪个子view可以拖动,现在假设有两个子views (mDragView1和mDragView2)  ,如下实现tryCaptureView之后,则只有mDragView1是可以拖动的。

1
2
3
4
@Override
public boolean tryCaptureView(View child, int pointerId) {
   return  child == mDragView1;
}

滑动边缘:

分为滑动左边缘还是右边缘:EDGE_LEFT和EDGE_RIGHT,下面的代码设置了可以处理滑动左边缘:

1
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);

假如如上设置,onEdgeTouched方法会在左边缘滑动的时候被调用,这种情况下一般都是没有和子view接触的情况。

1
2
3
4
5
@Override
public void onEdgeTouched(int edgeFlags, int pointerId) {
     super .onEdgeTouched(edgeFlags, pointerId);
     Toast.makeText(getContext(),  "edgeTouched" , Toast.LENGTH_SHORT).show();
}

如果你想在边缘滑动的时候根据滑动距离移动一个子view,可以通过实现onEdgeDragStarted方法,并在onEdgeDragStarted方法中手动指定要移动的子View

1
2
3
4
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
     mDragHelper.captureChildView(mDragView2, pointerId);
}


ViewDragHelper让我们很容易实现一个类似于YouTube视频浏览效果的控件,效果如下:


代码中的关键点:

1.tryCaptureView返回了唯一可以被拖动的header view;

2.拖动范围drag range的计算是在onLayout中完成的;

3.注意在onInterceptTouchEvent和onTouchEvent中使用的ViewDragHelper的若干方法;

4.在computeScroll中使用continueSettling方法(因为ViewDragHelper使用了scroller) 

5.smoothSlideViewTo方法来完成拖动结束后的惯性操作。

需要注意的是代码仍然有很大改进空间。

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<FrameLayout
         xmlns:android= "http://schemas.android.com/apk/res/android"
         android:layout_width= "match_parent"
         android:layout_height= "match_parent" >
     <ListView
             android:id= "@+id/listView"
             android:layout_width= "match_parent"
             android:layout_height= "match_parent"
             android:tag= "list"
             />
     <com.example.vdh.YoutubeLayout
             android:layout_width= "match_parent"
             android:layout_height= "match_parent"
             android:id= "@+id/youtubeLayout"
             android:orientation= "vertical"
             android:visibility= "visible" >
         <TextView
                 android:id= "@+id/viewHeader"
                 android:layout_width= "match_parent"
                 android:layout_height= "128dp"
                 android:fontFamily= "sans-serif-thin"
                 android:textSize= "25sp"
                 android:tag= "text"
                 android:gravity= "center"
                 android:textColor= "@android:color/white"
                 android:background= "#AD78CC" />
         <TextView
                 android:id= "@+id/viewDesc"
                 android:tag= "desc"
                 android:textSize= "35sp"
                 android:gravity= "center"
                 android:text= "Loreum Loreum"
                 android:textColor= "@android:color/white"
                 android:layout_width= "match_parent"
                 android:layout_height= "match_parent"
                 android:background= "#FF00FF" />
     </com.example.vdh.YoutubeLayout>
</FrameLayout>

YoutubeLayout.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
public class YoutubeLayout extends ViewGroup {
private final ViewDragHelper mDragHelper;
private View mHeaderView;
private View mDescView;
private float mInitialMotionX;
private float mInitialMotionY;
private int mDragRange;
private int mTop;
private float mDragOffset;
public YoutubeLayout(Context context) {
   this (context,  null );
}
public YoutubeLayout(Context context, AttributeSet attrs) {
   this (context, attrs, 0);
}
@Override
protected void onFinishInflate() {
     mHeaderView = findViewById(R.id.viewHeader);
     mDescView = findViewById(R.id.viewDesc);
}
public YoutubeLayout(Context context, AttributeSet attrs, int defStyle) {
   super (context, attrs, defStyle);
   mDragHelper = ViewDragHelper.create( this , 1f,  new  DragHelperCallback());
}
public void maximize() {
     smoothSlideTo(0f);
}
boolean smoothSlideTo(float slideOffset) {
     final int topBound = getPaddingTop();
     int y = (int) (topBound + slideOffset * mDragRange);
     if  (mDragHelper.smoothSlideViewTo(mHeaderView, mHeaderView.getLeft(), y)) {
         ViewCompat.postInvalidateOnAnimation( this );
         return  true ;
     }
     return  false ;
}
private class DragHelperCallback extends ViewDragHelper.Callback {
   @Override
   public boolean tryCaptureView(View child, int pointerId) {
         return  child == mHeaderView;
   }
     @Override
   public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
       mTop = top;
       mDragOffset = (float) top / mDragRange;
         mHeaderView.setPivotX(mHeaderView.getWidth());
         mHeaderView.setPivotY(mHeaderView.getHeight());
         mHeaderView.setScaleX(1 - mDragOffset / 2);
         mHeaderView.setScaleY(1 - mDragOffset / 2);
         mDescView.setAlpha(1 - mDragOffset);
         requestLayout();
   }
   @Override
   public void onViewReleased(View releasedChild, float xvel, float yvel) {
       int top = getPaddingTop();
       if  (yvel > 0 || (yvel == 0 && mDragOffset > 0.5f)) {
           top += mDragRange;
       }
       mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top);
   }
   @Override
   public int getViewVerticalDragRange(View child) {
       return  mDragRange;
   }
   @Override
   public int clampViewPositionVertical(View child, int top, int dy) {
       final int topBound = getPaddingTop();
       final int bottomBound = getHeight() - mHeaderView.getHeight() - mHeaderView.getPaddingBottom();
       final int newTop = Math.min(Math.max(top, topBound), bottomBound);
       return  newTop;
   }
}
@Override
public void computeScroll() {
   if  (mDragHelper.continueSettling( true )) {
       ViewCompat.postInvalidateOnAnimation( this );
   }
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
   final int action = MotionEventCompat.getActionMasked(ev);
   if  (( action != MotionEvent.ACTION_DOWN)) {
       mDragHelper.cancel();
       return  super .onInterceptTouchEvent(ev);
   }
   if  (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
       mDragHelper.cancel();
       return  false ;
   }
   final float x = ev.getX();
   final float y = ev.getY();
   boolean interceptTap =  false ;
   switch  (action) {
       case  MotionEvent.ACTION_DOWN: {
           mInitialMotionX = x;
           mInitialMotionY = y;
             interceptTap = mDragHelper.isViewUnder(mHeaderView, (int) x, (int) y);
           break ;
       }
       case  MotionEvent.ACTION_MOVE: {
           final float adx = Math.abs(x - mInitialMotionX);
           final float ady = Math.abs(y - mInitialMotionY);
           final int slop = mDragHelper.getTouchSlop();
           if  (ady > slop && adx > ady) {
               mDragHelper.cancel();
               return  false ;
           }
       }
   }
   return  mDragHelper.shouldInterceptTouchEvent(ev) || interceptTap;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
   mDragHelper.processTouchEvent(ev);
   final int action = ev.getAction();
     final float x = ev.getX();
     final float y = ev.getY();
     boolean isHeaderViewUnder = mDragHelper.isViewUnder(mHeaderView, (int) x, (int) y);
     switch  (action & MotionEventCompat.ACTION_MASK) {
       case  MotionEvent.ACTION_DOWN: {
           mInitialMotionX = x;
           mInitialMotionY = y;
           break ;
       }
       case  MotionEvent.ACTION_UP: {
           final float dx = x - mInitialMotionX;
           final float dy = y - mInitialMotionY;
           final int slop = mDragHelper.getTouchSlop();
           if  (dx * dx + dy * dy < slop * slop && isHeaderViewUnder) {
               if  (mDragOffset == 0) {
                   smoothSlideTo(1f);
               }  else  {
                   smoothSlideTo(0f);
               }
           }
           break ;
       }
   }
   return  isHeaderViewUnder && isViewHit(mHeaderView, (int) x, (int) y) || isViewHit(mDescView, (int) x, (int) y);
}
private boolean isViewHit(View view, int x, int y) {
     int[] viewLocation =  new  int[2];
     view.getLocationOnScreen(viewLocation);
     int[] parentLocation =  new  int[2];
     this .getLocationOnScreen(parentLocation);
     int screenX = parentLocation[0] + x;
     int screenY = parentLocation[1] + y;
     return  screenX >= viewLocation[0] && screenX < viewLocation[0] + view.getWidth() &&
             screenY >= viewLocation[1] && screenY < viewLocation[1] + view.getHeight();
}
@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 l, int t, int r, int b) {
   mDragRange = getHeight() - mHeaderView.getHeight();
     mHeaderView.layout(
             0,
             mTop,
             r,
             mTop + mHeaderView.getMeasuredHeight());
     mDescView.layout(
             0,
             mTop + mHeaderView.getMeasuredHeight(),
             r,
             mTop  + b);
}

代码下载地址:https://github.com/flavienlaurent/flavienlaurent.com


不管是menudrawer 还是本文实现的DragLayout都体现了一种设计哲学,即可拖动的控件都是封装在一个自定义的Layout中的,为什么这样做?为什么不直接将ViewDragHelper.create(this, 1f, new DragHelperCallback())中的this替换成任何已经布局好的容器,这样这个容器中的子View就能被拖动了,而往往是单独定义一个Layout来处理?个人认为如果在一般的布局中去拖动子view并不会出现什么问题,只是原本规则的世界被打乱了,而单独一个Layout来完成拖动,无非是说,他本来就没有什么规则可言,拖动一下也无妨。


Android ViewDragHelper完全解析 自定义ViewGroup神器 一、概述 在自定义ViewGroup中,很多效果都包含用户手指去拖动其内部的某个View(eg:侧滑菜单等),针对具体的需要去写好onInterceptTouchEvent和onTouchEvent这两个方法是一件很不容易的事,需要自己去处理:多手指的处理、加速度检测等等。 好在官方在v4的支持包中提供了ViewDragHelper这样一个类来帮助我们方便的编写自定义ViewGroup。简单看一下它的注释: ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number of usefu 立即下载

相关推荐

跟着团子学SAP CO:熟练使用结果分析码实现各个场景下收入成本的匹配(一) KKA2/CJ88

PS模块中对财务顾问最难的点在于项目结算,特别是销售型的项目结算。针对客户型项目结算我列举了以下常见的收入成本匹配的一些场景: (1)在项目执行过程中会多次开票,但由于各期成本浮动很大(如前期可能只涉及一些人工、中期全是比较金额较大的材料费),所以希望开票的时候能通过合理的一些指标进行主营业务成本与主营业务收入的匹配。 (2)项目过程中会多次开票,开票确认主营业务收入时,直接将累计发生的实际成本结转为主营业务成本。 (3)项目过程中虽多次开票,但不确认收入,所有发生的实际成本月末计算为在制品,最后项目一次性

Lucas1211的博客 9533

ViewDragHelper之手势操作神器,2021最新Android算法相关面试大全

为了让ViewDragHelper帮助我们简化手势操作,所以还需为它传入相关的MotionEvent。 override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { return mViewDragHelper.shouldInterceptTouchEvent(ev) } override fun onTouchEvent(event: MotionEvent?): Boolean { mViewDragHelper.processTouc

m0_64604636的博客 336

飞控算法-姿态解算之互补滤波

飞控乱入之姿态解算 姿态解算是通过读取各个传感器的数据进行融合最终得到当前飞行器的姿态,姿态通常用Euler角(Roll-Pitch-Yaw)来表示 姿态解算框架 姿态解算的数据源可来自于陀螺仪或加速度计,他们分别都可以得到当前姿态,但实际上他们都有各自的传感器性能的优缺点,需要取长补短,进行数据融合才能得到真实的姿态,这种方法简称 互补滤波 算法 传感器特性 互补滤波 姿态解...

GoolyOh的专栏 1万+

Android5.x新特性之ViewDragHelper拖动控件(3种方案)

+++++++++++++++++++++++++++++++方法1++++++++++++++++++++++++++++++++++++ activity_main.xml布局文件 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://sche

全干工程师 2055

Android SDK安装教程(超详细),从零基础入门到精通,从这篇开始_android sdk下载安装

Android SDK安装教程(超详细),从零基础入门到精通,从这篇开始_android sdk下载安装

Jinmindong 5013

Airsim动态 | 安装ROS包装器(AirSim ROS Wrapper)

本期内容我们将带来在Airsim环境下使用ROS Wrapper的相关教程,以下是AirSim客户端库上的一些ROS Wrapper相关配置。 一、启动 以下步骤适用于 Linux 系统。如果是在 Windows 上运行 AirSim,可以使用 Windows Subsystem for Linux (WSL) 来运行 ROS 包装器,如果不想在主机上安装ROS相关工具,也可以使用Docker容器进行安装。请检查下方内容并按照需求安装,具体内容可以参照最后网址。 如果您的默认 GCC 版本不是8或更高版.

AMOVLAB(阿木实验室) 1776

Android ViewDragHelper类

ViewDragHelper是个工具类,用来辅助ViewGroup内控件的操作和拖拽。 1. ViewDragHelper创建 ViewDragHelper通过静态方法create()创建, public static ViewDragHelper create(ViewGroup forParent, Callback cb) public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb)

假装你是大灰狼的专栏 1333

智能挂锁软件需求规格说明书(SRS)

智能挂锁系统SmartPadlockV1.0是一款融合蓝牙通信、指纹识别和远程控制技术的便携式安防设备。系统由设备端、移动App和云平台三部分组成,支持蓝牙配对(10米内)、指纹识别、OTP一次性密码等多种开锁方式,响应时间<1.5秒。产品采用SM2/SM4加密技术保障安全,日均20次使用下续航达180天,兼容iOS13+/Android8.0+系统。功能包括设备绑定、远程授权、开锁记录查询和OTA固件升级,符合个人信息保护法规要求,适用于仓储、快递柜等多场景应用。

moton2017的博客 2111

Android 自定义View基础(六)--ViewDragHelper(侧滑栏)

我们知道在Google在support的库中为我们提供了DrawerLayout和SlidingPanelLayout两个布局来实现侧滑栏的效果,这两个布局让我们实现侧滑的功能变的非常容易,其实这两个布局在内部,都有一个ViewDragHelper类,通过ViewDragHelper类基本可以实现各种不同的滑动,拖放需求:本文主要是讲述这个类,通过实现一个简单的例子来讲解,当滑动距离大于某个值的时候

Kenway090704的博客 1005

RT-DETR改进策略【卷积层】| ECCV-2024 小波卷积WTConv 增大感受野,降低参数量计算量,独家创新助力涨点

本文记录的是利用模块优化的目标检测网络模型。的目的是在不出现过参数化的情况下有效地增加卷积的感受野,从而解决了在感受野扩展中的参数膨胀问题。本文将其加入到深度可分离卷积中,有效降低模型参数量和计算量,并二次创新,使模块更好地捕捉低频特征,增强网络性能。Wavelet Convolutions for Large Receptive Fields小波卷积及其改进的实现代码如下: 四、创新模块 4.1 改进点1⭐ 模块改进方法:加入(第五节讲解添加步骤)。添加后如下:模块改进方法:基于的(第五节讲解添加步骤)

Limiiiing的博客 1503

深度强化学习 | 详解基于价值的强化学习DQN算法(附Pytorch实现)

深度Q网络DQN的核心原理是通过经验回放池和目标网络技术拟合高维状态空间,是Q-Learning算法的深度学习版本,本文分析DQN的基本算法,并给出训练实例和实际案例

FRIGIDWINTER的博客 4985

ViewDragHelper详解(侧滑栏)

乐观是一首激昂优美的进行曲,时刻鼓舞着你向事业的大路勇猛前进。——大仲马一、概述Drag拖拽;ViewDrag拖拽视图,拖拽控件;ViewDragHelper拖拽视图助手,拖拽操作类。利用ViewDragHelper类可以实现很多绚丽的效果,比如:拖拽删除,拖拽排序,侧滑栏等。本篇主要讲解简易侧滑栏的实现。注意:ViewDragHelper是作用在一个ViewGroup上,也就是说他不能直接作用到被

文淑的博客 1万+

杰理-tone

低音质格式切换高音质格式:切换提示音格式,未导出,编译下载没有提示音;提示音导出,再次编译下载,提示音正常高音质格式切换低音质格式:不需要导出,直接编译下载,提示音正常。

m0_67447112的博客 955

强大的ViewDragHelper和ViewDragHelper的妙用 一

文如其名,本篇博文我们将详细介绍强大的ViewDragHelper,但是这次我们将他们分开,本篇我们将完全解析 ViewDragHelper,下一篇我们我们将系统的说明ViewDragHelper的妙用       一般情况下,当我们希望我们的UI动起来(变得灵活的)的时候我们一般会首先想到在onInterceptTouchEvent 和OnTouchEvent做出配合处理,这样的话,我

大叔的愤怒,你驾驭不了 6044

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

ViewDragHelper实战 自己打造Drawerlayout

转载请标明出处: http://blog.youkuaiyun.com/lmj623565791/article/details/47396187; 本文出自:【张鸿洋的博客】 一、概述 在上一篇我们介绍了ViewDragHelper,详情:ViewDragHelper完全解析,当然了,上一篇都是小示例的形式去演示代码功能,并不能给人一种实用的感觉。那么,本篇博客就准备实用ViewDragH

Hongyang 4万+

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

ViewDragHelper简介

1,概述简单地来说,ViewDragHelper是一个实现滑动布局的辅助类。比如Google在support库中提供的DrawerLayout布局,就是用ViewDragHelper来实现的。 虽然现在有现成的滑动布局可以供我们使用,但是只有掌握ViewDragHelper的用法,我们才能够更加灵活地自定义我们需要的控件。 通常,ViewDragHelper用在一个自定义的ViewGroup中。

jialiang的博客 813

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

ViewDragHelper使用详解

一、基本介绍   前辈们已经总结的很多了,所以从别人的博客里直接复制的比较多,用到的源码我也会经过修改。用到的博客我会在下方注释。   最近发下一篇写的不错的ViewDragHelper的博客,比较清晰,调理,看完这一片再看下面的效果会更好点点击跳转。   2013年谷歌i/o大会上介绍了两个新的layout: SlidingPaneLayout和DrawerLayout,现在这俩个类...

zhangyalong_android的博客 3565

Viewdraghelper解析

Viewdraghelper解析 2013年谷歌i/o大会上介绍了两个新的layout: SlidingPaneLayout和DrawerLayout,现在这俩个类被广泛的运用, 其实研究他们的源码你会发现这两个类都运用了ViewDragHelper来处理拖动。ViewDragHelper是framework中非常有用的一个工具。 ViewDragHelper解决了

wxx614817的专栏 691

基于ViewDragHelper实现侧滑

ViewDragHelper 是一个非常强大的类 , 能够帮助我们这些新手处理复杂的手势问题。使用ViewDragHelper , 我们必须为其实现CallBack回调函数。 ViewDragHelper.Callback是连接ViewDragHelper与view之间的桥梁 上面这些方法,我们不必要完全实现。 tryCaptureView 方法 ,捕捉并确定我们要滑动的ViewclampVi

qq_35290457的博客 337
上一篇: Android ViewDragHelper完全解析 自定义ViewGroup神器
下一篇: Android使用ViewDragHelper实现仿QQ6.0侧滑界面(一)
千雅爸爸
博客等级 码龄18年 292粉丝 639原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值