【问题标题】:How stick to with Adapter position while it's scrolling in Android?在 Android 中滚动时如何坚持适配器位置?
【发布时间】:2020-05-16 20:37:45
【问题描述】:

问题是,在我的 recyclerview - 适配器中,单击删除按钮,我显示小进度条代替删除按钮。现在假设完成删除过程需要 2 分钟。因此,与此同时,如果用户正在滚动 recyclerview,正在运行的进度条交换位置

我该如何控制?

FLOW: 点击删除 - delete.onClicklistener - 内部监听器 - 在活动中通知 - 调用异步任务 - 异步任务结果监听器是 onDeleteDataReceived - 内部调用 updateView() 这是在适配器类中 - 在 updateView() 内部更改可见性。

注意:该特定位置的项目被正确删除,但滚动回收视图时进度条位置交换

我已经检查了这个答案,但不适用于我的情况:Why does the input value in EditText swaps its position while scrolling in a RecyclerView?

代码:

适配器类:

public void updateView(int position, RecyclerView.ViewHolder viewHolder) {
        try {
            if (viewHolder.getAdapterPosition() == position) {
                MyViewHolder holder = (MyViewHolder) viewHolder;
                holder.delete.setVisibility(View.VISIBLE);
                holder.progressBar.setVisibility(View.GONE);
                notifyItemRemoved(position);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
    Events events = eventList.get(position);

    holder.delete.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (listener != null) {
               holder.delete.setVisibility(View.GONE);
                    holder.progressBar.setVisibility(View.VISIBLE);
                    eventList.get(position).isSelected = true;
                    listener.onClicked(position, eventList.get(position).getEventId());
            }
        }
    });

活动:

 @Override
    public void onDeleteDataReceived(Boolean status, int position) {
        stopShimmerLayout();
        if (status) {
            try {
                if (eventsList.get(position).isSelected) {
                    eventsList.remove(position);
                    RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(position);
                    mAdapter.updateView(position, viewHolder);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            showToast(context, "Failed", Toast.LENGTH_SHORT);
        }
    }

观看视频以获得更好的理解:https://drive.google.com/open?id=13ZAtnyfGbi2X4JjUTmJsIDy-gt5y51Gr

实现:https://drive.google.com/open?id=1ePOfZctEO_IhzUM3bFYW3VJKThoVkI6a

这是什么? 为什么每个人都在说同样的事情?我要问的是一切正常。我能够显示正确位置的进度条和删除按钮可见性,并且项目也被用户选择的位置正确删除。问题是在删除时,如果我开始非常快地滚动,那么运行进度条会交换位置。但是当我再次到达那个位置时,那个项目被删除了。

【问题讨论】:

  • 我看到了,问题是你在 ViewHolder 类中而不是在成员函数 onBindViewHolder 中这样做。因为MyViewHolder 总是将整个布局表示为一个,而onBindViewHolder() 表示RecyclerView 中每个项目的布局,所以当您在MyViewHolder 中执行此操作时,它会更改每个项目的视图。因此,使用onBindViewHolder(holder: MyViewHolder, position: Int) 并使用此holder 将特定项目的ProgressBar 引用为holder.progressBar.setVisibility(View.VISIBLE);
  • @LalitFauzdar 我已经试过了。查看更新的问题。但问题还是一样。这又是一个问题:stackoverflow.com/questions/61842770/…
  • @LalitFauzdar 观看视频以获得更好的理解:drive.google.com/open?id=13ZAtnyfGbi2X4JjUTmJsIDy-gt5y51Gr
  • 要么使用适配器中的全局变量,在 OnCreate() 中初始化它们并从活动中调用它们,要么尝试使用 this。虽然,我没有找到任何与你有相同问题的好的答案/问题,但我认为这个问题会给你这个想法。此外,您可以在活动中创建局部/全局变量,通过onItemClick 中的相应视图将它们分配为here,然后在删除完成时切换可见性。
  • @LalitFauzdar 我检查了两个答案。你能告诉我,我可以用不同的方法在不同的不同情况下以两种方式使用相同的侦听器吗?就像我创建监听器 A 并在这两个方法中,X 和 Y.,我可以在单击删除按钮时这样做吗?我将使用 X 方法将数据从适配器传递到活动,删除后我将使用 Y 将数据从活动传递到适配器。有可能吗?

标签: android


【解决方案1】:

我认为这是在RecyclerView 上动态更新视图的一个非常常见的问题。一个简单的修复可能是保存当前正在删除的项目的位置,并根据您存储的位置在您的onBindViewHolder 中设置进度微调器。

让我们在Event 类中使用一个额外的变量,正如此处其他答案中所指出的那样。这是为了跟踪项目删除。

public class Event {
    // ... Your other variables will go here
    public boolean isDeleting = false; // Set the default value to false 
}

现在在deleteonClickListener 按钮中,更新变量的状态以指示项目是否正在被删除。

@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
    Events events = eventList.get(position);

    holder.delete.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (listener != null) {
               // We do not need setting the visibility here. The next actions for notifyDataSetChanged will take care of this. 
               // holder.delete.setVisibility(View.GONE);
               // holder.progressBar.setVisibility(View.VISIBLE);
               eventList.get(position).isSelected = true;
               eventList.get(position).isDeleting = true; // Set the variable to true to indicate that the item is being deleted
               listener.onClicked(position, eventList.get(position).getEventId());

               // It is important here to notify the list that the views are changed when the delete button is clicked. Hence call the notifyDataSetChanged
               notifyDataSetChanged();
            }
        }
    });

    // Now let us update the views based on the selection for deletion
    if (eventList.get(position).isDeleting) {
         // The item is being deleted 
         holder.progressBar.setVisibility(View.VISIBLE);
         holder.delete.setVisibility(View.GONE);
    } else {
        // The item is not being deleted (normal case) 
         holder.progressBar.setVisibility(View.GONE);
         holder.delete.setVisibility(View.VISIBLE);            
    }
}

