Disable Swipe for position in RecyclerView using ItemTouchHelper.SimpleCallback

前端 未结 7 619
面向向阳花
面向向阳花 2021-01-30 02:44

I am using recyclerview 22.2.0 and the helper class ItemTouchHelper.SimpleCallback to enable swipe-to-dismiss option to my list. But as I have a type of header on it, I

相关标签:
7条回答
  • Here's a simple way to do this that only depends upon the position of the item being swiped:

    @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;
    }
    

    This should also work if you're using 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);
    }
    

    If you want to disable swiping conditional upon the data in the item, use the position value to get data from the adapter for the item being swiped and disable accordingly.

    If you already have specific holder types which need to not swipe, the accepted answer will work. However, creating holder types as a proxy for position is a kludge and should be avoided.

    0 讨论(0)
  • 2021-01-30 03:21

    First in recyclerView at onCreateViewHolder method, set tag for each viewHolder type, like below code:

    @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;
        }
    } 
    

    then in ItemTouchHelper.Callback implementation, update getMovementFlags method, like below:

    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;
        }
    }
    

    at end attach to recyclerView:

    final SwipeController swipeController = new SwipeController();
    
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(swipeController);
        itemTouchHelper.attachToRecyclerView(recyclerView);
    
    0 讨论(0)
  • 2021-01-30 03:23

    After playing a bit, I managed that SimpleCallback has a method called getSwipeDirs(). As I have a specific ViewHolder for the not swipable position, I can make use of instanceof to avoid the swipe. If that's not your case, you can perform this control using the position of ViewHolder in the Adapter.

    Java

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

    Kotlin

    override fun getSwipeDirs (recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
        if (viewHolder is CartAdapter.MyViewHolder) return 0
        return super.getSwipeDirs(recyclerView, viewHolder)
    }
    
    0 讨论(0)
  • 2021-01-30 03:25

    It can be disabled using 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)
    
    0 讨论(0)
  • 2021-01-30 03:26

    There are a few ways to go about this, but if you only have one ViewHolder, but more than one layout you can take this approach.

    Override the getItemViewType and give it some logic as to determine view type based on position or type of data in object (I have a getType function in my object)

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

    Return proper layout in onCreateView based on ViewType (Make sure to pass view type to ViewHolder class.

    @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);
        }
    }
    

    Get the content views of the different layouts based on view type public static class AppListItemHolder extends RecyclerView.ViewHolder {

        public AppListItemHolder (View v, int viewType) {
            super(v);
    
            if (viewType == 0)
                ... get your views contents
            else
                ... get other views contents
            }
        }
    }
    

    And then in your ItemTouchHelper change actions based on ViewType. For me this disables swiping of a RecyclerView section header

    @Override
    public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        if (viewHolder.getItemViewType() == 1) return 0;
            return super.getSwipeDirs(recyclerView, viewHolder);
        }
    }
    
    0 讨论(0)
  • 2021-01-30 03:31

    If someone is using ItemTouchHelper.Callback. Then You can remove any related flags in getMovementFlags(..) function.

    @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);
    }
    

    Here instead of dragFlags and swipeFlags You can pass 0 to disable corresponding feature.

    ItemTouchHelper.START means swiping left to right in case of left to right locale (LTR application Support), but the other way around in a right to left locale (RTL application Support). ItemTouchHelper.END means swiping in the opposite direction of START.

    so you can remove any flag according to your requirements.

    0 讨论(0)
提交回复
热议问题