web-dev-qa-db-fra.com

Désactiver le balayage pour la position dans RecyclerView en utilisant ItemTouchHelper.SimpleCallback

J'utilise recyclerview 22.2.0 et la classe d'aide ItemTouchHelper.SimpleCallback pour activer l'option de glissement pour rejeter dans ma liste. Mais comme j'ai un type d'en-tête dessus, je dois désactiver le comportement de balayage pour la première position de l'adaptateur. Comme RecyclerView.Adapter n'a pas de méthode isEnabled (), j'ai essayé de désactiver l'interaction d'affichage à l'aide des méthodes isEnabled () et - isFocusable () dans la création de ViewHolder, mais n'a pas abouti. J'ai essayé d'ajuster le seuil de balayage à une valeur complète, comme f ot 1f dans la méthode de SimpleCallback getSwipeThreshold (), mais sans succès également.

Quelques fragments de mon code pour vous aider à m'aider.

Mon activité:

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

Et j'ai un adaptateur commun avec deux types de vue . Dans le ViewHolder que je veux désactiver, vous avez:

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);      
    }
}
74
Rafael Toledo

Après avoir joué un peu, j'ai réussi à ce que SimpleCallback possède une méthode appelée getSwipeDirs (). Comme j'ai un ViewHolder spécifique pour la position non balayable , je peux utiliser instanceof pour éviter le balayage. Si ce n'est pas votre cas, vous pouvez effectuer ce contrôle en utilisant la position de ViewHolder dans l'adaptateur.

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

Si quelqu'un utilise ItemTouchHelper.Callback. Ensuite, vous pouvez supprimer tous les indicateurs associés dans la fonction 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);
}

Ici au lieu de dragFlags et swipeFlags Vous pouvez passer 0 pour désactiver la fonctionnalité correspondante.

ItemTouchHelper.START signifie balayer de gauche à droite en cas de paramètres régionaux de gauche à droite (prise en charge de l'application LTR), mais inversement dans les paramètres régionaux de droite à gauche (prise en charge de l'application RTL). ItemTouchHelper.END signifie glisser dans le sens opposé de START.

afin que vous puissiez supprimer n'importe quel drapeau en fonction de vos besoins.

62
Muhammad Adil

Voici un moyen simple de faire cela qui ne dépend que de la position de l'élément balayé:

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

Cela devrait également fonctionner si vous utilisez 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);
}

Si vous souhaitez désactiver le balayage conditionnel aux données de l'élément, utilisez la valeur position pour obtenir les données de l'adaptateur pour l'élément en cours de balayage et les désactiver en conséquence.

Si vous avez déjà des types de détenteurs spécifiques qui ne doivent pas être balayés, la réponse acceptée fonctionnera. Cependant, la création de types de détenteurs en tant que proxy pour la position est un kludge et doit être évitée.

18
Robert Liberatore

Il y a plusieurs façons de s'y prendre, mais si vous ne possédez qu'un seul ViewHolder, mais plus d'une mise en page, vous pouvez adopter cette approche.

Remplacez getItemViewType et donnez-lui une logique permettant de déterminer le type de vue en fonction de la position ou du type de données dans l'objet (j'ai une fonction getType dans mon objet)

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

Renvoie la mise en page appropriée dans onCreateView en fonction de ViewType (assurez-vous de passer le type de vue à la classe 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);
    }
}

Obtient les vues de contenu des différentes mises en page en fonction du type de vue public, classe statique AppListItemHolder (extension) RecyclerView.ViewHolder {

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

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

Et ensuite, dans votre ItemTouchHelper, modifiez les actions en fonction de ViewType. Pour moi, cela désactive le balayage d'un en-tête de section RecyclerView

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

Tout d’abord dans la méthode recyclerView de onCreateViewHolder, définissez une balise pour chaque type de viewHolder, comme ci-dessous le 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;
    }
} 

puis dans l'implémentation ItemTouchHelper.Callback, mettez à jour la méthode getMovementFlags, comme ci-dessous:

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

à la fin attacher à recyclerView:

final SwipeController swipeController = new SwipeController();

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(swipeController);
    itemTouchHelper.attachToRecyclerView(recyclerView);
2
M.Kouchi

En plus de la réponse @Rafael Toledo, si vous souhaitez supprimer le geste de glissement spécifique, tel que le glissement GAUCHE ou DROIT en fonction de la position ou du type de données dans l'objet dans Adapter, vous pouvez procéder comme suit.

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

Ici, dans mon cas, dans mon aperçu du recyclage, je charge les conversations de discussion et il y a des gestes de balayage DROIT (pour ARCHIVE) et GAUCHE (pour EXIT) sur chaque élément. Mais dans le cas où la conversation n'est pas active, je dois alors désactiver le balayage DROIT pour l'élément spécifique dans la vue Recycler.

Donc, je vérifie le activeChat et par conséquent, je désactive le balayage à DROITE.

1
King of Masses