web-dev-qa-db-fra.com

MotionLayout: MotionsCene OnCliquez sur SetonClickListener

Je commence juste à jouer avec MotionLayout. J'ai défini une disposition d'activité à l'aide de MotionLayout qui utilise un MotionScene pour masquer et montrer une vue.

La transition MotionScene ressemble à ceci:

<Transition
    app:constraintSetStart="@id/collapsed"
    app:constraintSetEnd="@id/expanded">

    <OnClick app:target="@id/nextButton"  />

</Transition>

Troublie est que rien ne se passe lorsque j'ajouterai de manière programmée sur le bouton ClickListener sur le bouton:

nextButton.setOnClickListener {
        //do some stuff
    }

Cet auditeur est complètement ignoré, mais la transition (vue en expansion/effondrement) est déclenchée à chaque clic. J'ai vu où quelqu'un s'étendMotionLayout Pour gérer des événements clic, mais il semble que cela semble être un moyen plus facile d'ajouter un autre auditeur de clic pour le bouton.

Question 1: Existe-t-il un moyen d'ajouter un cliclistener à la cible d'un onclick dans une transition MotionLayout?

Question 2: Existe-t-il un moyen de faire la transition un événement unique? Le résultat souhaité est que si la vue est effondrée lorsque le bouton est cliqué sur , alors la vue se développe, mais si elle est déjà élargie, il reste élargi.

Enfin, j'utilise l'espace de noms "http://schemas.Android.com/apk/res-auto" et les docs clairement indiquent que target et mode sont des attributs pour OnClick. Mais le projet ne compilera pas lorsque j'utilise mode car il est introuvable dans cet espace de noms.

Question 3: Est-ce que j'utilise l'espace de nom correct?

11
MayNotBe

Vous pouvez également gérer simplement le clic programmatiquement depuis le début en supprimant

 <OnClick app:target="@id/nextButton"  />

tout à fait. Il est également facile de voir si votre vision est développée ou non en vérifiant la progression de votre transition. Donc, vous pouvez le gérer programmatiquement dans votre fichier Java/Kotlin avec

yourButton.setOnClickListener {
    if (yourMotionLayoutId.progress == 0.0)
        yourMotionLayoutId.transitionToEnd
}

De cette façon, il vérifiera si la transition est dans l'état où elle n'a pas eu lieu (la progression sera de 0,0) et de transition, sinon cela ne fera rien.

2
kjanderson2

J'ai trouvé une façon plus propre et plus correcte de le faire, vous pouvez le faire .... onclick directement à partir de la vue ..

Remarque: cela ne fonctionne pas avec: <OnSwipe/> seulement <OnClick/>

PD. Je suis désolé, je viens du Mexique et j'utilise le traducteur

<androidx.appcompat.widget.AppCompatImageView
        Android:id="@+id/play_pause_button_collapsed"
        Android:layout_width="30dp"
        Android:layout_height="50dp"
        app:srcCompat="@drawable/ic_play_arrow_black_48dp"
        Android:layout_marginTop="25dp"
        Android:elevation="2dp"
        Android:alpha="0"

        Android:onClick="handleAction"

        tools:ignore="ContentDescription" />



fun handleAction(view: View) { 
   //handle click
}
1
Erick Alvarez

Vous pouvez implémenter motionLayout.TransitionnementListenner à l'événement du gestionnaire lors de la transition.

public class LoginActivity extends AppCompatActivity implements MotionLayout.TransitionListener {
private static final String TAG = "LoginActivity";
private FirebaseAuth mAuth;
private LoginLayoutBinding binding;

@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = LoginLayoutBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());

    // initialize the FirebaseAuth instance.
    mAuth = FirebaseAuth.getInstance();
    binding.getRoot().addTransitionListener(this);
}


@Override
public void onStart() {
    super.onStart();
    // Check if user is signed in (non-null) and update UI accordingly.
    FirebaseUser currentUser = mAuth.getCurrentUser();
    updateUI(currentUser);
}

private void updateUI(FirebaseUser currentUser) {
    hideProgressBar();
    if (currentUser != null) {
        Intent intent = new Intent(LoginActivity.this, MainActivity.class);
        startActivity(intent);
        finish();
    }
}

private void hideProgressBar() {
    binding.progressBar2.setVisibility(View.GONE);
}

private void createAccount(String email, String password) {
    mAuth.createUserWithEmailAndPassword(email, password)
            .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        // Sign in success, update UI with the signed-in user's information
                        Log.d(TAG, "createUserWithEmail:success");
                        FirebaseUser user = mAuth.getCurrentUser();
                        updateUI(user);
                    } else {
                        // If sign in fails, display a message to the user.
                        Log.w(TAG, "createUserWithEmail:failure", task.getException());
                        Toast.makeText(LoginActivity.this, "Authentication failed.",
                                Toast.LENGTH_SHORT).show();
                        updateUI(null);
                    }
                }
            });
}

private void signIn(String email, String password) {
    mAuth.signInWithEmailAndPassword(email, password)
            .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        // Sign in success, update UI with the signed-in user's information
                        Log.d(TAG, "signInWithEmail:success");
                        FirebaseUser user = mAuth.getCurrentUser();
                        updateUI(user);
                    } else {
                        // If sign in fails, display a message to the user.
                        Log.w(TAG, "signInWithEmail:failure", task.getException());
                        Toast.makeText(LoginActivity.this, "Authentication failed.",
                                Toast.LENGTH_SHORT).show();
                        updateUI(null);
                    }
                }
            });
}


@Override
public void onTransitionStarted(MotionLayout motionLayout, int startId, int endId) {

}

@Override
public void onTransitionChange(MotionLayout motionLayout, int startId, int endId, float progress) {

}

@Override
public void onTransitionCompleted(MotionLayout motionLayout, int currentId) {
    if (currentId==R.id.end){
        binding.btnLogin.setText(R.string.sign_up);
        binding.textView3.setEnabled(false);
        binding.textView2.setEnabled(true);
    }else {
        binding.btnLogin.setText(R.string.login);
        binding.textView2.setEnabled(false);
        binding.textView3.setEnabled(true);
    }

}

@Override
public void onTransitionTrigger(MotionLayout motionLayout, int triggerId, boolean positive, float progress) {

}

}

0
Khánh Nguyễn Kim

Je viens d'utiliser ce piratage: clic est traité par programmation, mais cela déclenche la vue cachée sur laquelle <OnClick> est enregistré dans MotionScene:

actualVisibleView.setOnClickListener {
            doSomeLogic()
            hiddenView.performClick()
        }

Et dans MotionScene:

<Transition
        Android:id="@+id/hackedTransitionThanksToGoogle"
        motion:constraintSetEnd="@layout/expanded"
        motion:constraintSetStart="@layout/closed"
        motion:duration="300"
        motion:motionInterpolator="linear">

        <OnClick
            motion:clickAction="transitionToEnd"
            motion:targetId="@+id/hiddenView" />
</Transition>