UI components not visible in TransitionManager animations

让人想犯罪 __ 提交于 2020-05-17 06:26:27

问题


This is an issue in a Java Android application with a very simple custom draggable drawer in MainActivity.

This is how it behaves when it runs on Android 10 (API level 29) emulator, and it is the expected behavior.

But the problem is, when it runs on Android L (API level 21) emulator, it behaves unexpectedly as follows :

During the animation, UI components are not visible. But when app goes to background and comes back, they become visible.

Implementation details of app :

To detect fling / drag touch gesture, GestureDetectorCompat was used. When a fling gesture is detected, the custom drawer open animation is being initiated. Animation is implemented using ConstraintSet, ConstraintLayout and TransitionManager.

This is the implementation of touch gesture detections and TransitionManager animations.

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private boolean mIsDrawerOpened;
    private ConstraintLayout mRootConstraintLayout;
    private final ConstraintSet mDrawerClosedConstraintSet = new ConstraintSet();
    private final ConstraintSet mDrawerOpenedConstraintSet = new ConstraintSet();
    private GestureDetectorCompat mGestureDetector;

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

        // Drawer is initially closed
        mIsDrawerOpened = false;

        mRootConstraintLayout = findViewById(R.id.rootConstraintLayout);

        mDrawerClosedConstraintSet.clone(this, R.layout.activity_main_drawer_closed);
        mDrawerOpenedConstraintSet.clone(this, R.layout.activity_main_drawer_opened);

        mGestureDetector = new GestureDetectorCompat(
                getApplicationContext(),
                new GestureDetector.SimpleOnGestureListener() {

                    @Override
                    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

                        // Drag / Fling gesture detected

                        // TODO: Recongnize unwanted drag / fling gestures and ignore them.

                        TransitionManager.beginDelayedTransition(mRootConstraintLayout);

                        // Drawer is closed?
                        if(!mIsDrawerOpened) {
                            // Open the drawer
                            mDrawerOpenedConstraintSet.applyTo(mRootConstraintLayout);
                            mIsDrawerOpened = true;
                        }

                        return true;
                    }

                    @Override
                    public boolean onSingleTapUp(MotionEvent e) {

                        // Single tap detected

                        // TODO: If user has tapped on the drawer, do not close it.

                        TransitionManager.beginDelayedTransition(mRootConstraintLayout);

                        // Drawer is opened?
                        if(mIsDrawerOpened) {
                            // Close the drawer
                            mDrawerClosedConstraintSet.applyTo(mRootConstraintLayout);
                            mIsDrawerOpened = false;
                        }

                        return true;
                    }

                    @Override
                    public boolean onDown(MotionEvent e) {
                        return true;
                    }
                }
        );
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }
}

This is the layout XML of closed drawer.

res/layout/activity_main_drawer_closed.xml

<ConstraintLayout
    android:id="@+id/rootConstraintLayout">

    <ConstraintLayout
        android:id="@+id/drawerConstraintLayout"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        <!-- Constraint start (left) of drawer to end (right) of parent (drawer is outside the parent) -->
        app:layout_constraintStart_toEndOf="parent"
        ... >

        <Button
            android:id="@+id/button1"
            android:text="1"
            ... />

        <Button
            android:id="@+id/button2"
            android:text="2"
            ... />

    </ConstraintLayout>

    <ImageView
        android:id="@+id/notch"
        android:src="@drawable/drawer_notch"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/drawerConstraintLayout"
        ... />

</ConstraintLayout>

This is the layout XML of opened drawer.

res/layout/activity_main_drawer_opened.xml

<ConstraintLayout
    android:id="@+id/rootConstraintLayout">

    <ConstraintLayout
        android:id="@+id/drawerConstraintLayout"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        <!-- Constraint end (right) of drawer to end (right) of parent (drawer is inside the parent) -->
        app:layout_constraintEnd_toEndOf="parent"
        ... >

        <Button
            android:id="@+id/button1"
            android:text="1"
            ... />

        <Button
            android:id="@+id/button2"
            android:text="2"
            ... />

    </ConstraintLayout>

    <ImageView
        android:id="@+id/notch"
        android:src="@drawable/drawer_notch"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/drawerConstraintLayout"
        ... />

</ConstraintLayout>

ConstraintSets from those 2 layouts are taken as start and end key-frames for animations.

Min SDK version is set to API level 19.

build.gradle

android {
    defaultConfig {
        minSdkVersion 19
        ...
    }
    ...
}

Full implementation can be found in this GitHub gist.


回答1:


To do this works as expected you need to add android:clipChildren="false" to your root ViewGroup in your case is ConstaintLayout in your layout activity_main_drawer_closed.xml. Of course such solution applicable only when your view is outside of the viewport.

I don't know why this behaviour differ through versions of Android. In theory, from Android Marshmallow, when you start scene transition root view became invalidated by TransitionManager and being redraw.



来源:https://stackoverflow.com/questions/61729160/ui-components-not-visible-in-transitionmanager-animations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!