簡體   English   中英

在RecyclerView上垂直拖放項目后如何在Firestore中保留項目位置

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM