13
13
* See the License for the specific language governing permissions and
14
14
* limitations under the License.
15
15
*/
16
-
17
16
package com .drakeet .drawer ;
18
17
19
18
import android .annotation .SuppressLint ;
20
19
import android .content .Context ;
21
20
import android .util .AttributeSet ;
22
21
import android .view .Gravity ;
23
22
import android .view .MotionEvent ;
24
- import android .view .VelocityTracker ;
25
23
import android .view .View ;
26
- import android .view .ViewConfiguration ;
27
- import android .view .ViewGroup ;
28
24
import android .view .ViewParent ;
29
25
import android .widget .FrameLayout ;
30
26
import androidx .annotation .NonNull ;
36
32
import java .lang .reflect .Method ;
37
33
import java .util .List ;
38
34
39
- import static java .lang .Math .abs ;
40
35
import static java .util .Objects .requireNonNull ;
41
36
42
37
/**
43
- * TODO: Add support for the right drawer
44
- * TODO: Add support for other kinds of drawer
45
- *
46
38
* @author Drakeet Xu
47
39
*/
48
- public class FullDraggableContainer extends FrameLayout {
49
-
50
- private float initialMotionX ;
51
- private float initialMotionY ;
52
- private float lastMotionX ;
53
- private float lastMotionY ;
54
- private final int touchSlop ;
55
- private final int swipeSlop ;
56
- private final int distanceThreshold ;
57
- private final int xVelocityThreshold ;
40
+ public class FullDraggableContainer extends FrameLayout implements FullDraggableHelper .Callback {
58
41
59
- private boolean isDraggingDrawer = false ;
60
- private boolean shouldOpenDrawer = false ;
42
+ @ NonNull
43
+ private final FullDraggableHelper helper ;
61
44
62
- @ Nullable
63
- private VelocityTracker velocityTracker = null ;
64
45
private DrawerLayout drawerLayout ;
65
- private int gravity = Gravity .NO_GRAVITY ;
66
46
67
47
public FullDraggableContainer (@ NonNull Context context ) {
68
48
this (context , null );
@@ -74,10 +54,7 @@ public FullDraggableContainer(@NonNull Context context, @Nullable AttributeSet a
74
54
75
55
public FullDraggableContainer (@ NonNull Context context , @ Nullable AttributeSet attrs , int defStyleAttr ) {
76
56
super (context , attrs , defStyleAttr );
77
- touchSlop = ViewConfiguration .get (context ).getScaledTouchSlop ();
78
- swipeSlop = dipsToPixels (8 );
79
- distanceThreshold = dipsToPixels (80 );
80
- xVelocityThreshold = dipsToPixels (150 );
57
+ helper = new FullDraggableHelper (context , this );
81
58
}
82
59
83
60
@ Override
@@ -96,131 +73,50 @@ private void ensureDrawerLayout() {
96
73
97
74
@ Override
98
75
public boolean onInterceptTouchEvent (MotionEvent event ) {
99
- boolean intercepted = false ;
100
- int action = event .getActionMasked ();
101
- float x = event .getX ();
102
- float y = event .getY ();
103
- if (action == MotionEvent .ACTION_DOWN ) {
104
- lastMotionX = initialMotionX = x ;
105
- lastMotionY = initialMotionY = y ;
106
- return false ;
107
- } else if (action == MotionEvent .ACTION_MOVE ) {
108
- if (canNestedViewScroll (this , false , (int ) (x - lastMotionX ), (int ) x , (int ) y )) {
109
- return false ;
110
- }
111
- lastMotionX = x ;
112
- float diffX = x - initialMotionX ;
113
- intercepted = abs (diffX ) > touchSlop
114
- && abs (diffX ) > abs (y - initialMotionY )
115
- && isDrawerEnabled (diffX );
116
- }
117
- return intercepted ;
76
+ return helper .onInterceptTouchEvent (event );
118
77
}
119
78
120
- private boolean canNestedViewScroll (View view , boolean checkSelf , int dx , int x , int y ) {
121
- if (view instanceof ViewGroup ) {
122
- ViewGroup group = (ViewGroup ) view ;
123
- int scrollX = view .getScrollX ();
124
- int scrollY = view .getScrollY ();
125
- int count = group .getChildCount ();
126
- for (int i = count - 1 ; i >= 0 ; i --) {
127
- View child = group .getChildAt (i );
128
- if (child .getVisibility () != View .VISIBLE ) continue ;
129
- if (x + scrollX >= child .getLeft ()
130
- && x + scrollX < child .getRight ()
131
- && y + scrollY >= child .getTop ()
132
- && y + scrollY < child .getBottom ()
133
- && canNestedViewScroll (child , true , dx , x + scrollX - child .getLeft (), y + scrollY - child .getTop ())) {
134
- return true ;
135
- }
136
- }
137
- }
138
- return checkSelf && view .canScrollHorizontally (-dx );
79
+ @ Override
80
+ @ SuppressLint ("ClickableViewAccessibility" )
81
+ public boolean onTouchEvent (MotionEvent event ) {
82
+ return helper .onTouchEvent (event );
139
83
}
140
84
85
+ @ NonNull
141
86
@ Override
142
- @ SuppressLint ({ "RtlHardcoded" , "ClickableViewAccessibility" })
143
- public boolean onTouchEvent (MotionEvent event ) {
144
- float x = event .getX ();
145
- int action = event .getActionMasked ();
146
- switch (action ) {
147
- case MotionEvent .ACTION_MOVE : {
148
- float diffX = x - initialMotionX ;
149
- if (isDrawerOpen () || !isDrawerEnabled (diffX )) {
150
- return false ;
151
- }
152
- float absDiffX = abs (diffX );
153
- if (absDiffX > swipeSlop || isDraggingDrawer ) {
154
- if (velocityTracker == null ) {
155
- velocityTracker = VelocityTracker .obtain ();
156
- }
157
- velocityTracker .addMovement (event );
158
- boolean lastDraggingDrawer = isDraggingDrawer ;
159
- isDraggingDrawer = true ;
160
- shouldOpenDrawer = absDiffX > distanceThreshold ;
87
+ public View getDrawerMainContainer () {
88
+ return this ;
89
+ }
161
90
162
- // Not allowed to change direction in a process
163
- if (gravity == Gravity .NO_GRAVITY ) {
164
- gravity = diffX > 0 ? Gravity .LEFT : Gravity .RIGHT ;
165
- }
166
- offsetDrawer (gravity , absDiffX - swipeSlop );
91
+ @ Override
92
+ public boolean isDrawerOpen (int gravity ) {
93
+ return drawerLayout .isDrawerOpen (gravity );
94
+ }
167
95
168
- if (!lastDraggingDrawer ) {
169
- notifyDrawerDragging ();
170
- }
171
- }
172
- return isDraggingDrawer ;
173
- }
174
- case MotionEvent .ACTION_CANCEL :
175
- case MotionEvent .ACTION_UP : {
176
- if (isDraggingDrawer ) {
177
- if (velocityTracker != null ) {
178
- velocityTracker .computeCurrentVelocity (1000 );
179
- float xVelocity = velocityTracker .getXVelocity ();
180
- boolean fromLeft = (gravity == Gravity .LEFT );
181
- if (xVelocity > xVelocityThreshold ) {
182
- shouldOpenDrawer = fromLeft ;
183
- } else if (xVelocity < -xVelocityThreshold ) {
184
- shouldOpenDrawer = !fromLeft ;
185
- }
186
- }
187
- if (shouldOpenDrawer ) {
188
- openDrawer (gravity );
189
- } else {
190
- dismissDrawer (gravity );
191
- }
192
- }
193
- shouldOpenDrawer = false ;
194
- isDraggingDrawer = false ;
195
- gravity = Gravity .NO_GRAVITY ;
196
- if (velocityTracker != null ) {
197
- velocityTracker .recycle ();
198
- velocityTracker = null ;
199
- }
200
- }
201
- }
202
- return true ;
96
+ @ Override
97
+ public boolean hasEnabledDrawer (int gravity ) {
98
+ return drawerLayout .getDrawerLockMode (gravity ) == DrawerLayout .LOCK_MODE_UNLOCKED
99
+ && findDrawerWithGravity (gravity ) != null ;
203
100
}
204
101
205
- @ SuppressLint ("RtlHardcoded" )
206
- private boolean isDrawerOpen () {
207
- return drawerLayout .isDrawerOpen (Gravity .LEFT ) || drawerLayout .isDrawerOpen (Gravity .RIGHT );
102
+ @ Override
103
+ public void offsetDrawer (int gravity , float offset ) {
104
+ setDrawerToOffset (gravity , offset );
105
+ drawerLayout .invalidate ();
208
106
}
209
107
210
- private void openDrawer (int gravity ) {
108
+ @ Override
109
+ public void smoothOpenDrawer (int gravity ) {
211
110
drawerLayout .openDrawer (gravity , true );
212
111
}
213
112
214
- private void dismissDrawer (int gravity ) {
113
+ @ Override
114
+ public void smoothCloseDrawer (int gravity ) {
215
115
drawerLayout .closeDrawer (gravity , true );
216
116
}
217
117
218
- private void offsetDrawer (int gravity , float dx ) {
219
- setDrawerToOffset (gravity , dx );
220
- drawerLayout .invalidate ();
221
- }
222
-
223
- private void notifyDrawerDragging () {
118
+ @ Override
119
+ public void onDrawerDragging () {
224
120
List <DrawerLayout .DrawerListener > drawerListeners = getDrawerListeners ();
225
121
if (drawerListeners != null ) {
226
122
int listenerCount = drawerListeners .size ();
@@ -243,13 +139,13 @@ protected List<DrawerLayout.DrawerListener> getDrawerListeners() {
243
139
}
244
140
}
245
141
246
- protected void setDrawerToOffset (int gravity , float dx ) {
142
+ protected void setDrawerToOffset (int gravity , float offset ) {
247
143
View drawerView = findDrawerWithGravity (gravity );
248
- float slideOffset = dx / requireNonNull (drawerView ).getWidth ();
144
+ float slideOffsetPercent = offset / requireNonNull (drawerView ).getWidth ();
249
145
try {
250
146
Method method = DrawerLayout .class .getDeclaredMethod ("moveDrawerToOffset" , View .class , float .class );
251
147
method .setAccessible (true );
252
- method .invoke (drawerLayout , drawerView , slideOffset );
148
+ method .invoke (drawerLayout , drawerView , slideOffsetPercent );
253
149
drawerView .setVisibility (VISIBLE );
254
150
} catch (Exception e ) {
255
151
// throw to let developer know the api is changed
@@ -277,20 +173,4 @@ private int getDrawerViewAbsoluteGravity(View drawerView) {
277
173
final int gravity = ((DrawerLayout .LayoutParams ) drawerView .getLayoutParams ()).gravity ;
278
174
return GravityCompat .getAbsoluteGravity (gravity , ViewCompat .getLayoutDirection (drawerLayout ));
279
175
}
280
-
281
- @ SuppressLint ("RtlHardcoded" )
282
- private boolean isDrawerEnabled (float diffX ) {
283
- return diffX > 0 && hasUnlockedDrawer (Gravity .LEFT )
284
- || diffX < 0 && hasUnlockedDrawer (Gravity .RIGHT );
285
- }
286
-
287
- private boolean hasUnlockedDrawer (int gravity ) {
288
- return drawerLayout .getDrawerLockMode (gravity ) == DrawerLayout .LOCK_MODE_UNLOCKED
289
- && findDrawerWithGravity (gravity ) != null ;
290
- }
291
-
292
- private int dipsToPixels (int dips ) {
293
- float scale = getContext ().getResources ().getDisplayMetrics ().density ;
294
- return (int ) (dips * scale + 0.5f );
295
- }
296
176
}
0 commit comments