mirror of
https://github.com/M66B/FairEmail.git
synced 2026-01-02 19:10:11 +01:00
Updated recyclerview-selection: to version 1.1.0-alpha05
This commit is contained in:
@@ -348,7 +348,7 @@ public class DefaultSelectionTracker<K> extends SelectionTracker<K> {
|
||||
}
|
||||
|
||||
@Override
|
||||
AdapterDataObserver getAdapterDataObserver() {
|
||||
protected AdapterDataObserver getAdapterDataObserver() {
|
||||
return mAdapterObserver;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ package androidx.recyclerview.selection;
|
||||
import static androidx.core.util.Preconditions.checkArgument;
|
||||
import static androidx.core.util.Preconditions.checkState;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -27,6 +26,7 @@ import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
|
||||
|
||||
@@ -41,12 +41,11 @@ final class GestureSelectionHelper implements OnItemTouchListener {
|
||||
private static final String TAG = "GestureSelectionHelper";
|
||||
|
||||
private final SelectionTracker<?> mSelectionMgr;
|
||||
private final ItemDetailsLookup<?> mDetailsLookup;
|
||||
private final SelectionTracker.SelectionPredicate<?> mSelectionPredicate;
|
||||
private final AutoScroller mScroller;
|
||||
private final ViewDelegate mView;
|
||||
private final OperationMonitor mLock;
|
||||
|
||||
private int mLastStartedItemPos = RecyclerView.NO_POSITION;
|
||||
private boolean mStarted = false;
|
||||
|
||||
/**
|
||||
@@ -55,19 +54,19 @@ final class GestureSelectionHelper implements OnItemTouchListener {
|
||||
*/
|
||||
GestureSelectionHelper(
|
||||
@NonNull SelectionTracker<?> selectionTracker,
|
||||
@NonNull ItemDetailsLookup<?> detailsLookup,
|
||||
@NonNull SelectionPredicate<?> selectionPredicate,
|
||||
@NonNull ViewDelegate view,
|
||||
@NonNull AutoScroller scroller,
|
||||
@NonNull OperationMonitor lock) {
|
||||
|
||||
checkArgument(selectionTracker != null);
|
||||
checkArgument(detailsLookup != null);
|
||||
checkArgument(selectionPredicate != null);
|
||||
checkArgument(view != null);
|
||||
checkArgument(scroller != null);
|
||||
checkArgument(lock != null);
|
||||
|
||||
mSelectionMgr = selectionTracker;
|
||||
mDetailsLookup = detailsLookup;
|
||||
mSelectionPredicate = selectionPredicate;
|
||||
mView = view;
|
||||
mScroller = scroller;
|
||||
mLock = lock;
|
||||
@@ -78,16 +77,9 @@ final class GestureSelectionHelper implements OnItemTouchListener {
|
||||
*/
|
||||
void start() {
|
||||
checkState(!mStarted);
|
||||
// See: b/70518185. It appears start() is being called via onLongPress
|
||||
// even though we never received an intial handleInterceptedDownEvent
|
||||
// where we would usually initialize mLastStartedItemPos.
|
||||
if (mLastStartedItemPos == RecyclerView.NO_POSITION) {
|
||||
Log.w(TAG, "Illegal state. Can't start without valid mLastStartedItemPos.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Partner code in MotionInputHandler ensures items
|
||||
// are selected and range established prior to
|
||||
// are selected and range anchor initialized prior to
|
||||
// start being called.
|
||||
// Verify the truth of that statement here
|
||||
// to make the implicit coupling less of a time bomb.
|
||||
@@ -102,20 +94,14 @@ final class GestureSelectionHelper implements OnItemTouchListener {
|
||||
@Override
|
||||
/** @hide */
|
||||
public boolean onInterceptTouchEvent(@NonNull RecyclerView unused, @NonNull MotionEvent e) {
|
||||
if (MotionEvents.isMouseEvent(e)) {
|
||||
if (Shared.DEBUG) Log.w(TAG, "Unexpected Mouse event. Check configuration.");
|
||||
switch (e.getActionMasked()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
return mStarted;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(b/109808552): It seems that mLastStartedItemPos should likely be set as a method
|
||||
// parameter in start().
|
||||
if (e.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||
if (mDetailsLookup.getItemDetails(e) != null) {
|
||||
mLastStartedItemPos = mView.getItemUnder(e);
|
||||
}
|
||||
}
|
||||
|
||||
// See handleTouch(MotionEvent) javadoc for explanation as to why this is correct.
|
||||
return handleTouch(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,6 +132,14 @@ final class GestureSelectionHelper implements OnItemTouchListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mSelectionMgr.isRangeActive()) {
|
||||
Log.e(TAG,
|
||||
"Internal state of GestureSelectionHelper out of sync w/ SelectionTracker "
|
||||
+ "(isRangeActive is false). Ignoring event and resetting state.");
|
||||
endSelection();
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (e.getActionMasked()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
handleMoveEvent(e);
|
||||
@@ -172,9 +166,6 @@ final class GestureSelectionHelper implements OnItemTouchListener {
|
||||
private void handleUpEvent() {
|
||||
mSelectionMgr.mergeProvisionalSelection();
|
||||
endSelection();
|
||||
if (mLastStartedItemPos != RecyclerView.NO_POSITION) {
|
||||
mSelectionMgr.startRange(mLastStartedItemPos);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when ACTION_CANCEL event is to be handled.
|
||||
@@ -188,7 +179,6 @@ final class GestureSelectionHelper implements OnItemTouchListener {
|
||||
private void endSelection() {
|
||||
checkState(mStarted);
|
||||
|
||||
mLastStartedItemPos = RecyclerView.NO_POSITION;
|
||||
mStarted = false;
|
||||
mScroller.reset();
|
||||
mLock.stop();
|
||||
@@ -197,14 +187,12 @@ final class GestureSelectionHelper implements OnItemTouchListener {
|
||||
// Call when an intercepted ACTION_MOVE event is passed down.
|
||||
// At this point, we are sure user wants to gesture multi-select.
|
||||
private void handleMoveEvent(@NonNull MotionEvent e) {
|
||||
Point lastInterceptedPoint = MotionEvents.getOrigin(e);
|
||||
|
||||
int lastGlidedItemPos = mView.getLastGlidedItemPosition(e);
|
||||
if (lastGlidedItemPos != RecyclerView.NO_POSITION) {
|
||||
if (mSelectionPredicate.canSetStateAtPosition(lastGlidedItemPos, true)) {
|
||||
extendSelection(lastGlidedItemPos);
|
||||
}
|
||||
|
||||
mScroller.scroll(lastInterceptedPoint);
|
||||
mScroller.scroll(MotionEvents.getOrigin(e));
|
||||
}
|
||||
|
||||
// It's possible for events to go over the top/bottom of the RecyclerView.
|
||||
@@ -232,14 +220,14 @@ final class GestureSelectionHelper implements OnItemTouchListener {
|
||||
*/
|
||||
static GestureSelectionHelper create(
|
||||
@NonNull SelectionTracker<?> selectionMgr,
|
||||
@NonNull ItemDetailsLookup<?> detailsLookup,
|
||||
@NonNull SelectionPredicate<?> selectionPredicate,
|
||||
@NonNull RecyclerView recyclerView,
|
||||
@NonNull AutoScroller scroller,
|
||||
@NonNull OperationMonitor lock) {
|
||||
|
||||
return new GestureSelectionHelper(
|
||||
selectionMgr,
|
||||
detailsLookup,
|
||||
selectionPredicate,
|
||||
new RecyclerViewDelegate(recyclerView),
|
||||
scroller,
|
||||
lock);
|
||||
|
||||
@@ -33,7 +33,7 @@ import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -84,7 +84,7 @@ final class GridModel<K> {
|
||||
|
||||
// Array passed to registered OnSelectionChangedListeners. One array is created and reused
|
||||
// throughout the lifetime of the object.
|
||||
private final Set<K> mSelection = new HashSet<>();
|
||||
private final Set<K> mSelection = new LinkedHashSet<>();
|
||||
|
||||
// The current pointer (in absolute positioning from the top of the view).
|
||||
private Point mPointer;
|
||||
@@ -259,7 +259,7 @@ final class GridModel<K> {
|
||||
private void updateModel() {
|
||||
RelativePoint old = mRelPointer;
|
||||
mRelPointer = createRelativePoint(mPointer);
|
||||
if (old != null && mRelPointer.equals(old)) {
|
||||
if (mRelPointer.equals(old)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package androidx.recyclerview.selection;
|
||||
|
||||
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RestrictTo;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
@@ -67,8 +70,10 @@ public abstract class ItemDetailsLookup<K> {
|
||||
|
||||
/**
|
||||
* @return true if there is an item w/ a stable ID at the event coordinates.
|
||||
* @hide
|
||||
*/
|
||||
final boolean overItemWithSelectionKey(@NonNull MotionEvent e) {
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
protected boolean overItemWithSelectionKey(@NonNull MotionEvent e) {
|
||||
return overItem(e) && hasSelectionKey(getItemDetails(e));
|
||||
}
|
||||
|
||||
|
||||
@@ -33,18 +33,10 @@ final class MotionEvents {
|
||||
return e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE;
|
||||
}
|
||||
|
||||
static boolean isTouchEvent(@NonNull MotionEvent e) {
|
||||
return e.getToolType(0) == MotionEvent.TOOL_TYPE_FINGER;
|
||||
}
|
||||
|
||||
static boolean isActionMove(@NonNull MotionEvent e) {
|
||||
return e.getActionMasked() == MotionEvent.ACTION_MOVE;
|
||||
}
|
||||
|
||||
static boolean isActionDown(@NonNull MotionEvent e) {
|
||||
return e.getActionMasked() == MotionEvent.ACTION_DOWN;
|
||||
}
|
||||
|
||||
static boolean isActionUp(@NonNull MotionEvent e) {
|
||||
return e.getActionMasked() == MotionEvent.ACTION_UP;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ abstract class MotionInputHandler<K> extends SimpleOnGestureListener {
|
||||
mFocusDelegate.focusItem(details);
|
||||
}
|
||||
|
||||
final boolean isRangeExtension(@NonNull MotionEvent e) {
|
||||
final boolean shouldExtendRange(@NonNull MotionEvent e) {
|
||||
return MotionEvents.isShiftKeyPressed(e)
|
||||
&& mSelectionTracker.isRangeActive()
|
||||
// Without full corpus access we can't reliably implement range
|
||||
|
||||
@@ -126,7 +126,7 @@ final class MouseInputHandler<K> extends MotionInputHandler<K> {
|
||||
checkState(mSelectionTracker.hasSelection());
|
||||
checkArgument(item != null);
|
||||
|
||||
if (isRangeExtension(e)) {
|
||||
if (shouldExtendRange(e)) {
|
||||
extendSelectionRange(item);
|
||||
} else {
|
||||
if (shouldClearSelection(e, item)) {
|
||||
|
||||
@@ -19,9 +19,9 @@ package androidx.recyclerview.selection;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -65,8 +65,8 @@ public class Selection<K> implements Iterable<K> {
|
||||
final Set<K> mProvisionalSelection;
|
||||
|
||||
Selection() {
|
||||
mSelection = new HashSet<>();
|
||||
mProvisionalSelection = new HashSet<>();
|
||||
mSelection = new LinkedHashSet<>();
|
||||
mProvisionalSelection = new LinkedHashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ public class Selection<K> implements Iterable<K> {
|
||||
*/
|
||||
Selection(@NonNull Set<K> selection) {
|
||||
mSelection = selection;
|
||||
mProvisionalSelection = new HashSet<>();
|
||||
mProvisionalSelection = new LinkedHashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +117,7 @@ public class Selection<K> implements Iterable<K> {
|
||||
* @return Map of ids added or removed. Added ids have a value of true, removed are false.
|
||||
*/
|
||||
Map<K, Boolean> setProvisionalSelection(@NonNull Set<K> newSelection) {
|
||||
Map<K, Boolean> delta = new HashMap<>();
|
||||
Map<K, Boolean> delta = new LinkedHashMap<>();
|
||||
|
||||
for (K key: mProvisionalSelection) {
|
||||
// Mark each item that used to be in the provisional selection
|
||||
@@ -128,7 +128,7 @@ public class Selection<K> implements Iterable<K> {
|
||||
}
|
||||
|
||||
for (K key: mSelection) {
|
||||
// Mark each item that used to be in the selection but is unsaved and not in the new
|
||||
// Mark each item that in the selection but is not in the new
|
||||
// provisional selection.
|
||||
if (!newSelection.contains(key)) {
|
||||
delta.put(key, false);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package androidx.recyclerview.selection;
|
||||
|
||||
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
|
||||
import static androidx.core.util.Preconditions.checkArgument;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -28,6 +29,7 @@ import android.view.MotionEvent;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RestrictTo;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
|
||||
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
|
||||
@@ -177,7 +179,9 @@ public abstract class SelectionTracker<K> {
|
||||
*/
|
||||
public abstract boolean deselect(@NonNull K key);
|
||||
|
||||
abstract AdapterDataObserver getAdapterDataObserver();
|
||||
/** @hide */
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
protected abstract AdapterDataObserver getAdapterDataObserver();
|
||||
|
||||
/**
|
||||
* Attempts to establish a range selection at {@code position}, selecting the item
|
||||
@@ -186,8 +190,10 @@ public abstract class SelectionTracker<K> {
|
||||
* @param position The "anchor" position for the range. Subsequent range operations
|
||||
* (primarily keyboard and mouse based operations like SHIFT + click)
|
||||
* work with the established anchor point to define selection ranges.
|
||||
* @hide
|
||||
*/
|
||||
abstract void startRange(int position);
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
public abstract void startRange(int position);
|
||||
|
||||
/**
|
||||
* Sets the end point for the active range selection.
|
||||
@@ -200,20 +206,26 @@ public abstract class SelectionTracker<K> {
|
||||
* @param position The new end position for the selection range.
|
||||
* @throws IllegalStateException if a range selection is not active. Range selection
|
||||
* must have been started by a call to {@link #startRange(int)}.
|
||||
* @hide
|
||||
*/
|
||||
abstract void extendRange(int position);
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
public abstract void extendRange(int position);
|
||||
|
||||
/**
|
||||
* Clears an in-progress range selection. Provisional range selection established
|
||||
* using {@link #extendProvisionalRange(int)} will be cleared (unless
|
||||
* {@link #mergeProvisionalSelection()} is called first.)
|
||||
* @hide
|
||||
*/
|
||||
abstract void endRange();
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
public abstract void endRange();
|
||||
|
||||
/**
|
||||
* @return Whether or not there is a current range selection active.
|
||||
* @hide
|
||||
*/
|
||||
abstract boolean isRangeActive();
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
public abstract boolean isRangeActive();
|
||||
|
||||
/**
|
||||
* Establishes the "anchor" at which a selection range begins. This "anchor" is consulted
|
||||
@@ -223,32 +235,42 @@ public abstract class SelectionTracker<K> {
|
||||
* TODO: Reconcile this with startRange. Maybe just docs need to be updated.
|
||||
*
|
||||
* @param position the anchor position. Must already be selected.
|
||||
* @hide
|
||||
*/
|
||||
abstract void anchorRange(int position);
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
public abstract void anchorRange(int position);
|
||||
|
||||
/**
|
||||
* Creates a provisional selection from anchor to {@code position}.
|
||||
*
|
||||
* @param position the end point.
|
||||
* @hide
|
||||
*/
|
||||
abstract void extendProvisionalRange(int position);
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
protected abstract void extendProvisionalRange(int position);
|
||||
|
||||
/**
|
||||
* Sets the provisional selection, replacing any existing selection.
|
||||
* @param newSelection
|
||||
* @hide
|
||||
*/
|
||||
abstract void setProvisionalSelection(@NonNull Set<K> newSelection);
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
protected abstract void setProvisionalSelection(@NonNull Set<K> newSelection);
|
||||
|
||||
/**
|
||||
* Clears any existing provisional selection
|
||||
* @hide
|
||||
*/
|
||||
abstract void clearProvisionalSelection();
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
protected abstract void clearProvisionalSelection();
|
||||
|
||||
/**
|
||||
* Converts the provisional selection into primary selection, then clears
|
||||
* provisional selection.
|
||||
* @hide
|
||||
*/
|
||||
abstract void mergeProvisionalSelection();
|
||||
@RestrictTo(LIBRARY_GROUP)
|
||||
protected abstract void mergeProvisionalSelection();
|
||||
|
||||
/**
|
||||
* Preserves selection, if any. Call this method from Activity#onSaveInstanceState
|
||||
@@ -689,7 +711,7 @@ public abstract class SelectionTracker<K> {
|
||||
// of motions and gestures in order to provide gesture driven selection support
|
||||
// when used in conjunction with RecyclerView.
|
||||
final GestureSelectionHelper gestureHelper = GestureSelectionHelper.create(
|
||||
tracker, mDetailsLookup, mRecyclerView, scroller, mMonitor);
|
||||
tracker, mSelectionPredicate, mRecyclerView, scroller, mMonitor);
|
||||
|
||||
// Finally hook the framework up to listening to recycle view events.
|
||||
mRecyclerView.addOnItemTouchListener(eventRouter);
|
||||
|
||||
@@ -16,17 +16,18 @@
|
||||
|
||||
package androidx.recyclerview.selection;
|
||||
|
||||
import static androidx.recyclerview.selection.Shared.DEBUG;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.LongSparseArray;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An {@link ItemKeyProvider} that provides stable ids by way of cached
|
||||
* {@link RecyclerView.Adapter} stable ids. Items enter the cache as they are laid out by
|
||||
@@ -39,8 +40,10 @@ import java.util.Map;
|
||||
*/
|
||||
public final class StableIdKeyProvider extends ItemKeyProvider<Long> {
|
||||
|
||||
private static final String TAG = "StableIdKeyProvider";
|
||||
|
||||
private final SparseArray<Long> mPositionToKey = new SparseArray<>();
|
||||
private final Map<Long, Integer> mKeyToPosition = new HashMap<Long, Integer>();
|
||||
private final LongSparseArray<Integer> mKeyToPosition = new LongSparseArray<>();
|
||||
private final RecyclerView mRecyclerView;
|
||||
|
||||
/**
|
||||
@@ -76,6 +79,12 @@ public final class StableIdKeyProvider extends ItemKeyProvider<Long> {
|
||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||
void onAttached(@NonNull View view) {
|
||||
RecyclerView.ViewHolder holder = mRecyclerView.findContainingViewHolder(view);
|
||||
if (holder == null) {
|
||||
if (DEBUG) {
|
||||
Log.w(TAG, "Unable to find ViewHolder for View. Ignoring onAttached event.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
int position = holder.getAdapterPosition();
|
||||
long id = holder.getItemId();
|
||||
if (position != RecyclerView.NO_POSITION && id != RecyclerView.NO_ID) {
|
||||
@@ -87,6 +96,12 @@ public final class StableIdKeyProvider extends ItemKeyProvider<Long> {
|
||||
@SuppressWarnings("WeakerAccess") /* synthetic access */
|
||||
void onDetached(@NonNull View view) {
|
||||
RecyclerView.ViewHolder holder = mRecyclerView.findContainingViewHolder(view);
|
||||
if (holder == null) {
|
||||
if (DEBUG) {
|
||||
Log.w(TAG, "Unable to find ViewHolder for View. Ignoring onDetached event.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
int position = holder.getAdapterPosition();
|
||||
long id = holder.getItemId();
|
||||
if (position != RecyclerView.NO_POSITION && id != RecyclerView.NO_ID) {
|
||||
@@ -102,9 +117,6 @@ public final class StableIdKeyProvider extends ItemKeyProvider<Long> {
|
||||
|
||||
@Override
|
||||
public int getPosition(@NonNull Long key) {
|
||||
if (mKeyToPosition.containsKey(key)) {
|
||||
return mKeyToPosition.get(key);
|
||||
}
|
||||
return RecyclerView.NO_POSITION;
|
||||
return mKeyToPosition.get(key, RecyclerView.NO_POSITION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ final class TouchInputHandler<K> extends MotionInputHandler<K> {
|
||||
}
|
||||
|
||||
if (mSelectionTracker.hasSelection()) {
|
||||
if (isRangeExtension(e)) {
|
||||
if (shouldExtendRange(e)) {
|
||||
extendSelectionRange(item);
|
||||
} else if (mSelectionTracker.isSelected(item.getSelectionKey())) {
|
||||
mSelectionTracker.deselect(item.getSelectionKey());
|
||||
@@ -126,32 +126,26 @@ final class TouchInputHandler<K> extends MotionInputHandler<K> {
|
||||
|
||||
boolean handled = false;
|
||||
|
||||
if (isRangeExtension(e)) {
|
||||
if (shouldExtendRange(e)) {
|
||||
extendSelectionRange(item);
|
||||
handled = true;
|
||||
} else {
|
||||
if (!mSelectionTracker.isSelected(item.getSelectionKey())
|
||||
&& mSelectionPredicate.canSetStateForKey(item.getSelectionKey(), true)) {
|
||||
// If we cannot select it, we didn't apply anchoring - therefore should not
|
||||
// start gesture selection
|
||||
if (selectItem(item)) {
|
||||
// And finally if the item was selected && we can select multiple
|
||||
// we kick off gesture selection.
|
||||
if (mSelectionPredicate.canSelectMultiple()) {
|
||||
mGestureStarter.run();
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
} else {
|
||||
// We only initiate drag and drop on long press for touch to allow regular
|
||||
// touch-based scrolling
|
||||
mOnDragInitiatedListener.onDragInitiated(e);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
mHapticPerformer.run();
|
||||
} else {
|
||||
if (mSelectionTracker.isSelected(item.getSelectionKey())) {
|
||||
// Long press on existing selected item initiates drag/drop.
|
||||
mOnDragInitiatedListener.onDragInitiated(e);
|
||||
mHapticPerformer.run();
|
||||
} else if (mSelectionPredicate.canSetStateForKey(item.getSelectionKey(), true)
|
||||
&& selectItem(item)) {
|
||||
// And finally if the item was selected && we can select multiple
|
||||
// we kick off gesture selection.
|
||||
// NOTE: isRangeActive should ALWAYS be true at this point, but there have
|
||||
// been reports indicating that assumption isn't correct. So we explicitly
|
||||
// check isRangeActive.
|
||||
if (mSelectionPredicate.canSelectMultiple() && mSelectionTracker.isRangeActive()) {
|
||||
mGestureStarter.run();
|
||||
}
|
||||
mHapticPerformer.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,9 +116,9 @@
|
||||
* <b>Include Selection in Activity lifecycle events</b>
|
||||
*
|
||||
* <p>
|
||||
* In order to preserve state the author must the selection library in handling
|
||||
* of Activity lifecycle events. See SelectionTracker#onSaveInstanceState
|
||||
* and SelectionTracker#onRestoreInstanceState.
|
||||
* In order to preserve state, the author must include the selection library in the handling
|
||||
* of Activity lifecycle events. See SelectionTracker#onSaveInstanceState and
|
||||
* SelectionTracker#onRestoreInstanceState.
|
||||
*
|
||||
* <p>A unique selection id must be supplied to
|
||||
* {@link androidx.recyclerview.selection.SelectionTracker.Builder SelectionTracker.Builder}
|
||||
|
||||
Reference in New Issue
Block a user