使用ItemTouchHelper.SimpleCallback禁用在RecyclerView中的位置滑动


92

我正在使用recyclerview 22.2.0和帮助程序类ItemTouchHelper.SimpleCallback启用对列表的滑动到关闭选项。但是,由于上面有一种标头,因此需要禁用适配器第一个位置的滑动行为。由于RecyclerView.Adapter没有isEnabled()方法,因此我尝试通过ViewHolder创建本身中的isEnabled()isFocusable()方法禁用视图交互,但是没有成功。我试图将滑动阈值调整为一个完整值,例如SimpleCallback的方法getSwipeThreshold()中的0f1f,但也没有成功。

我的代码的一些片段可以帮助您帮助我。

我的活动:

@Override
protected void onCreate(Bundle bundle) {
    //... initialization
    ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0,
            ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {

        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                          RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
            if (viewHolder instanceof CartAdapter.MyViewHolder) return 1f;
            return super.getSwipeThreshold(viewHolder);
        }

        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {

        }
    };

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
    itemTouchHelper.attachToRecyclerView(recyclerView);
}

我有一个具有两种视图类型的通用适配器。在要禁用滑动的ViewHolder中,我执行了以下操作:

public static class MyViewHolder extends RecyclerView.ViewHolder {
    public ViewGroup mContainer;

    public MyViewHolder(View v) {
        super(v);
        v.setFocusable(false);
        v.setEnabled(false);
        mContainer = (ViewGroup) v.findViewById(R.id.container);      
    }
}

Answers:


204

玩了一点之后,我设法 SimpleCallback有一个名为getSwipeDirs()的方法。因为我有一个特定的ViewHolder用于不可滑动的位置,所以我可以利用instanceof来避免滑动。如果不是您这种情况,则可以使用ViewHolder在适配器中的位置来执行此控制。

爪哇

@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    if (viewHolder instanceof CartAdapter.MyViewHolder) return 0;
    return super.getSwipeDirs(recyclerView, viewHolder);
}

科特林

override fun getSwipeDirs (recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
    if (viewHolder is CartAdapter.MyViewHolder) return 0
    return super.getSwipeDirs(recyclerView, viewHolder)
}

1
正是我想要的!特别是当此方法未出现在官方文档中时...
ptitvinou 2015年


2
值得一提的是:如果您只想在某些项目上允许一个方向,请使用return position == 0 ? ItemTouchHelper.LEFT : super.getSwipeDirs(recyclerView, viewHolder);-这个方向, 即只允许向左滑动。
Jean d'arme

完善。像魅力一样工作
大众之王

这是如何运作的?例如,如果我想禁用向右滑动怎么办?
抗体

66

如果有人在使用ItemTouchHelper.Callback。然后,您可以删除getMovementFlags(..)函数中的所有相关标志。

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
    int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
    return makeMovementFlags(dragFlags, swipeFlags);
}

您可以在此处传递0来禁用相应功能,而不是dragFlagsswipeFlags

ItemTouchHelper.START的意思是在从左到右的区域设置(LTR应用程序支持)的情况下从左向右滑动,但是在从右到左的区域设置(RTL应用程序支持)中相反。 ItemTouchHelper.END表示沿的相反方向滑动START

因此您可以根据自己的要求删除任何标志。


谢谢!,我使用代码:@Override public int getMovementFlags(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder){int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; //移动拖动返回makeFlag(ItemTouchHelper.ACTION_STATE_DRAG,dragFlags); //作为参数,拖动动作和拖动标记}
做Xuan Nguyen

如果ItemTouchHelper.Callback直接扩展(与OP不同),这是首选答案。
tir38

23

这是一种简单的方法,仅取决于被刷物品的位置:

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder holder) {
    int position = holder.getAdapterPosition();
    int dragFlags = 0; // whatever your dragFlags need to be
    int swipeFlags = createSwipeFlags(position)

    return makeMovementFlags(dragFlags, swipeFlags);
}

private int createSwipeFlags(int position) {
  return position == 0 ? 0 : ItemTouchHelper.START | ItemTouchHelper.END;
}

如果您正在使用,这也应该起作用SimpleCallback

@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder holder) {
    int position = holder.getAdapterPosition();
    return createSwipeFlags(position);
}

private int createSwipeFlags(int position) {
  return position == 0 ? 0 : super.getSwipeDirs(recyclerView, viewHolder);
}

