为什么在重写getItemViewType()之后,我的带有ItemTouchHelper的RecyclerView只能拖动一个项目就停止了?

6

我有一个简单的RecyclerView,使用ItemTouchHelper来滑动和拖动项目。一切都很好,直到我需要以不同的样式呈现第一个和最后一个项目,所以我需要在适配器中重写getItemViewType(int p)函数。在我这样做之后,拖动功能就不再流畅,并且总是在移动一个位置后放下项目。这是我的RecyclerView适配器:

public class CurrentStopsAdapter extends RecyclerView.Adapter<CurrentStopsAdapter.ViewHolder> {
private RemoveFromTripListener removeFromTripListener = null;
private SwapPlacesTripListener swapPlacesTripListener = null;
private Context context;
private List<PlaceLink> stops;

public CurrentStopsAdapter(Context context, List<PlaceLink> stops,
                           RemoveFromTripListener removeListener, SwapPlacesTripListener swapListener) {
    this.context = context;
    this.stops = stops;
    removeFromTripListener = removeListener;
    swapPlacesTripListener = swapListener;
}

public interface RemoveFromTripListener {
    void onRemoveTripButtonClick(String id);
}

public interface SwapPlacesTripListener {
    void onSwapPlacesButtonClick(int first, int second);
}

@Override
public int getItemViewType(int position) {
    if (position == (getItemCount()-1)) {
        return -1;
    }
    return position;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    switch (viewType) {
        case -1:
            return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.list_item_destination, parent, false));
        case 0:
            return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.list_item_origin, parent, false));
        default:
            return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.list_item_stop, parent, false));
    }
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    holder.bindStop(stops.get(position));
}

@Override
public int getItemCount() {
    return stops.size();
}

public void remove(int position) {
    if (removeFromTripListener != null) {
        removeFromTripListener.onRemoveTripButtonClick(stops.get(position).getId());
    }
    notifyItemRemoved(position);
}

public void swap(int firstPosition, int secondPosition) {
    if (swapPlacesTripListener != null) {
       swapPlacesTripListener.onSwapPlacesButtonClick(firstPosition, secondPosition);
    }
    notifyItemMoved(firstPosition, secondPosition);
}

public class ViewHolder extends RecyclerView.ViewHolder {
    public final TextView placeTitle;

    public ViewHolder(View view){
        super(view);
        placeTitle = (TextView) view.findViewById(R.id.stops_list_item_title);
    }

    public void bindStop(PlaceLink place){
        this.placeTitle.setText(place.getTitle());

    }
}
}

我的ItemTouchHelper:

public class TripTouchHelper extends ItemTouchHelper.SimpleCallback {
    private CurrentStopsAdapter currentStopsAdapter;

    public TripTouchHelper(CurrentStopsAdapter currentStopsAdapter){
        super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
        this.currentStopsAdapter = currentStopsAdapter;
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        currentStopsAdapter.swap(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        currentStopsAdapter.remove(viewHolder.getAdapterPosition());
    }

}

如果我跳过在getItemViewType上的覆盖并对所有项目使用相同的布局,一切都可以正常工作,但我非常希望找到解决这个问题的方法。任何帮助都将不胜感激 :)

你曾经解决过这个问题吗?我也有同样的问题。谢谢。 - drod
@drod 对不起,我没有跟进项目的变化,你尝试过建议了吗? - Fanney
3个回答

3
适配器认为你移动的两个ViewHolder是不同类型,因为getItemViewType()返回了唯一的类型。所以它应该重新渲染。
例如,你可以按照以下步骤返回类型:
对于r.layout.foo,返回0
对于r.layout.bar,返回1
然后,你可以编写自己的方法/对来检查布局,以便在需要按类型获取布局时使用。如果你仍然需要位置,你可以在ViewHolder被创建后获取AdapterPosition。
如果你需要在OnCreateViewHolder()中获得位置,那么你可能有些问题,并且可能打败了ViewHolder的目的。考虑在操作数据或者onBindViewHolder()时完成这项工作,如果不那么昂贵的话。

我正在为我的适配器使用 setHasStableIds(true),并且我还在适配器类中重写了 getItemId(),我也遇到了同样的问题(在第一个位置后停止移动),有什么想法吗? - marticztn

1
在您的RecyclerView适配器中删除getItemViewType(int position)方法。我也遇到了同样的问题,这个方法可以解决。

0
我认为你应该返回有关所讨论的项目的“类型”作为int,而不是位置。 这意味着对于标题/页脚类型,您可以返回一个值(例如:1),而对于所有其他类型,您可以返回另一个值(例如:2)。 如果返回位置,则每个通过类型进行的移动都将视为不同的View类型,因为位置将是唯一的,这可能会停止拖动。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接