API design
FLAVIEN LAURENT
The Android Framework, step by step
Each Navigation Drawer Hides a ViewDragHelperAug 28th, 2013 6:56 pmRecently, at the Google I/O 2013, two new layouts have been introduced:SlidingPaneLayout
, a view that can be dragged from bottom to top and vice versa and theDrawerLayout
, now used in almost all Google applications. Both of these use a new concept to more easily manage dragging: the ViewDragHelper.In this article, I’m going to talk about the ViewDragHelper (aka VDH) because making a custom layout with dragging child view may be pain sometimes. First, I will show you how to use it and how it works (the main lines). Secondly, I will expose you a use case where the VDH is really useful.Download Sample Application
IN A FEW WORDS
There are some important points to remember about VDH:
- a
ViewDragHelper.Callback
is used as a communication channel between parent view and VDH - there is a static factory method to create a VDH instance
- you can configure the drag direction as you want
- a drag can be detected from edge even if there is no view to capture (left, right, top, bottom)
- a
Remember to read the official documentation: ViewDragHelper and ViewDragHelper.Callback
READING THE SOURCE CODE
The VDH and its callback are available in the support-v4 library. You can read the source code : ViewDragHelper and ViewDragHelper.Callback.
It uses some common classes of the framework : a VelocityTracker for tracking fingling and other touch events and a Scroller to scroll views when it’s needed.
You must read the source code as much as possible because first, it’s very interesting and then if you know how it works, you will be able to use it in a better way.
Using the VDH
In this section, I’m going to show you a few examples of what is possible to configure on a VDH. Let’s begin with some initializations and then, I will explain a few possible configurations.
VDH’S INITIALIZATION
A custom
ViewGroup
extending aLinearLayout
(DragLayout
) with a simple childView
(namedmDragView
).
根据外国牛人的友好教程 http://t.cn/z8UbEqU
写了仿Youtube的视频拖动控件Demo。
源码地址:http://t.cn/z85JHtq
APK体验下载地址:http://t.cn/z85JHtG
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16Create a VDH with its callback. Note that you can specify the sensivity (official documentation says Multiplier for how sensitive the helper should be about detecting the start of a drag. Larger values are more sensitive. 1.0f is normal.)
1 2 3 4 5The most important, don’t forget to call VDH methods in
onInterceptTouch
andonTouch
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16Now, you can change the VDH behavior just by configuring the callback.
HORIZONTAL ONLY
Implements
clampViewPositionHorizontal
to allow horizontal drag and to bound the drag motion. Note that documentation says The default implementation does not allow horizontal motion.You have to take margins and parent padding into consideration.
1 2 3 4 5 6 7 8 9 10 11 12
VERTICAL ONLY
Implements
clampViewPositionVertical
to allow horizontal drag and to bound the drag motion. Note that documentation says The default implementation does not allow vertical motion.You have to take margins and parent padding into consideration. Not like in the code below
1 2 3 4 5 6 7 8 9
CAPTURE OR NOT CAPTURE A VIEW
Implements
tryCaptureView
to allow a child view to be captured. Here, there are two child views (mDragView1
andmDragView2
) but only one (mDragView1
) is draggable.
1 2 3 4
DRAGRANGE
Implements
getViewHorizontalDragRange
orgetViewVerticalDragRange
to returns the range of horizontal|vertical drag in pixels. This range is used by the VDH when you callsmoothSlideViewTo
orsettleCapturedViewAt
to calculate the scroll duration. Also, it’s used to check the horizontal|vertical touch slop.EDGE DRAGGING
This feature is used in the
DrawerLayout
withEDGE_LEFT
andEDGE_RIGHT
.Configure the VDH to enable edge tracking.
1
Implements
onEdgeTouched
called when the configured edge is touched. Note that at this time, no child view is currently captured.
1 2 3 4 5Implements
onEdgeDragStarted
called when a real drag from the configured edge has started. Note that at this time, no child view is currently captured. In this method, you have to capture a child view manually.
1 2 3 4
A REAL EXAMPLE, THE YOUTUBE WHILE PLAYING LAYOUT
Recently, I’ve received an update of the Youtube app on my phone. Before this update, the most annoying thing was to not be able to watch a video and search the next video at the same time. They fixed this by implementing a nice layout in which you can minimize the video view from top to bottom.
I’m going to show how to do it and how it’s simple thanks to VDH.
Here is the expected result
Key points:
-
tryCaptureView
returns true only for the header view - drag range is calculated
onLayout
- use VDH’s methods in
onInterceptTouchEvent
andonTouchEvent
- call
continueSettling
incomputeScroll
(because VDH uses a scroller) - use
smoothSlideViewTo
to finish the drag motion
-
Be careful, this layout is not well made: it’s a draft. There is still work to do; on the scale part, touch event when the header is scaled,
onLayout
andonMeasure
are badly written too. Also, I don’t know if callingrequestLayout
inonViewPositionChanged
is good solution… Anyway, if you have remarks or ideas to improve this layout, please tell me!).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 39 40 41 42 43 44 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 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">
name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">
name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">
name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">
name="oauth2relay612174205" id="oauth2relay612174205" src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=http%3A%2F%2Fflavienlaurent.com#rpctoken=731950870&forcesecure=1" tabindex="-1" style="text-align: center; margin: 0px; padding: 0px; border-width: 0px; font-family: 'PT Serif', Georgia, Times, 'Times New Roman', serif; line-height: 20px; font-size: 20px; vertical-align: baseline; color: rgb(51, 51, 51); width: 1px; height: 1px; position: absolute; top: -100px;">