aga
aga

Reputation: 29454

Scenes elevation in Android Transition API

Recently I started playing with the Transition APIs and there is one thing I can not grasp.

Assume I have two scenes (screenshots attached):

Scene A Scene B

Now, when I click on TRANSIT button, I transfer either from 1st scene to 2nd, or from 2nd to 1st, depending on which scene was shown last. When I transfer from 1st scene to 2nd, everything works as expected: the big blue square is moved to the screen's centre (via changeBounds transition) and the green square is being slide in to the screen from the screen's top edge (via the slide) transition.

When I make the backwards transition, though, something strange happens: upon the transition's start, the blue square is being drawn below the green square (in terms of their elevation) and it starts moving to the top right corner as expected. While what I'd want to do is keep the blue square on top of the green square and move it to the top right corner w/o change of its elevation.

Is there something that I miss?

Relevant parts of code:

transition.xml

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="together">

        <changeBounds>
            <targets>
                <target android:targetId="@id/square_view"/>
            </targets>
        </changeBounds>

        <slide android:slideEdge="top">
            <targets>
                <target android:targetId="@+id/green_square_view"/>
            </targets>
        </slide>

</transitionSet>

Scenes:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/green_square_view"
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_marginStart="72dp"
        android:layout_marginTop="216dp"
        android:background="#0cfc28"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:id="@id/square_view"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_marginBottom="180dp"
        android:background="@color/colorPrimary"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</android.support.constraint.ConstraintLayout>

and

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@id/square_view"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:background="@color/colorPrimary"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.931"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.044" />

</android.support.constraint.ConstraintLayout>

MainActivity:

package aga.android.sample.transitionssample

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.transition.*
import android.util.Log
import android.view.ViewGroup
import android.widget.Button

class MainActivity : AppCompatActivity() {

    private lateinit var sceneRoot: ViewGroup

    private var currentSceneIndex = 0
    private var scenes: Array<Scene> = emptyArray()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        sceneRoot = findViewById(R.id.scene_root_view)

        scenes = arrayOf(
            Scene.getSceneForLayout(sceneRoot, R.layout.scene1, this),
            Scene.getSceneForLayout(sceneRoot, R.layout.scene2, this)
        )

        val transition = TransitionInflater.from(this).inflateTransition(R.transition.move_animation)

        findViewById<Button>(R.id.button).setOnClickListener {
            currentSceneIndex = (currentSceneIndex + 1) % 2
            TransitionManager.go(scenes[currentSceneIndex], transition)
        }
    }
}

Upvotes: 2

Views: 293

Answers (1)

Andreas Wenger
Andreas Wenger

Reputation: 4330

The green_square_view is not present in the second scene.xml you posted. If you add the green_square_view to this scene too, the green square will be behind the blue square for both directions. However in this case the Slide animation is not played any more, because the green square does not disappear. This can be fixed easily with android:visibility="invisible" for the newly added green_square_view, because the Slide animation reacts to Views that are not available any more as well as Views that change the Visibility.

I tried to debug what is causing this behavior. In the end I found this part in the documentation that could be applicable:

... For example, if a View was simply removed from its parent, then the View will be added into a ViewGroupOverlay and passed as the view parameter in onDisappear(ViewGroup, View, TransitionValues, TransitionValues). If a visible View is changed to be GONE or INVISIBLE, then it can be used as the view and the visibility will be changed to VISIBLE for the duration of the animation.

The mentioned ViewGroupOverlay is drawn on top of what is in this view group. So this could explain the behavior. However I'm not 100% sure this is causing the problem. Nevertheless having the view in both scenes fixes the problematic behavior.

Upvotes: 1

Related Questions