Отключите салфетки для позиции в RecyclerView с помощью ItemTouchHelper.SimpleCallback


Я использую recyclerview 22.2.0 и вспомогательный класс ItemTouchHelper.SimpleCallback для включения swipe-to-dismiss в моем списке. Но поскольку у меня есть тип заголовка на нем, мне нужно отключить поведение салфетки для первой позиции адаптера. Как RecyclerView.Адаптер нет isEnabled () метод, я попытался отключить взаимодействие с видом через методы isEnabled () и isFocusable() в Само создание ViewHolder, но не имело успеха. Я попытался настроить порог салфетки на полное значение, например 0f ot 1f в методе SimpleCallback getSwipeThreshold(), но и без успеха тоже.

некоторые фрагменты моего кода, чтобы помочь вам помочь мне.

Мои Действия:

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

6 ответов:

поиграв немного, мне это удалось 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);
}

Если кто-то использует ItemTouchHelper.Обратный вызов. Затем вы можете удалить все связанные флаги в getMovementFlags(..)

вот простой способ сделать это, который зависит только от положения элемента свистнул:

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder holder) {
    int position = holder.getAdapterPosition();
    int dragFlags = 0; // whatever your dragFlags need to be
    int swipeFlags = position == 0 ? 0 : ItemTouchHelper.START | ItemTouchHelper.END;

    return makeMovementFlags(dragFlags, swipeFlags);
}

Это также должно работать, если вы используете SimpleCallback:

@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder holder) {
    int position = holder.getAdapterPosition();
    return position == 0 ? 0 : super.getSwipeDirs(recyclerView, viewHolder);
}

лучше ли это, чем другие ответы, зависит от ваших потребностей.

  • если вы просто хотите отключить на основе позиции, используйте этот подход.
  • если swipe-способность зависит от данных для элемента, то вы можете использовать этот подход. Используйте position значение для получения данных от адаптера для элемента, который считывается и отключается соответственно.
  • если у вас есть определенные типы держателей, которые не нужно прокручивать, принятый ответ будет работать.

есть несколько способов сделать это, но если у вас есть только один ViewHolder, но более одного макета, вы можете использовать этот подход.

переопределите getItemViewType и дайте ему некоторую логику, чтобы определить тип представления на основе позиции или типа данных в объекте (у меня есть функция getType в моем объекте)

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

возвращает правильный макет в onCreateView на основе ViewType (обязательно передайте тип представления классу 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);
    }
}

в дополнение к ответу @Rafael Toledo, если вы хотите удалить конкретный жест салфетки, такой как левый свайп или правый свайп, основанный на положении или типе данных в объекте в адаптере, вы можете сделать это.

@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 я загружаю разговоры в чате, и у него есть правые ( для архива) и левые ( для выхода) жесты салфетки на каждом элементе. Но в случае, если разговор не активен, то мне нужно отключить правый свайп для конкретного элемент в представлении Recycler.

поэтому я проверяю activeChat и, соответственно, отключил правый свайп.

надеюсь, что это поможет кому-то. " Ура !!

сначала в recyclerView в методе 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.Реализация обратного вызова, обновление 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);