带滑动手势的RecyclerView:点击其他条目时内容无法归位
RecyclerView左滑按钮复位问题修复
问题分析
点击其他条目时,已滑动条目的content布局无法复位:
调用notifyItemChanged仅触发视图重新绑定,但未主动重置content的translationX属性,结合ViewHolder复用机制,旧的偏移状态会被保留。点击同一条目时,按钮图标无法完全隐藏:
滑动归位时未及时清除buttonBuffer中对应位置的按钮记录,且onChildDraw未处理归位时的按钮绘制逻辑,导致残留绘制内容。
解决方案
1. 主动重置content布局偏移状态
在多个关键节点强制重置content的translationX为0,确保视图状态正确:
修改UserSwipeHelper的onChildDraw方法
@Override public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { int pos = viewHolder.getAdapterPosition(); float translationX = dX; View itemView = viewHolder.itemView; View contentView = itemView.findViewById(R.id.content); if (pos < 0) { swipePosition = pos; contentView.setTranslationX(0); return; } if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { if (dX < 0) { List<UserButton> buffer = new ArrayList<>(); if (!buttonBuffer.containsKey(pos)) { instantiateUserButton(viewHolder, buffer); buttonBuffer.put(pos, buffer); } else { buffer = buttonBuffer.get(pos); } translationX = dX * Objects.requireNonNull(buffer).size() * buttonWidth / itemView.getWidth(); contentView.setTranslationX(-translationX); drawButton(c, itemView, buffer, pos, translationX); } else { // 滑动归位时重置content位置 contentView.setTranslationX(0); } } else { // 非滑动状态强制重置content位置 contentView.setTranslationX(0); } super.onChildDraw(c, recyclerView, viewHolder, translationX, dY, actionState, isCurrentlyActive); }
修改recoverSwipedItem方法
private synchronized void recoverSwipedItem() { while (!removerQueue.isEmpty()) { int pos = removerQueue.poll(); if (pos > -1) { // 直接找到ViewHolder重置content RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(pos); if (holder != null) { holder.itemView.findViewById(R.id.content).setTranslationX(0); } Objects.requireNonNull(recyclerView.getAdapter()).notifyItemChanged(pos); // 移除buffer中的记录,避免残留绘制 buttonBuffer.remove(pos); } } }
修改onSwiped方法
@Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { int pos = viewHolder.getAdapterPosition(); if (swipePosition != pos) { // 重置旧滑动条目的content位置 if (swipePosition > -1) { RecyclerView.ViewHolder oldHolder = recyclerView.findViewHolderForAdapterPosition(swipePosition); if (oldHolder != null) { oldHolder.itemView.findViewById(R.id.content).setTranslationX(0); } removerQueue.add(swipePosition); } } swipePosition = pos; if (buttonBuffer.containsKey(swipePosition)) { userButtonList = buttonBuffer.get(swipePosition); } else { userButtonList.clear(); } swipeThreshold = 0.5f * userButtonList.size() * buttonWidth; recoverSwipedItem(); }
2. 适配ViewHolder复用
在RecyclerView的Adapter的onBindViewHolder方法中,强制重置content偏移状态,避免复用旧视图的残留状态:
@Override public void onBindViewHolder(@NonNull YourViewHolder holder, int position) { // 业务逻辑绑定 // ... // 重置content位置 holder.contentView.setTranslationX(0); }
关键说明
- 主动重置
translationX是核心:notifyItemChanged不一定立即触发视图重建,手动设置能确保状态及时恢复。 - 清理
buttonBuffer避免残留绘制:滑动归位后移除对应位置的按钮记录,防止后续drawButton绘制残留内容。
内容的提问来源于stack exchange,提问作者Lock
相关产品推荐
相关产品推荐

