Skip to content

Commit 244f91f

Browse files
authored
Add support for other kinds of drawer (#2)
Add a `FullDraggableHelper` to hold the reusable part so that we can use it for other kinds of drawers. * Make _drawerlayout_ as an optional and `compileOnly` dependency * Rename `dismissDrawer` to `smoothCloseDrawer` * Bump to 1.0.0
1 parent 86f838b commit 244f91f

File tree

7 files changed

+243
-161
lines changed

7 files changed

+243
-161
lines changed

README.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ In your `build.gradle`:
1212

1313
```groovy
1414
dependencies {
15-
implementation 'com.drakeet.drawer:drawer:0.9.0'
15+
implementation 'com.drakeet.drawer:drawer:1.0.0'
16+
// Optional: No need if you just use the FullDraggableHelper
17+
implementation 'androidx.drawerlayout:drawerlayout:1.1.1'
1618
}
1719
```
1820

@@ -50,10 +52,14 @@ Replace the main Layout of `DrawerLayout` with the `FullDraggableContainer` (or
5052

5153
**That's all, you're good to go!**
5254

55+
### Advanced usage
56+
57+
See `com.drakeet.drawer.FullDraggableHelper`
58+
5359
## TODO
5460

5561
- [x] Add support for the right drawer / RTL
56-
- [ ] Add support for other kinds of drawer
62+
- [x] Add support for other kinds of drawer
5763

5864
License
5965
-------

build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
buildscript {
1818

1919
ext.kotlinVersion = '1.4.21'
20-
ext.buildConfig = ['versionCode' : 2,
21-
'versionName' : "0.9.1",
20+
ext.buildConfig = ['versionCode' : 3,
21+
'versionName' : "1.0.0",
2222
'compileSdkVersion': 30,
2323
'minSdkVersion' : 19,
2424
'targetSdkVersion' : 30]

library/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ android {
3434
}
3535

3636
dependencies {
37-
api 'androidx.drawerlayout:drawerlayout:1.1.1'
37+
compileOnly 'androidx.drawerlayout:drawerlayout:1.1.1'
3838
testImplementation 'junit:junit:4.13.1'
3939
}

library/gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ POM_PACKAGING=aar
2020

2121
GROUP=com.drakeet.drawer
2222

23-
POM_DESCRIPTION=Easier and more flexible to create multiple types for Android RecyclerView.
23+
POM_DESCRIPTION=Make Android DrawerLayout can be dragged out in real-time within the range of fullscreen.
2424
POM_URL=https://github.com/PureWriter/FullDraggableDrawer
2525
POM_SCM_URL=https://github.com/PureWriter/FullDraggableDrawer
2626
POM_SCM_CONNECTION=scm:git@github.com:PureWriter/FullDraggableDrawer.git

library/src/main/java/com/drakeet/drawer/FullDraggableContainer.java

+34-154
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,14 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package com.drakeet.drawer;
1817

1918
import android.annotation.SuppressLint;
2019
import android.content.Context;
2120
import android.util.AttributeSet;
2221
import android.view.Gravity;
2322
import android.view.MotionEvent;
24-
import android.view.VelocityTracker;
2523
import android.view.View;
26-
import android.view.ViewConfiguration;
27-
import android.view.ViewGroup;
2824
import android.view.ViewParent;
2925
import android.widget.FrameLayout;
3026
import androidx.annotation.NonNull;
@@ -36,33 +32,17 @@
3632
import java.lang.reflect.Method;
3733
import java.util.List;
3834

39-
import static java.lang.Math.abs;
4035
import static java.util.Objects.requireNonNull;
4136

4237
/**
43-
* TODO: Add support for the right drawer
44-
* TODO: Add support for other kinds of drawer
45-
*
4638
* @author Drakeet Xu
4739
*/
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 {
5841

59-
private boolean isDraggingDrawer = false;
60-
private boolean shouldOpenDrawer = false;
42+
@NonNull
43+
private final FullDraggableHelper helper;
6144

62-
@Nullable
63-
private VelocityTracker velocityTracker = null;
6445
private DrawerLayout drawerLayout;
65-
private int gravity = Gravity.NO_GRAVITY;
6646

6747
public FullDraggableContainer(@NonNull Context context) {
6848
this(context, null);
@@ -74,10 +54,7 @@ public FullDraggableContainer(@NonNull Context context, @Nullable AttributeSet a
7454

7555
public FullDraggableContainer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
7656
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);
8158
}
8259

8360
@Override
@@ -96,131 +73,50 @@ private void ensureDrawerLayout() {
9673

9774
@Override
9875
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);
11877
}
11978

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);
13983
}
14084

85+
@NonNull
14186
@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+
}
16190

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+
}
16795

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;
203100
}
204101

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();
208106
}
209107

210-
private void openDrawer(int gravity) {
108+
@Override
109+
public void smoothOpenDrawer(int gravity) {
211110
drawerLayout.openDrawer(gravity, true);
212111
}
213112

214-
private void dismissDrawer(int gravity) {
113+
@Override
114+
public void smoothCloseDrawer(int gravity) {
215115
drawerLayout.closeDrawer(gravity, true);
216116
}
217117

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() {
224120
List<DrawerLayout.DrawerListener> drawerListeners = getDrawerListeners();
225121
if (drawerListeners != null) {
226122
int listenerCount = drawerListeners.size();
@@ -243,13 +139,13 @@ protected List<DrawerLayout.DrawerListener> getDrawerListeners() {
243139
}
244140
}
245141

246-
protected void setDrawerToOffset(int gravity, float dx) {
142+
protected void setDrawerToOffset(int gravity, float offset) {
247143
View drawerView = findDrawerWithGravity(gravity);
248-
float slideOffset = dx / requireNonNull(drawerView).getWidth();
144+
float slideOffsetPercent = offset / requireNonNull(drawerView).getWidth();
249145
try {
250146
Method method = DrawerLayout.class.getDeclaredMethod("moveDrawerToOffset", View.class, float.class);
251147
method.setAccessible(true);
252-
method.invoke(drawerLayout, drawerView, slideOffset);
148+
method.invoke(drawerLayout, drawerView, slideOffsetPercent);
253149
drawerView.setVisibility(VISIBLE);
254150
} catch (Exception e) {
255151
// throw to let developer know the api is changed
@@ -277,20 +173,4 @@ private int getDrawerViewAbsoluteGravity(View drawerView) {
277173
final int gravity = ((DrawerLayout.LayoutParams) drawerView.getLayoutParams()).gravity;
278174
return GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(drawerLayout));
279175
}
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-
}
296176
}

0 commit comments

Comments
 (0)