web-dev-qa-db-fra.com

Est-il possible de désactiver MotionLayout?

J'ai un Fragment qui héberge un RecyclerView dans un MotionLayout. En plus de la vue du recycleur, j'ai une vue qui s'effondre et se développe, tout cela dans ma scène de mouvement. Il est déclenché par un clic et répond au glissement de la vue du recycleur. Jusqu'à présent, tout fonctionne comme prévu.

Vient maintenant le nœud du problème: je voudrais masquer complètement les vues réduites pour certains états dans mon application. Mais si je règle la visibilité des vues ou modifie sa hauteur, elle revient toujours en vue lorsque je fais glisser la vue de recyclage.

Il est donc possible de désactiver complètement MotionLayout (Verrouiller les contraintes) jusqu'à ce que je le réactive. Désactiver la reconnaissance de traînée serait également une solution viable.

Maintenant, du XML simplifié pour illustrer la situation.

Disposition contenant la disposition de mouvement avec vue d'en-tête et vue d'ensemble du recyclage

<?xml version="1.0" encoding="utf-8"?>
<Android.support.constraint.motion.MotionLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:id="@+id/favouritesMotionLayout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    app:layoutDescription="@xml/favourites_motion_scene"
    Android:animateLayoutChanges="true">

    <ImageView
        Android:id="@+id/headerView"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        ...
        />

    <Android.support.v4.widget.SwipeRefreshLayout
        Android:id="@+id/swipeRefreshLayout"
        Android:layout_width="match_parent"
        Android:layout_height="0dp"
        ...
    >

        <pinch.nrcnext.view.scroll.NRCRecyclerView
            Android:id="@+id/favoritesList"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent" />

    </Android.support.v4.widget.SwipeRefreshLayout>

</Android.support.constraint.motion.MotionLayout>

La scène de mouvement correspondante:

<?xml version="1.0" encoding="utf-8"?>
<MotionScene
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:motion="http://schemas.Android.com/apk/res-auto"
>

    <Transition
        motion:constraintSetStart="@id/expanded"
        motion:constraintSetEnd="@id/collapsed"
        motion:duration="300">
        <OnSwipe
            motion:touchAnchorId="@id/swipeRefreshLayout"
            motion:touchAnchorSide="top"
            motion:dragDirection="dragUp" />
    </Transition>

    <ConstraintSet Android:id="@+id/expanded">
        ... Constraints for expanded header ...
    </ConstraintSet>

    <ConstraintSet Android:id="@+id/collapsed">
        ... ... Constraints for collapsed header ...
    </ConstraintSet>

</MotionScene>

Utilisation de la version de mise en page de contraintes "2.0.0-alpha3"

implementation "com.Android.support.constraint:constraint-layout:2.0.0-alpha3"

Donc, récapitulons: j'aimerais pouvoir désactiver la disposition des mouvements, afin de pouvoir faire défiler la vue de recyclage sans que l'en-tête ne se développe, jusqu'à ce que je lui dise d'être réactivé. Malheureusement, ce n'est pas aussi simple que favouritesMotionLayout.isEnabled = false, mais c'est ainsi que je pensais.

6
stephanmantel

Notez que depuis la dernière version bêta (beta2), il est possible de désactiver une transition: https://androidstudio.googleblog.com/2019/06/constraintlayout-200-beta-2.html

Exemple d'utilisation dans Kotlin:

(view as? MotionLayout)?.getTransition(R.id.swipe_transition)?.setEnable(false)
2
John Leehey

En fait, j'ai réussi à le faire fonctionner en définissant l'état de départ de ma scène pour le début et la fin. En kotlin:

motionLayout.setTransition(R.id.start, R.id.start)

Et quand j'avais besoin d'activer ma mise en page:

motionLayout.setTransition(R.id.start, R.id.end)

Pas besoin de changer votre scène xml, a parfaitement fonctionné pour moi en alpha-03

2
Lucas Rodrigues

J'utilise androidx.constraintlayout:constraintlayout:2.0.0-beta4 Et motionLayout.getTransition(R.id.yourTransition).setEnable(false) ne fonctionne pas pour moi, mais pour désactiver complètement la disposition des mouvements, par exemple dans mon cas, je dois masquer la vue dans un cas spécial, mais cette vue impliquait en animation. Donc cardMotionLayout.loadLayoutDescription(0) désactiver complètement MotionLayout, et pour réactiver j'utilise cardMotionLayout.loadLayoutDescription(R.xml.fragment_buy_card_step_one_scene)

0
yandroidUA

La réponse acceptée par LPirro ne fonctionnait pas pour moi, j'utilise beta3 maintenant. J'ai plutôt changé la description de la mise en page selon mes besoins:

