From a9575cf67fbe823924b92533dfa33f2924a53b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=8A=B2=E9=B9=8F?= Date: Fri, 17 Jun 2022 15:44:17 +0800 Subject: [PATCH] Android: implements list drag feature --- .../java/pub/doric/shader/list/ListNode.java | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/doric-android/doric/src/main/java/pub/doric/shader/list/ListNode.java b/doric-android/doric/src/main/java/pub/doric/shader/list/ListNode.java index 7962cffb..1fe63ac6 100644 --- a/doric-android/doric/src/main/java/pub/doric/shader/list/ListNode.java +++ b/doric-android/doric/src/main/java/pub/doric/shader/list/ListNode.java @@ -23,6 +23,8 @@ import android.view.MotionEvent; import android.view.View; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -76,6 +78,38 @@ public class ListNode extends SuperNode implements IDoricScrollabl private boolean scrollable = true; + private final DoricItemTouchHelperCallback doricItemTouchHelperCallback = new DoricItemTouchHelperCallback( + new OnItemTouchCallbackListener() { + @Override + public void onSwiped(int adapterPosition) { + + } + + @Override + public boolean onMove(int srcPosition, int targetPosition) { + String srcValue = itemValues.valueAt(srcPosition); + String targetValue = itemValues.valueAt(targetPosition); + itemValues.setValueAt(srcPosition, targetValue); + itemValues.setValueAt(targetPosition, srcValue); + listAdapter.notifyItemMoved(srcPosition, targetPosition); + if (!TextUtils.isEmpty(onDraggingFuncId)) { + callJSResponse(onDraggingFuncId, srcPosition, targetPosition); + } + return true; + } + + @Override + public void onMoved(int fromPos, int toPos) { + if (!TextUtils.isEmpty(onDraggedFuncId)) { + callJSResponse(onDraggedFuncId, fromPos, toPos); + } + } + } + ); + + private String onDraggingFuncId; + private String onDraggedFuncId; + @Override protected void blendSubNode(JSObject subProperties) { String viewId = subProperties.getProperty("id").asString().value(); @@ -162,6 +196,11 @@ public class ListNode extends SuperNode implements IDoricScrollabl return gestureDetector.onTouchEvent(e); } }); + + DoricItemTouchHelper doricItemTouchHelper = new DoricItemTouchHelper(doricItemTouchHelperCallback); + + doricItemTouchHelper.attachToRecyclerView(recyclerView); + return recyclerView; } @@ -249,6 +288,25 @@ public class ListNode extends SuperNode implements IDoricScrollabl } }); break; + case "canDrag": + if (!prop.isBoolean()) { + return; + } + boolean canDrag = prop.asBoolean().value(); + doricItemTouchHelperCallback.setDragEnable(canDrag); + break; + case "onDragging": + if (!prop.isString()) { + return; + } + this.onDraggingFuncId = prop.asString().value(); + break; + case "onDragged": + if (!prop.isString()) { + return; + } + this.onDraggedFuncId = prop.asString().value(); + break; default: super.blend(view, name, prop); break; @@ -362,5 +420,120 @@ public class ListNode extends SuperNode implements IDoricScrollabl onScrollFuncId = null; onScrollEndFuncId = null; renderItemFuncId = null; + onDraggedFuncId = null; + onDraggingFuncId = null; } + + private static class DoricItemTouchHelper extends ItemTouchHelper { + + /** + * Creates an ItemTouchHelper that will work with the given Callback. + *

+ * You can attach ItemTouchHelper to a RecyclerView via + * {@link #attachToRecyclerView(RecyclerView)}. Upon attaching, it will add an item decoration, + * an onItemTouchListener and a Child attach / detach listener to the RecyclerView. + * + * @param callback The Callback which controls the behavior of this touch helper. + */ + public DoricItemTouchHelper(@NonNull Callback callback) { + super(callback); + } + } + + private static class DoricItemTouchHelperCallback extends ItemTouchHelper.Callback { + + private OnItemTouchCallbackListener onItemTouchCallbackListener; + + private boolean isCanDrag = false; + private boolean isCanSwipe = false; + + private int fromPos; + private int toPos; + + public DoricItemTouchHelperCallback(OnItemTouchCallbackListener onItemTouchCallbackListener) { + this.onItemTouchCallbackListener = onItemTouchCallbackListener; + } + + public void setOnItemTouchCallbackListener(OnItemTouchCallbackListener onItemTouchCallbackListener) { + this.onItemTouchCallbackListener = onItemTouchCallbackListener; + } + + public void setDragEnable(boolean canDrag) { + isCanDrag = canDrag; + } + + public void setSwipeEnable(boolean canSwipe) { + isCanSwipe = canSwipe; + } + + @Override + public boolean isLongPressDragEnabled() { + return isCanDrag; + } + + @Override + + public boolean isItemViewSwipeEnabled() { + return isCanSwipe; + } + + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); + if (layoutManager instanceof LinearLayoutManager) { + LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; + int orientation = linearLayoutManager.getOrientation(); + int dragFlag = 0; + int swipeFlag = 0; + if (orientation == LinearLayoutManager.VERTICAL) { + dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN; + swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; + } + return makeMovementFlags(dragFlag, swipeFlag); + } + return 0; + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { + if (onItemTouchCallbackListener != null) { + return onItemTouchCallbackListener.onMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); + } + return false; + } + + @Override + public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) { + super.onSelectedChanged(viewHolder, actionState); + if (viewHolder != null) { + fromPos = viewHolder.getAdapterPosition(); + } + } + + @Override + public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + toPos = viewHolder.getAdapterPosition(); + + if (onItemTouchCallbackListener != null) { + onItemTouchCallbackListener.onMoved(fromPos, toPos); + } + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { + if (onItemTouchCallbackListener != null) { + onItemTouchCallbackListener.onSwiped(viewHolder.getAdapterPosition()); + } + } + } + + private interface OnItemTouchCallbackListener { + void onSwiped(int adapterPosition); + + boolean onMove(int srcPosition, int targetPosition); + + void onMoved(int fromPos, int toPos); + } + }