现在通过updateView 函数,您需要根据需要设置eventList 并再次调用notifyDataSetChanged 以获取RecyclerView 中的更新视图。

public void updateView(int position) {
    // Update the eventList 
    eventList.remove(position); // Remove the item that was deleted by the index
    // Now let the RecyclerView know that the list is updated as one of the items is removed. 
    notifyDataSetChanged();
}

你应该很高兴!

更新

我无法运行您共享的程序。但是,我有机会研究活动和适配器类。看起来这里还有其他一些问题。

eventListArrayList,它不是线程安全的数据结构。您正在尝试删除后台线程中的事件并在该线程上完成删除时更新RecyclerView。因此,当您尝试同时删除多个项目时,您无法真正确保列表会相应更新。

您可以考虑删除synchronized 或使用线程安全的数据结构来避免eventList 中的这种并发修改问题。

【讨论】:

【解决方案2】:
  1. Events对象内创建变量
public class Events {
    // your parametters bla bla

    boolean isDeleting = false;

    public boolean isDeleting() {
        return isDeleting;
    }

    public void setDeleting(boolean deleting) {
        isDeleting = deleting;
    }
}
  1. 将您的视图持有者更改为此
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
    Events events = eventList.get(position);

    holder.progressBar.setVisibility(events.isDeleting() ? View.VISIBLE : VIEW.GONE)
    holder.delete.setVisibility(events.isDeleting() ? View.GONE : View.VISIBLE);
    holder.delete.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (listener != null) {
                holder.delete.setVisibility(View.GONE);
                holder.progressBar.setVisibility(View.VISIBLE);
                eventList.get(position).setDeleting(true)
                listener.onClicked(position, eventList.get(position).getEventId());
            }
        }
    });

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 2013-09-22
  • 2010-10-03
  • 2021-10-18
  • 2014-01-21
  • 2012-05-25
相关资源
最近更新 更多