我試圖通過RecyclerView和ItemTouchHelper實現「刷卡刪除」功能。我有一個奇怪的問題,我無法找到我的生活問題。我從頂端(而不是第一個)掃一個項目,它消失了,到目前爲止這麼好。當我滾動回來時,在上面一排擦掉的物品上面有一個人工製品。看起來這行沒有繪製(或者可能是x翻譯?)。視頻顯示了這個問題。視頻RecyclerView和ItemTouchHelper刷卡以消除問題
步驟:
- 我滑開的第2項
- 向下滾動至底部
- 回來
- 第1項是不再可見
- 我向下滾動到底部再
- 我滾動備份
- 一切都很好現在
- 了,但與第三(而不是秒)從頂部的項目,同樣的問題
- 此外,與第一個項目,沒有問題
相關代碼:(全GitHub的示例應用程序here)
public class MainActivity extends AppCompatActivity {
RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(new TestAdapter());
setUpItemTouchHelper();
}
private void setUpItemTouchHelper() {
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
int swipedPosition = viewHolder.getAdapterPosition();
TestAdapter adapter = (TestAdapter)mRecyclerView.getAdapter();
adapter.remove(swipedPosition);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);
}
static class TestAdapter extends RecyclerView.Adapter {
List<String> items;
public TestAdapter() {
items = new ArrayList<>();
// this should give us a couple of screens worth
for (int i=1; i<= 15; i++) {
items.add("Item " + i);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new TestViewHolder(parent);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
TestViewHolder viewHolder = (TestViewHolder)holder;
String item = items.get(position);
viewHolder.titleTextView.setText(item);
}
@Override
public int getItemCount() {
return items.size();
}
public void remove(int position) {
if (position < 0 || position >= items.size()) {
return;
}
items.remove(position);
notifyItemRemoved(position);
}
}
static class TestViewHolder extends RecyclerView.ViewHolder {
TextView titleTextView;
public TestViewHolder(ViewGroup parent) {
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.row_view, parent, false));
titleTextView = (TextView) itemView.findViewById(R.id.title_text_view);
}
}
}
編輯:
我有一個刪除這個故障的黑客,但我仍然想知道原因,我怎樣才能真正解決這個問題。黑客正在調用notifyDataSetChanged(),但動畫完成後(否則動畫被終止)。基本上,我添加一個ItemDecorator並找出一個動畫結束。
mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
boolean running;
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (parent.getItemAnimator().isRunning()) {
running = true;
}
if (running == true && !parent.getItemAnimator().isRunning()) {
// first time it's not running
running = false;
parent.getAdapter().notifyDataSetChanged();
}
super.onDraw(c, parent, state);
}
});
謝謝,但notifyDataSetChanged()會搞亂去除動畫所以這不是我要找的不幸的解決方案:當我在短暫的延遲後跑notifyDataSetChanged的問題得到解決。工作的黑客是等待動畫完成,然後調用notifyDataSetChanged(),但沒有回調,我需要猜測。請參閱編輯我的問題,瞭解我是如何做到的。這不是我願意留在生產代碼中的東西。 –
好的,看看更新的答案是否有幫助 – random
不完全。適配器中的位置不會映射1到1與回收站視圖的子項中的位置。您可以在適配器中擁有數百個項目,但只能在一個屏幕上添加x個視圖以及多個視圖。你的修補程序可以稍作修改:如果我在onSwipe()中調用它,而不是removeViewAt(position),但removeView(view)像這樣 - mRecyclerView.removeView(viewHolder.itemView);無論如何,這也可能只是一個「黑客」解決方案,最近引入了這個問題,肯定是一個錯誤。看到我的答案。我非常感謝你的幫助! –