Skip to content

Commit 19b7dfc

Browse files
committed
refactor(filetree): implement double-tap-to-drag gesture to resolve scroll conflicts
1 parent f7401e9 commit 19b7dfc

File tree

1 file changed

+47
-49
lines changed

1 file changed

+47
-49
lines changed
Lines changed: 47 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,47 @@
11
package com.unnamed.b.atv.view;
22

33
import android.annotation.SuppressLint;
4+
import android.view.GestureDetector;
45
import android.view.HapticFeedbackConstants;
56
import android.view.MotionEvent;
67
import android.view.View;
7-
import android.view.ViewConfiguration;
8+
9+
import androidx.annotation.NonNull;
10+
811
import com.unnamed.b.atv.model.TreeNode;
912

1013
class NodeTouchHandler implements View.OnTouchListener {
1114

1215
private final TreeNode node;
1316
private final View view;
1417
private final TreeNode.TreeNodeDragListener defaultDragListener;
15-
private final int touchSlop;
16-
private final long longPressTimeout;
17-
18-
private float startX, startY;
19-
private boolean isDragging = false;
20-
private boolean isLongPressFired = false;
18+
private final GestureDetector gestureDetector;
2119

22-
private final Runnable longPressRunnable;
20+
private boolean isAwaitingDrag = false;
2321

2422
NodeTouchHandler(TreeNode node, View view, TreeNode.TreeNodeDragListener defaultDragListener) {
2523
this.node = node;
2624
this.view = view;
2725
this.defaultDragListener = defaultDragListener;
28-
this.touchSlop = ViewConfiguration.get(view.getContext()).getScaledTouchSlop();
29-
this.longPressTimeout = ViewConfiguration.getLongPressTimeout();
30-
31-
this.longPressRunnable = () -> {
32-
isLongPressFired = true;
33-
this.view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
34-
this.view.performLongClick();
35-
};
26+
27+
this.gestureDetector = new GestureDetector(view.getContext(), new GestureListener());
28+
this.gestureDetector.setIsLongpressEnabled(true);
3629
}
3730

3831
@SuppressLint("ClickableViewAccessibility")
3932
@Override
4033
public boolean onTouch(View v, MotionEvent event) {
41-
switch (event.getAction()) {
42-
case MotionEvent.ACTION_DOWN:
43-
startX = event.getX();
44-
startY = event.getY();
45-
isDragging = isLongPressFired = false;
46-
view.setPressed(true);
47-
view.postDelayed(longPressRunnable, longPressTimeout);
48-
return true;
34+
gestureDetector.onTouchEvent(event);
4935

50-
case MotionEvent.ACTION_MOVE:
51-
if (isDragging || isLongPressFired) break;
52-
53-
float dx = Math.abs(event.getX() - startX);
54-
float dy = Math.abs(event.getY() - startY);
55-
56-
if (dx > (touchSlop * 2) || dy > (touchSlop * 2)) {
57-
isDragging = true;
58-
cancelPendingAction();
59-
dispatchDrag();
60-
}
61-
break;
62-
63-
case MotionEvent.ACTION_UP:
64-
case MotionEvent.ACTION_CANCEL:
65-
if (!isDragging && !isLongPressFired && event.getAction() == MotionEvent.ACTION_UP) {
66-
view.performClick();
67-
}
68-
cancelPendingAction();
69-
break;
36+
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
37+
isAwaitingDrag = false;
38+
view.setPressed(false);
39+
} else if (event.getAction() == MotionEvent.ACTION_MOVE && isAwaitingDrag) {
40+
isAwaitingDrag = false;
41+
dispatchDrag();
7042
}
71-
return true;
72-
}
7343

74-
private void cancelPendingAction() {
75-
view.setPressed(false);
76-
view.removeCallbacks(longPressRunnable);
44+
return true;
7745
}
7846

7947
private void dispatchDrag() {
@@ -82,7 +50,37 @@ private void dispatchDrag() {
8250
: defaultDragListener;
8351

8452
if (listener != null) {
53+
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
8554
listener.onStartDrag(node, node.getValue());
8655
}
8756
}
57+
58+
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
59+
@Override
60+
public boolean onDown(@NonNull MotionEvent e) {
61+
view.setPressed(true);
62+
return true;
63+
}
64+
65+
@Override
66+
public boolean onSingleTapConfirmed(@NonNull MotionEvent e) {
67+
view.performClick();
68+
return true;
69+
}
70+
71+
@Override
72+
public void onLongPress(@NonNull MotionEvent e) {
73+
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
74+
view.performLongClick();
75+
}
76+
77+
@Override
78+
public boolean onDoubleTapEvent(MotionEvent e) {
79+
if (e.getAction() == MotionEvent.ACTION_DOWN) {
80+
isAwaitingDrag = true;
81+
return true;
82+
}
83+
return super.onDoubleTapEvent(e);
84+
}
85+
}
8886
}

0 commit comments

Comments
 (0)