Вимкніть проведення пальцем для позиції в RecyclerView за допомогою ItemTouchHelper.SimpleCallback


92

Я використовую recyclerview 22.2.0 та допоміжний клас ItemTouchHelper.SimpleCallback, щоб увімкнути в своєму списку опцію проведення пальцем до звільнення . Але оскільки на мені є тип заголовка, мені потрібно відключити поведінку проведення пальцем для першого положення адаптера. Оскільки RecyclerView.Adapter не має методу isEnabled () , я спробував відключити взаємодію подання за допомогою методів isEnabled () та isFocusable () у самому створенні ViewHolder, але не мав успіху. Я спробував налаштувати поріг проведення пальцем до повного значення, наприклад 0f від 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);      
    }
}

Відповіді:


204

Погравши трохи, мені вдалося, що у SimpleCallback є метод, який називається getSwipeDirs () . Оскільки я маю специфічний ViewHolder для положення, яке не можна розгортати , я можу використовувати instanceof, щоб уникнути проведення. Якщо це не ваш випадок, ви можете виконати цей контроль, використовуючи положення ViewHolder в адаптері.

Java

@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


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

Тут замість dragFlags та swipeFlags Ви можете передати 0, щоб вимкнути відповідну функцію.

ItemTouchHelper . ItemTouchHelper.END означає проведення пальцем у протилежному напрямку START.

щоб ви могли зняти будь-який прапор відповідно до ваших вимог.


Дякую!, Я використовую код: @Override public int getMovementFlags (RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; // рухи перетягування повернення makeFlag (ItemTouchHelper.ACTION_STATE_DRAG, dragFlags); // як параметр, перетягування дії та перетягування прапорів}
Do Xuan Nguyen

Це найкраща відповідь, якщо (на відміну від OP) ви продовжуєте ItemTouchHelper.Callbackбезпосередньо.
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;
}

Поверніть правильний макет у 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 extends 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

Спочатку в reciclerView у методі 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;
    }
}

в кінці приєднати до reciclerView:

final SwipeController swipeController = new SwipeController();

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

2

На додаток до відповіді @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і, відповідно, і вимкнув ПРАВО.


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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.