You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带滑动手势的RecyclerView:点击其他条目时内容无法归位

RecyclerView左滑按钮复位问题修复

问题分析

  1. 点击其他条目时,已滑动条目的content布局无法复位:
    调用notifyItemChanged仅触发视图重新绑定,但未主动重置content的translationX属性,结合ViewHolder复用机制,旧的偏移状态会被保留。

  2. 点击同一条目时,按钮图标无法完全隐藏:
    滑动归位时未及时清除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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 02:10:55