![](/img/trans.png)
[英]How to update all the items in ArrayList due to shift in drag and drop of recyclerview
[英]How to persist items position in firestore after vertically drag & drop them on a RecyclerView
在垂直拖放待辦事項后,我嘗試保持待辦事項列表應用程序項目的位置。 我使用RecyclerView / FirestoreRecylerAdapter / ItemTouchHelper / Firestore。 在ItemTouchHelper.Callback的onMove()-Method中,我訪問帶有異步調用的Firestore。 這會導致RecyclerView中不必要的內容更改。 想象一下,我有一個包含標題A,B,C,D的4個項目的列表。現在,我將標題為A的項目從位置0(在頂部)拖到位置1。像這樣,項目B的標題也更改為A。但這僅在UI上而不在DB中。 當我轉到另一項活動並回來時,標題再次正確。 我想這與異步調用有關。
//part of MainActivity onCreate()
mFirestore = FirebaseFirestore.getInstance();
FirebaseFirestore.setLoggingEnabled(true);
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(true)
.build();
mFirestore.setFirestoreSettings(settings);
mRecyclerView = findViewById(R.id.recycler_view);
mUser = FirebaseAuth.getInstance().getCurrentUser();
if(mUser == null){
startSignIn();
}else{
Query mQuery = mFirestore.collection("todos").whereEqualTo("author", mUser.getUid()).whereEqualTo("done", false).orderBy("position", Query.Direction.ASCENDING);
FirestoreRecyclerOptions<Todo> options = new FirestoreRecyclerOptions.Builder<Todo>()
.setQuery(mQuery, Todo.class)
.build();
mAdapter = new TodoAdapter(options);
initRecyclerView();
//ItemTouchHelper.Callback method as part of initRecyclerView()
@Override
public boolean onMove(final RecyclerView recyclerView, final RecyclerView.ViewHolder source, final RecyclerView.ViewHolder target) {
if (source.getItemViewType() != target.getItemViewType()) {
return false;
}
int fromPos = source.getAdapterPosition();
int toPos = target.getAdapterPosition();
//Change items position when an item was draged & droped vertically downwards
if(toPos > fromPos) {
DocumentReference docTo = mAdapter.getSnapshots().getSnapshot(fromPos).getReference();
docTo.update("position", toPos);
int current = fromPos+1;
while(current <= toPos){
DocumentReference docCurrent = mAdapter.getSnapshots().getSnapshot(current).getReference();
docCurrent.update("position", current-1);
current ++;
}
//Change items position when an item was draged & droped vertically upwards
}else if (toPos < fromPos){
//TODO implement
} else {
return false;
}
mAdapter.notifyItemMoved(fromPos, toPos);
return true;
}
//adapter class
public class TodoAdapter extends FirestoreRecyclerAdapter<Todo, TodoAdapter.TodoHolder> {
private static final String TAG = "DOIT_DEBUG: ";
private OnItemClickListener listener;
private View viewItem;
public TodoAdapter(@NonNull FirestoreRecyclerOptions<Todo> options) {
super(options);
}
@Override
protected void onBindViewHolder(@NonNull TodoHolder holder, int position, @NonNull Todo model) {
holder.textViewTitle.setText(model.getTitle());
holder.textViewDescription.setText(model.getDescription());
}
@NonNull
@Override
public TodoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
viewItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_todo,
parent, false);
return new TodoHolder(viewItem);
}
public void deleteItem(final int position) {
getSnapshots().getSnapshot(position).getReference().delete();
}
public void setDoneItem(int position){
getSnapshots().getSnapshot(position).getReference().update("done", true);
viewItem.setEnabled(false);
}
public void setOnItemClickListener(OnItemClickListener listener){
this.listener = listener;
}
public interface OnItemClickListener{
void onItemClick (DocumentSnapshot documentSnapshot, int position);
}
public class TodoHolder extends RecyclerView.ViewHolder {
private TextView textViewTitle;
private TextView textViewDescription;
private String documentID;
public TodoHolder(View itemView) {
super(itemView);
textViewTitle = itemView.findViewById(R.id.todo_title);
textViewDescription = itemView.findViewById(R.id.todo_description);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = getAdapterPosition();
if(position != RecyclerView.NO_POSITION && listener != null){
listener.onItemClick(getSnapshots().getSnapshot(position), position);
}
}
});
}
}
//model class
public class Todo {
private String title;
private String description;
private String author;
private boolean done;
private int position;
private Date created;
public Todo(){} // Needed for Firebase
public Todo(String title, String description, String author, boolean done, int position, Date created) {
this.title = title;
this.description = description;
this.author = author;
this.done = done;
this.position = position;
this.created = created;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public String getAuthor() {
return author;
}
public boolean getDone() {
return done;
}
public void setTitle(String title) {
this.title = title;
}
public void setDescription(String description) {
this.description = description;
}
public void setAuthor(String author) {
this.author = author;
}
public void setDone(boolean done) {
this.done = done;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
@ServerTimestamp
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
//數據庫結構
集合“ todos”文檔字段:作者字符串,創建的時間戳,描述字符串,完成的布爾值,職位編號,標題字符串
我希望拖放位置更改能夠在Firestore中持久保存,並且RecyclerView僅顯示項目的正確移動而沒有其他更改。
我能夠做到這一點的方法是存儲位置並在必要時進行更新。 如果給每個項目一個等級,則只需要在該項目受到影響時寫一個項目即可。
我只有一個重新排序功能,每次移動該項目時都會寫入新的排名,如果將項目15移動到位置1,則需要更改所有1-15的位置。 根據功能的頻率,您會變得很聰明,例如存儲排名並僅在幾秒鍾沒有其他更改后才更新排名(以避免用戶非常快速地進行50次更改並每次更新)。
這不是最佳方法,但是通過數據庫進行持久化似乎需要一個專用字段,因此需要這種方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.