这是我的解决方案,它允许用户对其 Firestore 集合中的文档进行排序。
我为任何 RecyclerAdapter / ViewHolder 组合创建了一些可重用的类来实现这一点。
首先,让你的 POJO 实现PositionAwareDocument
。
public interface PositionAwareDocument {
public Double getPosition();
public void setPosition(double position);
}
public class Experience implements Serializable, PositionAwareDocument {
public String company;
public String timeframe;
public String jobTitle;
public String jobDescription;
public Double position;
@ServerTimestamp
public Date added;
@Override
public Double getPosition() {
return position;
}
@Override
public void setPosition(double position) {
this.position = position;
}
}
然后扩展FirestoreRecyclerAdapter
(来自 FirebaseUI)。
public abstract class IgnoreChangesFirestoreRecyclerAdapter<T, VH extends RecyclerView.ViewHolder> extends FirestoreRecyclerAdapter<T, VH> {
private boolean mIgnoreChanges = false;
public IgnoreChangesFirestoreRecyclerAdapter(@NonNull FirestoreRecyclerOptions<T> options) {
super(options);
}
public void setIgnoreChanges(boolean ignoreChanges) {
mIgnoreChanges = ignoreChanges;
}
@Override
public void onChildChanged(@NonNull ChangeEventType type, @NonNull DocumentSnapshot snapshot, int newIndex, int oldIndex) {
if (!mIgnoreChanges) {
super.onChildChanged(type, snapshot, newIndex, oldIndex);
}
}
}
创建 RecyclerAdapter 保持不变,只需扩展IgnoreChangesFirestoreRecyclerAdapter
:
public class ExperienceRecyclerAdapter extends IgnoreChangesFirestoreRecyclerAdapter<Experience, ExperienceViewHolder> {
public ExperienceRecyclerAdapter(@NonNull FirestoreRecyclerOptions<Experience> options) {
super(options);
}
@Override
protected void onBindViewHolder(@NonNull ExperienceViewHolder holder, int position, @NonNull Experience model) {
holder.setExperience(getSnapshots().getSnapshot(position).getId(), model);
}
@NonNull
@Override
public ExperienceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ExperienceViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.experience_list_item, parent, false));
}
}
这是秘方 - ItemTouchHelper.Callback
:
import android.app.Activity;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.google.firebase.firestore.CollectionReference;
public class FirestoreReorderableItemTouchHelperCallback<T extends PositionAwareDocument> extends ItemTouchHelper.SimpleCallback {
private final Activity mContext;
private final IgnoreChangesFirestoreRecyclerAdapter<T, ?> mRecyclerAdapter;
private final CollectionReference mCollectionReference;
private int dragFrom = -1;
private int dragTo = -1;
public FirestoreReorderableItemTouchHelperCallback(
Activity context,
IgnoreChangesFirestoreRecyclerAdapter<T, ?> recyclerAdapter,
CollectionReference collectionReference) {
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
mContext = context;
mRecyclerAdapter = recyclerAdapter;
mCollectionReference = collectionReference;
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder source, @NonNull RecyclerView.ViewHolder target) {
if (dragFrom == -1) {
dragFrom = source.getAdapterPosition();
}
dragTo = target.getAdapterPosition();
mRecyclerAdapter.notifyItemMoved(source.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
if (dragFrom == -1) {
return;
}
final PositionAwareDocument draggedItem = mRecyclerAdapter.getItem(dragFrom);
final PositionAwareDocument draggedToItem = mRecyclerAdapter.getItem(dragTo);
final String draggedId = mRecyclerAdapter.getSnapshots().getSnapshot(dragFrom).getId();
final int itemCount = mRecyclerAdapter.getItemCount();
mRecyclerAdapter.setIgnoreChanges(true);
if (dragTo == itemCount - 1) {
draggedItem.setPosition(draggedToItem.getPosition() + 100);
} else if (dragTo == 0) {
draggedItem.setPosition(draggedToItem.getPosition() / 2);
} else {
PositionAwareDocument draggedToNext = mRecyclerAdapter.getItem(dragTo > dragFrom ? dragTo + 1 : dragTo - 1);
draggedItem.setPosition((draggedToItem.getPosition() + draggedToNext.getPosition()) / 2);
}
mCollectionReference.document(draggedId).update("position", draggedItem.getPosition()).addOnCompleteListener(mContext, task -> mRecyclerAdapter.setIgnoreChanges(false));
dragFrom = dragTo = -1;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
@Override
public boolean isLongPressDragEnabled() {
return false;
}
}
其余的一切都很顺利,这是我在我的 RecyclerView 和 Adapter 中制作的地方onCreate
:
final CollectionReference experienceReference = mResumeFirestore.collection("experience");
final FirestoreRecyclerOptions<Experience> experienceOptions = new FirestoreRecyclerOptions.Builder<Experience>()
.setQuery(experienceReference.orderBy("position"), Experience.class)
.build();
mExperienceList.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
mExperienceList.setAdapter(mExperienceAdapter = new ExperienceRecyclerAdapter(experienceOptions) {
@Override
public void onDataChanged() {
super.onDataChanged();
setupEmptyView(mExperienceList, mExperienceEmpty, getItemCount());
}
});
mExperienceTouchHelper = new ItemTouchHelper(new FirestoreReorderableItemTouchHelperCallback<>(this, mExperienceAdapter, experienceReference));
mExperienceTouchHelper.attachToRecyclerView(mExperienceList);
如果您有任何问题,请告诉我!