public void enableTransition(boolean enable) {
    if (enable) loadLayoutDescription(R.xml.scene);
    else loadLayoutDescription(0);
}
0
Ankit Bansal

Ça marche pour moi:

  if (list.isNullOrEmpty()) {
                    //disable
                    motionLayout.apply {
                        setTransition(R.id.expanded, R.id.expanded)
                        setTransitionDuration(0)
                    }
                } else {
                   //enable
                    motionLayout.apply {
                        setTransition(R.id.expanded, R.id.collapsed)
                        setTransitionDuration(200)
                    }
                }





 p.s.: 'androidx.constraintlayout:constraintlayout:2.0.0-beta2'
0
RomanK.

Si vous souhaitez désactiver la transition une fois l'action utilisateur terminée. Définissez simplement motionLayout.transitionToState (0). Vous souhaiterez peut-être effectuer cette opération dans le rappel de transition terminée.

Vérifiez si le code ci-dessous vous convient.

motionLayout.setTransitionListener(object : 
MotionLayout.TransitionListener {
        override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {

        }

        override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {

        }

        override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
        }

        override fun onTransitionCompleted(p0: MotionLayout?, p1: Int) {
            (motionLayout as MotionLayout).transitionToState(0)
        }

    })
0
ShubhamDanny

Il semble donc qu'il existe un moyen de pirater votre état pour désactiver la transition de mouvement. Il doit être ajouté après la transition ci-dessus dans le fichier xml. J'ai ajouté une autre transition avec le même état de début et de fin. Dans ton cas:

<Transition
        motion:constraintSetStart="@id/collapsed"
        motion:constraintSetEnd="@id/collapsed"
        motion:duration="0">

Et en Java/kotlin

motion_layout.setTransition(R.id.collapsed, R.id.collapsed)
0
Geoffrey Powell

Eh bien, je devais le faire et j'ai essayé les bibliothèques beta1 et beta2 et je n'ai pas pu désactiver motionlayout et enfin j'ai fait cela pour désactiver l'animation motionlayout lorsque ma liste est vide: -

[[# #]] solution [~ # ~]

// this fix the transition but other parts of layout will still able to trigger transition somehow to R.id.end!!
motionLayout.setTransition(R.id.start, R.id.start);
// disable all other views touch handling except view clicks.
motionLayout.findViewById(R.id.view_ids).setOnTouchListener(
          (v, event) -> event.getActionMasked() != MotionEvent.ACTION_UP);
motionLayout.findViewById(R.id.view_ids).setOnTouchListener(
          (v, event) -> event.getActionMasked() != MotionEvent.ACTION_UP);
     .... disable all the views touch handling cause they can trigger the motion layout animation!

// And then finally has to disable touch handling of motionlayout itself to avoid the space exposed by motionlayout due to padding or margin which can trigger the transition!
motionLayout.setOnTouchListener(
          (v, event) -> event.getActionMasked() != MotionEvent.ACTION_UP);

En bref, nous devons setTransition pour l'identifiant de démarrage à la fois pour le début et la fin. Mais j'avais remarqué que cela ne suffisait pas. Comme en quelque sorte motionlayout désactivez la gestion tactile de recylerview mais toutes les autres parties de motionlayout peuvent déclencher la transition et j'ai donc besoin de désactiver la manipulation tactile de toutes les autres vues et de les laisser uniquement gérer les événements de clic et enfin faire de même pour motionlayout aussi. Cause l'espace entre les vues gérées par motionlayout, donc lorsque vous touchez les parties où se trouve motionlayout, cela déclenchera la transition. Il faut donc aussi désactiver sa gestion tactile.

Et enfin, cela a fonctionné avec cette solution! J'espère que cette réponse aidera quelqu'un! :) profitez-en!

0
Kailash Dabhi

À ce stade, il semble qu'il ne soit pas possible de désactiver les mouvements dans un MotionLayout. J'espère que cela sera ajouté dans une future version. Pour résoudre mon cas d'utilisation, j'ai utilisé un peu de hack sale: j'ai supprimé les vues constituant l'en-tête.

favouritesMotionLayout.removeView(headerView)

La mise en page était correcte et la vue a disparu et le mouvement n'a pas été déclenché. Pour récupérer les vues, je viens de regonfler la disposition entière. (Une alternative serait d'ajouter à nouveau les vues avec leurs contraintes par programme).

Je me rends compte que ce n'est pas la plus jolie solution et je suis actuellement à la recherche de moyens de résoudre l'intégralité du cas d'utilisation sans disposition de mouvement. C'est dommage car cela a été très utile pour jusqu'à 90% de mon cas d'utilisation.

0
stephanmantel