O framework de transição do Android permite animar todos os tipos de movimento sua interface fornecendo os layouts inicial e final. Você pode selecionar o tipo de animação desejado, por exemplo, para esmaecer visualizações. entrada, saída ou alteração do tamanho da visualização, e o framework de transição determina como animar do layout inicial para o final.
O framework de transição inclui os seguintes recursos:
- Animações no nível do grupo: aplicar efeitos de animação a todas as visualizações de uma hierarquia.
- Animações integradas: usar animações predefinidas para efeitos comuns, como esmaecimento ou movimento.
- Suporte ao arquivo de recurso: carregar hierarquias de visualização e animações integradas a partir de arquivos de recursos de layout.
- Callbacks do ciclo de vida: recebem callbacks que oferecem controle sobre a animação e a hierarquia. no processo de mudança.
Para ver um exemplo de código que é animado entre mudanças de layout, consulte BasicTransition (link em inglês).
O processo básico para animar entre dois layouts é o seguinte:
- Crie um objeto
Scene
para o layouts iniciais e finais. No entanto, a cena do layout inicial é muitas vezes é determinado automaticamente a partir do layout atual. - Criar um
Transition
para definir o tipo de animação desejado. - Ligação
TransitionManager.go()
, e o sistema executa a animação para trocar os layouts.
O diagrama na Figura 1 ilustra a relação entre seus layouts, as cenas, a transição e a animação final.
Figura 1. Ilustração básica de como o framework de transição cria uma animação.
Criar uma cena
As cenas armazenam o estado de uma hierarquia de visualização, incluindo todas as visualizações e . O framework de transições pode executar animações entre uma fase e uma cena final.
Você pode criar suas cenas a partir de um layout arquivo de recursos ou de um grupo de visualizações no seu código. No entanto, a cena inicial para sua transição geralmente é determinada automaticamente a partir do interface atual.
Uma cena também pode definir as próprias ações que são executadas quando você faz uma mudança de cena. Esse recurso é útil para limpar as configurações de exibição fazer a transição para uma cena.
Criar uma cena a partir de um recurso de layout
É possível criar uma instância Scene
diretamente de um recurso de layout
. Use essa técnica quando a hierarquia de visualização no arquivo for predominantemente estática.
A cena resultante representa o estado da hierarquia de visualização no momento em que você
criou a instância Scene
. Se você mudar a hierarquia de visualização,
recriar a cena. O framework cria a cena a partir de toda a visualização
no arquivo. Não é possível criar uma cena usando parte de um arquivo de layout.
Para criar uma instância Scene
de um arquivo de recurso de layout, recupere
a raiz da cena a partir do seu layout como um
ViewGroup
. Em seguida, chame o método
Scene.getSceneForLayout()
com a raiz da cena e o ID de recurso do arquivo de layout que
contém a hierarquia de visualização da cena.
Definir layouts para cenas
Os snippets de código no restante desta seção mostram como criar dois
cenas diferentes com o mesmo elemento raiz da cena. Os snippets também mostram
que você pode carregar vários objetos Scene
não relacionados sem implicar que eles
estão relacionadas entre si.
O exemplo consiste nas seguintes definições de layout:
- O layout principal de uma atividade com um rótulo de texto e um filho
FrameLayout
- Um
ConstraintLayout
para o a primeira cena com dois campos de texto. - Uma
ConstraintLayout
para a segunda cena com os mesmos dois campos de texto em ordem diferente.
O exemplo foi projetado para que toda a animação ocorra dentro do arquivo filho. o layout principal da atividade. Rótulo de texto no layout principal permanece estática.
O layout principal da atividade é definido da seguinte forma:
res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/master_layout"> <TextView android:id="@+id/title" ... android:text="Title"/> <FrameLayout android:id="@+id/scene_root"> <include layout="@layout/a_scene" /> </FrameLayout> </LinearLayout>
Essa definição de layout contém um campo de texto e um FrameLayout
filho para o
de cena. O layout da primeira cena é incluído no arquivo de layout principal.
Isso permite que o app a exiba como parte da interface inicial do usuário e carregue
em uma cena, já que o framework só pode carregar um arquivo de layout inteiro em um
cena
O layout da primeira cena é definido da seguinte maneira:
res/layout/a_scene.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/scene_container" android:layout_width="match_parent" android:layout_height="match_parent" ></androidx.constraintlayout.widget.ConstraintLayout>
O layout da segunda cena contém os mesmos dois campos de texto (com o mesmos IDs, colocados em uma ordem diferente. Ela é definida da seguinte maneira:
res/layout/another_scene.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/scene_container" android:layout_width="match_parent" android:layout_height="match_parent" ></androidx.constraintlayout.widget.ConstraintLayout>
Gerar cenas a partir de layouts
Depois de criar definições para os dois layouts de restrição, você pode obter uma cena para cada um deles. Isso permite fazer a transição entre as duas interfaces personalizadas. Para conseguir uma cena, você precisa de uma referência à raiz da cena e ao layout ID do recurso.
O snippet de código a seguir mostra como acessar uma referência à raiz da cena e
crie dois objetos Scene
a partir dos arquivos de layout:
Kotlin
val sceneRoot: ViewGroup = findViewById(R.id.scene_root) val aScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this) val anotherScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this)
Java
Scene aScene; Scene anotherScene; // Create the scene root for the scenes in this app. sceneRoot = (ViewGroup) findViewById(R.id.scene_root); // Create the scenes. aScene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this); anotherScene = Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this);
No app, agora há dois objetos Scene
baseados na visualização.
hierarquias Ambas as cenas usam a raiz da cena definida pelo
Elemento FrameLayout
em res/layout/activity_main.xml
.
Criar uma cena no código
Também é possível criar uma instância Scene
no seu código a partir de uma
objeto ViewGroup
. Use essa técnica ao modificar as hierarquias de visualização
diretamente no código ou ao gerá-los de maneira dinâmica.
Para criar uma cena a partir de uma hierarquia de visualização no seu código, use o
Scene(sceneRoot, viewHierarchy)
construtor. Chamar esse construtor é equivalente a chamar o
Scene.getSceneForLayout()
quando você já inflou um arquivo de layout.
O snippet de código abaixo demonstra como criar um Scene
.
do elemento raiz da cena e a hierarquia de visualização da cena no
seu código:
Kotlin
val sceneRoot = someLayoutElement as ViewGroup val viewHierarchy = someOtherLayoutElement as ViewGroup val scene: Scene = Scene(sceneRoot, viewHierarchy)
Java
Scene mScene; // Obtain the scene root element. sceneRoot = (ViewGroup) someLayoutElement; // Obtain the view hierarchy to add as a child of // the scene root when this scene is entered. viewHierarchy = (ViewGroup) someOtherLayoutElement; // Create a scene. mScene = new Scene(sceneRoot, mViewHierarchy);
Criar ações de cena
O framework permite definir ações de cena personalizadas que o sistema executa ao entrar ou sair de uma cena. Em muitos casos, definir ações de cena personalizadas é desnecessário, uma vez que o framework anima a mudança entre as cenas automaticamente.
As ações de cena são úteis para lidar com estes casos:
- Para animar visualizações que não estão na mesma hierarquia. É possível animar as visualizações as cenas inicial e final usando ações de cena de saída e entrada.
- Para animar visualizações que o framework de transições não pode animar automaticamente,
como objetos
ListView
. Para mais mais informações, consulte a seção sobre limitações.
Para oferecer ações de cena personalizadas, defina suas ações como
objetos Runnable
e transmiti-los para
Scene.setExitAction()
ou Scene.setEnterAction()
. O framework chama a função setExitAction()
no início
antes de executar a animação de transição e o setEnterAction()
na cena final após executar a animação de transição.
Aplicar uma transição
O framework de transição representa o estilo de animação entre as cenas com uma
Transition
. É possível instanciar um Transition
usando
subclasses, como
AutoTransition
e
Fade
ou
defina sua própria transição.
Em seguida, execute o
animação entre as cenas transmitindo o Scene
final
e o Transition
para
TransitionManager.go()
O ciclo de vida da transição é semelhante ao da atividade e representa a transição afirma que o framework monitora entre o início e o a conclusão de uma animação. Em estados importantes do ciclo de vida, o framework invoca funções de retorno de chamada que você pode implementar para ajustar sua interface de usuário em diferentes fases da transição.
Criar uma transição
A seção anterior mostra como criar cenas que representam o estado
diferentes hierarquias de visualização. Depois de definir as cenas inicial e final,
quiser alternar, crie um objeto Transition
que defina uma animação.
O framework permite especificar uma transição integrada em um arquivo de recurso
e infle-a no código ou crie uma instância de uma transição integrada
diretamente no código.
Tabela 1. Tipos de transição integrada.
Classe | Tag | Efeito |
---|---|---|
AutoTransition |
<autoTransition/> |
Transição padrão. Esmaece, move-se, redimensiona e faz as visualizações aparecerem gradualmente, nessa ordem. |
ChangeBounds |
<changeBounds/> |
Move e redimensiona as visualizações. |
ChangeClipBounds |
<changeClipBounds/> |
captura o View.getClipBounds() antes e depois da cena;
mudar e anima essas mudanças durante a transição. |
ChangeImageTransform |
<changeImageTransform/> |
Captura a matriz de uma ImageView antes e depois da cena
ser alterado e animado durante a transição. |
ChangeScroll |
<changeScroll/> |
Captura as propriedades de rolagem dos alvos antes e depois da cena mudar e anima todas as mudanças. |
ChangeTransform |
<changeTransform/> |
Captura a escala e a rotação de visualizações antes e depois da mudança de cena e anima essas mudanças durante a transição. |
Explode |
<explode/> |
Acompanha mudanças na visibilidade das visualizações desejadas no início e no fim e move as visualizações para dentro ou para fora a partir das bordas da cena. |
Fade |
<fade/> |
fade_in faz as visualizações aparecerem gradualmente.fade_out faz as visualizações esmaecerem.fade_in_out (padrão) faz um fade_out seguido por
um fade_in .
|
Slide |
<slide/> |
Acompanha mudanças na visibilidade das visualizações desejadas no início e no fim e move as visualizações para dentro ou para fora partindo de um dos cantos da cena. |
Criar uma instância de transição a partir de um arquivo de recurso
Essa técnica permite que você modifique sua definição de transição sem alterar o código da sua atividade. Essa técnica também é útil para separar dados complexos definições de transição do código do aplicativo, conforme mostrado na seção sobre como especificar várias transições.
Para especificar uma transição integrada em um arquivo de recurso, siga estas etapas:
- Adicione o diretório
res/transition/
ao projeto. - Crie um novo arquivo de recurso XML dentro desse diretório.
- Adicione um nó XML para uma das transições integradas.
Por exemplo, o seguinte arquivo de recurso especifica a transição Fade
:
res/transition/fade_transition.xml
<fade xmlns:android="http://schemas.android.com/apk/res/android" />
O snippet de código a seguir mostra como inflar uma instância Transition
dentro
sua atividade em um arquivo de recurso:
Kotlin
var fadeTransition: Transition = TransitionInflater.from(this) .inflateTransition(R.transition.fade_transition)
Java
Transition fadeTransition = TransitionInflater.from(this). inflateTransition(R.transition.fade_transition);
Criar uma instância de transição no seu código
Essa técnica é útil para criar objetos de transição dinamicamente se você modificar a interface do usuário no código e criar uma transição integrada simples instâncias com poucos ou nenhum parâmetro.
Para criar uma instância de uma transição integrada, invoque uma das solicitações
construtores nas subclasses da classe Transition
. Por exemplo, o
O snippet de código a seguir cria uma instância da transição Fade
:
Kotlin
var fadeTransition: Transition = Fade()
Java
Transition fadeTransition = new Fade();
Aplicar uma transição
Você normalmente aplica uma transição para alternar entre diferentes hierarquias de visualização em resposta a um evento, como uma ação do usuário. Por exemplo, considere um app de pesquisa: quando o usuário digita um termo de pesquisa e toca no botão de pesquisa, o app muda para uma cena que representa o layout dos resultados ao aplicar uma transição que esmaece o botão de pesquisa e aparece gradualmente nos resultados da pesquisa.
Para fazer uma mudança de cena ao aplicar uma transição em resposta a um evento no
sua atividade, chame a função de classe TransitionManager.go()
com o final
cena e a instância de transição a ser usada para a animação, como mostrado
snippet a seguir:
Kotlin
TransitionManager.go(endingScene, fadeTransition)
Java
TransitionManager.go(endingScene, fadeTransition);
O framework muda a hierarquia de visualização dentro da raiz da cena com a visualização. da cena final durante a execução da animação especificada pelo instância de transição. A cena inicial é a última cena da última a transição. Se não houver transição anterior, a cena inicial será determinada automaticamente a partir do estado atual da interface do usuário.
Se você não especificar uma instância de transição, o gerenciador de transição poderá aplicar uma
uma transição automática que faz algo razoável para a maioria das situações. Para
mais informações, consulte a referência da API
TransitionManager
.
Escolher visualizações de destino específicas
O framework aplica transições a todas as visualizações nas cenas inicial e final
por padrão. Em alguns casos, você pode querer aplicar uma animação apenas a um subconjunto
de visualizações em uma cena. O framework permite selecionar visualizações específicas que você quer
animar. Por exemplo, o framework não oferece suporte à animação de mudanças para
Objetos ListView
, portanto, não tente animá-los durante uma transição.
Cada visualização que a transição anima é chamada de destino. Você só pode selecionar destinos que fazem parte da hierarquia de visualização associada a uma cena.
Para remover uma ou mais visualizações da lista de destinos, chame o método
removeTarget()
antes de iniciar a transição. Para adicionar apenas as visualizações especificadas ao
lista de destinos, chame o método
addTarget()
função. Para obter mais informações, consulte a referência de API para a
classe Transition
.
Especificar várias transições
Para gerar o maior impacto em uma animação, faça a correspondência dela com o tipo de alteração que ocorrer entre as cenas. Por exemplo, se você estiver removendo algumas visualizações e adicionando outros entre as cenas, uma animação de esmaecimento ou esmaecimento fornece uma impressão perceptível indicação de que algumas visualizações não estão mais disponíveis. Se você estiver movendo visualizações para pontos diferentes na tela, é melhor animar o movimento para que os usuários percebem a nova localização das visualizações.
Você não precisa escolher apenas uma animação, já que o framework de transições permite combinar efeitos de animação em um conjunto de transições que contém um grupo de transições individuais integradas ou personalizadas.
Para definir um conjunto de transições em uma coleção de transições em XML, crie uma
arquivo de recurso no diretório res/transitions/
e listar as transições em
elemento TransitionSet
. Por exemplo, o snippet a seguir mostra como
especificar um conjunto de transições que tenha o mesmo comportamento que o AutoTransition
;
classe:
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:transitionOrdering="sequential"> <fade android:fadingMode="fade_out" /> <changeBounds /> <fade android:fadingMode="fade_in" /> </transitionSet>
Para inflar o conjunto de transições em um
Objeto TransitionSet
em
seu código, chame o método
TransitionInflater.from()
em sua atividade. A classe TransitionSet
é uma extensão da
Transition
, para que você possa usá-lo com um gerenciador de transição como qualquer outro
outra instância do Transition
.
Aplicar uma transição sem cenas
Mudar as hierarquias de visualização não é a única maneira de modificar sua interface do usuário. Você também pode fazer alterações adicionando, modificando e removendo visualizações filhas no hierarquia atual.
Por exemplo, você pode implementar uma interação de pesquisa com
um único layout. Comece com o layout que mostra um campo de entrada de pesquisa e uma pesquisa
ícone. Para mudar a interface do usuário e mostrar os resultados, remova o botão de pesquisa
quando o usuário toca nele, chamando
ViewGroup.removeView()
e adicione os resultados da pesquisa chamando
ViewGroup.addView()
função.
Use essa abordagem se a alternativa for ter duas hierarquias quase idêntica. Em vez de criar e manter dois arquivos de layout separados para uma pequena diferença na interface do usuário, use um arquivo de layout contendo uma hierarquia de visualizações que pode ser modificada no código.
Se você fizer mudanças na hierarquia de visualização atual dessa maneira, para criar uma cena. Em vez disso, você pode criar e aplicar uma transição entre dois estados de uma hierarquia de visualização usando uma transição atrasada. Esse recurso do o framework de transições começa com o estado atual da hierarquia de visualização, registros alterações feitas em suas visualizações e aplica uma transição que anima a muda quando o sistema redesenha a interface do usuário.
Para criar uma transição atrasada em uma única hierarquia de visualização, siga estas etapas:
- Quando o evento que aciona a transição ocorrer, chame o método
TransitionManager.beginDelayedTransition()
, que fornece a visualização pai de todas as visualizações que você quer mudar e a transição a ser usada. O framework armazena os arquivos estado das visualizações filhas e seus valores de propriedade. - Faça alterações nas visualizações filhas conforme necessário para seu caso de uso. A estrutura registra as alterações que você faz nas visualizações filhas e suas propriedades.
- Quando o sistema redesenha a interface do usuário de acordo com as alterações, a framework anima as mudanças entre o estado original e o novo.
O exemplo a seguir mostra como animar a adição de uma visualização de texto a uma visualização usando uma transição atrasada. O primeiro snippet mostra o layout arquivo de definição:
res/layout/activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/mainLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <EditText android:id="@+id/inputText" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> ... </androidx.constraintlayout.widget.ConstraintLayout>
O próximo snippet mostra o código que anima o acréscimo da visualização de texto:
MainActivity
Kotlin
setContentView(R.layout.activity_main) val labelText = TextView(this).apply { text = "Label" id = R.id.text } val rootView: ViewGroup = findViewById(R.id.mainLayout) val mFade: Fade = Fade(Fade.IN) TransitionManager.beginDelayedTransition(rootView, mFade) rootView.addView(labelText)
Java
private TextView labelText; private Fade mFade; private ViewGroup rootView; ... // Load the layout. setContentView(R.layout.activity_main); ... // Create a new TextView and set some View properties. labelText = new TextView(this); labelText.setText("Label"); labelText.setId(R.id.text); // Get the root view and create a transition. rootView = (ViewGroup) findViewById(R.id.mainLayout); mFade = new Fade(Fade.IN); // Start recording changes to the view hierarchy. TransitionManager.beginDelayedTransition(rootView, mFade); // Add the new TextView to the view hierarchy. rootView.addView(labelText); // When the system redraws the screen to show this update, // the framework animates the addition as a fade in.
Definir callbacks do ciclo de vida da transição
O ciclo de vida da transição é semelhante ao da atividade. Ela representa
declara que o framework monitora durante o período entre uma chamada
à função TransitionManager.go()
e a conclusão
a animação. Em estados importantes do ciclo de vida, o framework invoca callbacks
definido pela classe TransitionListener
interface gráfica do usuário.
Os callbacks do ciclo de vida da transição são úteis, por exemplo, para copiar uma visualização.
Valor de propriedade da hierarquia de visualização inicial para a hierarquia de visualização final
durante uma mudança de cena. Não é possível simplesmente copiar o valor da visualização inicial para
a visualização na hierarquia final, já que ela não é
inflado até que a transição seja concluída. Em vez disso, você precisa armazenar o valor
em uma variável e a copia para a hierarquia de visualização final quando o framework
tiver concluído a transição. Para receber uma notificação quando a transição terminar,
implementar
TransitionListener.onTransitionEnd()
em sua atividade.
Para obter mais informações, consulte a referência de API para a
TransitionListener
.
Limitações
Esta seção lista algumas limitações conhecidas do framework de transições:
- Animações aplicadas a uma
Talvez
SurfaceView
não apareça corretamente. As instâncias deSurfaceView
são atualizadas em uma linha de execução que não é de interface. Portanto, a atualizações podem estar fora de sincronia com as animações de outras visualizações. - Alguns tipos específicos de transição podem não produzir o efeito de animação desejado.
quando aplicado a um
TextureView
. - Classes que se estendem
AdapterView
, comoListView
, gerenciam as visualizações filhas de maneiras incompatíveis com o framework de transições. Se você tentar animar uma visualização com base emAdapterView
, a tela do dispositivo pode parar de responder. - Se você tentar redimensionar um
TextView
com em uma animação, o texto salta para um novo local antes que o objeto seja completamente redimensionados. Para evitar esse problema, não anime o redimensionamento de visualizações que contenham em textos.