如果要以项目中的数据为条件来禁用刷卡,请使用该position值从适配器中获取要刷卡的项目的数据,并相应地禁用。

如果您已经有不需要滑动的特定持有人类型,则接受的答案将起作用。但是,创建持有人类型作为头寸代理很费力,应该避免。


6

有几种解决方法,但是如果您只有一个ViewHolder,但是有多个布局,则可以采用这种方法。

重写getItemViewType并为其提供一些逻辑,以便根据对象中数据的位置或类型确定视图类型(我的对象中有一个getType函数)

@Override
public int getItemViewType(int position) {
    return data.get(position).getType;
}

在基于ViewType的onCreateView中返回正确的布局(请确保将视图类型传递给ViewHolder类。

@Override
public AppListItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    mContext = parent.getContext();

    if (viewType == 0){
        return new AppListItemHolder(LayoutInflater.from(mContext).inflate(R.layout.layout, parent, false), viewType);
    else
        return new AppListItemHolder(LayoutInflater.from(mContext).inflate(R.layout.header, parent, false), viewType);
    }
}

根据视图类型获取不同布局的内容视图。公共静态类AppListItemHolder扩展了RecyclerView.ViewHolder {

    public AppListItemHolder (View v, int viewType) {
        super(v);

        if (viewType == 0)
            ... get your views contents
        else
            ... get other views contents
        }
    }
}

然后在您的ItemTouchHelper中更改基于ViewType的操作。对我来说,这禁用了RecyclerView节标题的刷卡

@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    if (viewHolder.getItemViewType() == 1) return 0;
        return super.getSwipeDirs(recyclerView, viewHolder);
    }
}

好主意,但getItemViewType是最终的
蒂姆

3

首先在oncyclView的onCreateViewHolder方法中,为每种viewHolder类型设置标签,如以下代码所示:

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    if(ITEM_TYPE_NORMAL == viewType) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.deposite_card_view, viewGroup, false);
        ItemViewHolder holder = new ItemViewHolder(context, v);
        holder.itemView.setTag("normal");
        return holder;
    } else {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_header, viewGroup, false);
        HeaderViewHolder holder = new HeaderViewHolder(context, v);
        holder.itemView.setTag("header");
        return holder;
    }
} 

然后在ItemTouchHelper.Callback实现中,更新getMovementFlags方法,如下所示:

public class SwipeController extends ItemTouchHelper.Callback {

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    if("normal".equalsIgnoreCase((String) viewHolder.itemView.getTag())) {
        return makeMovementFlags(0, LEFT | RIGHT);
    } else {
        return 0;
    }
}

最后附加到recyclerView:

final SwipeController swipeController = new SwipeController();

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(swipeController);
    itemTouchHelper.attachToRecyclerView(recyclerView);

2

除了@Rafael Toledo答案之外,如果您要根据Adapter中对象中数据的位置或类型来删除特定的滑动手势(如LEFT滑动或RIGHT滑动),则可以这样做。

@Override
  public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
       {
          int position = viewHolder.getAdapterPosition();
          ConversationDataModel conversationModel = null;
          conversationModel = mHomeAdapter.getItems().get(position);
          boolean activeChat = true;
          if(conversationModel!=null && !conversationModel.isActive())
           {
             activeChat = false;
           }
  return activeChat ? super.getSwipeDirs(recyclerView, viewHolder): ItemTouchHelper.RIGHT;
        }

在我的情况下,在我的Recyclerview中,我正在加载聊天对话,并且每个项目上的手势向右滑动(对于ARCHIVE)和向左滑动(对于EXIT)。但是,如果对话未激活,那么我需要在“回收者”视图中为特定项目禁用向右滑动。

因此,我正在检查activeChat并因此禁用了RIGHT滑动。


2

可以使用禁用它 ItemTouchHelper.ACTION_STATE_IDLE

ItemTouchHelper.SimpleCallback(
    ItemTouchHelper.UP or ItemTouchHelper.DOWN, //drag directions
    ItemTouchHelper.ACTION_STATE_IDLE //swipe directions
)
val touchHelperCallback = object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.ACTION_STATE_IDLE) {
    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        (recyclerView.adapter as MyAdapter).onItemMove(viewHolder.adapterPosition, target.adapterPosition)
        return true
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        return
    }

}
val touchHelper = ItemTouchHelper(touchHelperCallback)
touchHelper.attachToRecyclerView(recyclerViewX)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.