Translation animation of view when referenced view's width is wrap_content in ConstraintSet animation

1.3k views Asked by At

This is the design of xml layout begin.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >

    <Button
            android:id="@+id/delete"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="@string/delete"
            android:layout_margin="0dp"
            style="@style/DeleteButton"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:translationZ="-2dp"
            />

    <View
            android:id="@+id/top_layer"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@color/white"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            />

    <ImageButton
            android:id="@+id/bet_slip_remove_item"
            android:layout_width="30dp"
            android:layout_height="30dp"
            app:srcCompat="@drawable/close"
            android:background="@drawable/button_white_radius_10"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="@id/top_layer"
            android:contentDescription="@string/close"
            />

    <TextView
        android:id="@+id/some_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/timeout_error"
        app:layout_constraintTop_toTopOf="@id/top_layer"
        app:layout_constraintBottom_toBottomOf="@id/top_layer"
        app:layout_constraintStart_toStartOf="@id/top_layer"
        android:layout_marginStart="8dp"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

It looks something like this:

enter image description here

There is a Delete button hidden behind top_layer view.

By clicking on "X" I wish, by using ConstraintSet animations, top_layer view to go left with its left part to be outside of the screen and to reveal Delete button, to get something like this:

enter image description here

The problem lies in the fact that Delete button has its width set to wrap_content, but even if it has the fixed width, how can I set xml layout end.xml, to get the desired design on the last picture?

Setting view's position that one part of it is outside of screen puzzles me.

Side note: I use top_layer view for two reasons:

  1. it hides DeleteButton

  2. since all views (X, TextView and presumably others which should be there) should move to the left together, I set their constraints to be relative to top_layer's dimensions.

1

There are 1 answers

0
Cheticamp On

Update: Just realized that you are using animation through ConstraintSet. The easiest thing to do is to set up a clone of your delete button (at least some view with the same width) with its end constraint set to the start of the parent layout. This will give you an off-screen widget whose start side is off screen by how far you want to move your other widgets. You can then set new constraints to that left side and apply the transition.

Here is a sample app:

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onClick(View view) {
        ConstraintLayout layout = findViewById(R.id.layout);
        ConstraintSet cs = new ConstraintSet();
        cs.clone(layout);
        ChangeBounds transition = new ChangeBounds();
        transition.setDuration(1000);

        TransitionManager.beginDelayedTransition(layout, transition);
        cs.connect(R.id.some_text, ConstraintSet.START, R.id.offScreenView, ConstraintSet.START);
        cs.connect(R.id.bet_slip_remove_item, ConstraintSet.END, R.id.delete, ConstraintSet.START);
        cs.applyTo(layout);
    }
}

activity_main.xml
This is a little simplified, but it shows the concepts.

<androidx.constraintlayout.widget.ConstraintLayout 
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/offScreenView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="0dp"
        android:text="@string/delete"
        app:layout_constraintEnd_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="0dp"
        android:text="@string/delete"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/some_text"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@android:color/holo_blue_light"
        android:gravity="center_vertical"
        android:paddingStart="16dp"
        android:elevation="7dp"
        android:text="@string/timeout_error"
        app:layout_constraintBottom_toBottomOf="@+id/delete"
        app:layout_constraintEnd_toEndOf="@id/bet_slip_remove_item"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageButton
        android:id="@+id/bet_slip_remove_item"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:onClick="onClick"
        android:elevation="7dp"
        app:layout_constraintBottom_toBottomOf="@+id/delete"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/close" />

</androidx.constraintlayout.widget.ConstraintLayout>

enter image description here


Animation with the translationX property also works:

You can setup an animation of the translationX property for each element you need to move to the left. You will also need to determine the width of the "delete" button to know how far to move left.

Add something like this to the startup part of your app - onCreate() for an activity:

// Top level member variables.
private ObjectAnimator slide1Animator;
private ObjectAnimator slide2Animator;
private ObjectAnimator slide3Animator;   

findViewById(R.id.top_layer).getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            View topLayer = findViewById(R.id.top_layer);
            View someText = findViewById(R.id.some_text);
            View delete = findViewById(R.id.bet_slip_remove_item);
            pixToSlide = -findViewById(R.id.delete).getWidth();
            slide1Animator = ObjectAnimator.ofFloat(topLayer, "translationX", pixToSlide)
                    .setDuration(1000);

            slide2Animator = ObjectAnimator.ofFloat(someText, "translationX", pixToSlide)
                    .setDuration(1000);

            slide3Animator = ObjectAnimator.ofFloat(delete, "translationX", pixToSlide)
                    .setDuration(1000);
        }
    });

Then, in a click handler for the "x", do the following:

slide1Animator.start();
slide2Animator.start();
slide3Animator.start();

This will shift the views off to the left side of the screen and expose the delete button underneath.