De Shalom Gibly, engenheiro de software da equipe Google do Material Gallery
As transições nos aplicativos que usam Material Design dão continuidade visual. Enquanto o usuário navega, as visualizações do aplicativo mudam de estado. O movimento e a transformação reforçam a ideia de que as interfaces são tangíveis, conectando elementos comuns entre uma visualização e outra.
Nessa postagem, ofereceremos algumas diretrizes e mostraremos a implementação de uma transição contínua específica entre Android Fragments. Demonstraremos como implementar uma transição de uma imagem em um RecyclerView para uma imagem em um ViewPager e vice-versa usando "elementos compartilhados" para definir quais visualizações participam da transição e como. Além disso, lidaremos com o caso bem complicado de fazer uma transição de volta à grade de um item que estava antes fora da tela.
Esse é o resultado que queremos:
Se quiser pular a explicação e ir direto para o código, é só clicar aqui .
O que são os elementos compartilhados?
Uma transição de elemento compartilhado determina como as visualizações presentes em dois fragmentos realizam uma transição entre si. Por exemplo, uma imagem exibida em um ImageView
nos fragmentos A
e B
faz uma transição de A
para B
quando B
fica visível.
Existem vários exemplos já publicados que explicam o funcionamento dos elementos compartilhados e como implementar uma transição de fragmentos básica. Nesta postagem, ignoraremos boa parte dos conceitos básicos e detalharemos como criar uma transição que funcione corretamente para um ViewPager e no sentido inverso. Mas, se você quiser saber mais sobre transições, recomendo começar pelo site dos desenvolvedores Android e assistir à esta apresentação da Google I/O 2016.
Os desafios
Mapeamento de elementos compartilhados
Queremos ajudar você a criar uma transição de ida e volta perfeita. E isso inclui uma transição da grade para o paginador e depois outra transição de volta para a imagem em questão, mesmo quando o usuário paginou para uma imagem diferente.
Para fazer isso, precisamos encontrar uma forma de remapear dinamicamente os elementos compartilhados para dar ao sistema de transições do Android o que ele precisa para fazer a sua mágica.
Carregamento adiado
As transições de elementos compartilhados são fantásticas, mas podem ficar meio complexas quando lidam com elementos que precisam ser carregados antes que possam ser o destino de uma transição. A transição pode simplesmente não funcionar da forma esperada quando as visualizações do fragmento de destino não estão definidas e prontas.
Nesse projeto, temos duas áreas em que o tempo de carregamento afeta a transição de elementos compartilhados:
O ViewPager
demora alguns milissegundos para carregar seus fragmentos internos. Além disso, o carregamento de uma imagem em um fragmento de paginador exibido leva algum tempo e pode até incluir o tempo de download do ativo.
O RecyclerView
também sofre um atraso parecido quando carrega as imagens nas visualizações.
Design de um aplicativo de exemplo
Estrutura básica
Antes de detalharmos essas transições incríveis, vamos examinar rapidamente como o aplicativo de exemplo está estruturado.
A MainActivity carrega um GridFragment
para apresentar um RecyclerView
de imagens. O adaptador do RecyclerView
carrega os itens de imagem (uma matriz constante definida na classe ImageData
) e gerencia os eventos onClick
substituindo o GridFragment
exibido por um ImagePagerFragment
.
O adaptador do ImagePagerFragment
carrega os ImageFragments
aninhados para exibir as imagens no momento da paginação.
Observação: a implementação do aplicativo de exemplo usa o Glide , que carrega imagens em visualizações de forma assíncrona. As imagens do aplicativo de exemplo foram agrupadas com ele. Porém, é bem fácil converter a classe ImageData
para armazenar strings de URL que apontam para imagens on-line.
Coordenação de uma posição selecionada/exibida
Para comunicar a posição selecionada para a imagem entre os fragmentos, usamos a MainActivity
para armazenar a posição.
Quando um item recebe um clique, ou quando a página é alterada, a MainActivity é atualizada com a posição do respectivo item.
A posição armazenada é usada depois em diversos lugares:
Ao definir a página que será exibida no ViewPager
.
Ao navegar de volta para a grade e rolar automaticamente até a posição para garantir sua visibilidade.
E, é claro, ao trabalhar com os retornos de chamada das transições, como veremos na próxima seção.
Configuração de transições
Como falamos acima, precisamos encontrar uma forma de remapear dinamicamente os elementos compartilhados para dar ao sistema de transição o que ele precisa para fazer a sua mágica.
Um mapeamento estático que define os atributos transitionName
para as visualizações de imagem no XML não funciona, já que estamos lidando com uma quantidade arbitrária de visualizações que compartilham a mesma disposição (por exemplo, visualizações infladas pelo adaptador RecyclerView
ou pelo ImageFragment
).
Para fazer isso, usamos parte dos recursos oferecidos pelo sistema de transições:
Definimos um nome para a transição nas visualizações de imagem chamando setTransitionName
. Identificamos assim a visualização com um nome exclusivo para a transição. setTransitionName
é chamada durante a vinculação da visualização no adaptador RecyclerView
da grade e onCreateView
é chamada no ImageFragment
. Nos dois locais, usamos um recurso de imagem exclusivo como o nome que identifica a visualização.
Configuramos SharedElementCallbacks
para interceptar onMapSharedElements
e ajustar o mapeamento do nome dos elementos compartilhados às visualizações. Fazemos isso na saída do GridFragment
e na entrada do ImagePagerFragment
.
Configuração da transação do FragmentManager
A primeira coisa que configuramos para iniciar uma transição para a substituição de um fragmento é a preparação da transação do FragmentManager
. Precisamos informar o sistema de que temos uma transição de elemento compartilhado.
fragment.getFragmentManager()
.beginTransaction()
.setReorderingAllowed(true) // setAllowOptimization before 26.1.0
.addSharedElement(imageView, imageView.getTransitionName())
.replace(R.id.fragment_container,
new ImagePagerFragment(),
ImagePagerFragment.class.getSimpleName())
.addToBackStack(null)
.commit();
O setReorderingAllowed
está definido como true
. Dessa forma, as mudanças de estado dos fragmentos são reordenadas para aprimorar as transições entre os elementos compartilhados. Nos fragmentos adicionados, onCreate(Bundle)
é chamada antes que os fragmentos substituídos chamem onDestroy()
, o que permite criar e dispor a visualização compartilhada antes do início da transição.
Transição de imagem
Para definir como é a transição de uma imagem no momento da animação para o novo local, definimos um TransitionSet
em um arquivo XML e o carregamos no ImagePagerFragment
.
<ImagePagerFragment.java>
Transition transition =
TransitionInflater.from(getContext())
.inflateTransition(R.transition.image_shared_element_transition);
setSharedElementEnterTransition(transition);
<image_shared_element_transition.xml>
<?xml version="1.0" encoding="utf-8"?>
<transitionSet
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="375"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:transitionOrdering="together">
<changeClipBounds/>
<changeTransform/>
<changeBounds/>
</transitionSet>
Ajuste do mapeamento do elemento compartilhado
Para começar, ajustamos o mapeamento do elemento compartilhado na saída do GridFragment
. Para isso, chamamos setExit SharedElementCallback()
e fornecemos um SharedElementCallback
que mapeia os nomes dos elementos nas visualizações que queremos incluir na transição.
É importante lembrar que esse retorno de chamada é chamado na saída do Fragment
, quando a transação de fragmento ocorre, e na reentrada no Fragment
quando ele é retirado da pilha de retorno (na navegação no sentido contrário). Usamos esse comportamento para remapear a visualização compartilhada e ajustar a transição para gerenciar casos em que a visualização é alterada depois da paginação das imagens.
Neste caso em específico, só estamos interessados em uma única transição de ImageView
, da grade ao fragmento mantido pelo paginador. Portanto, o mapeamento só precisa ser ajustado para o primeiro elemento nomeado recebido no retorno de chamada de onMapSharedElements
.
<GridFragment.java>
setExitSharedElementCallback(
new SharedElementCallback() {
@Override
public void onMapSharedElements(
List<String> names, Map<String, View> sharedElements) {
// Locate the ViewHolder for the clicked position.
RecyclerView.ViewHolder selectedViewHolder = recyclerView
.findViewHolderForAdapterPosition(MainActivity.currentPosition);
if (selectedViewHolder == null || selectedViewHolder.itemView == null) {
return;
}
// Map the first shared element name to the child ImageView.
sharedElements
.put(names.get(0),
selectedViewHolder.itemView.findViewById(R.id.card_image));
}
});
Além disso, precisamos ajustar o mapeamento do elemento compartilhado na entrada do ImagePagerFragment
. Para tanto, chamamos setEnter SharedElementCallback()
.
<ImagePagerFragment.java>
setEnterSharedElementCallback(
new SharedElementCallback() {
@Override
public void onMapSharedElements(
List<String> names, Map<String, View> sharedElements) {
// Locate the image view at the primary fragment (the ImageFragment
// that is currently visible). To locate the fragment, call
// instantiateItem with the selection position.
// At this stage, the method will simply return the fragment at the
// position and will not create a new one.
Fragment currentFragment = (Fragment) viewPager.getAdapter()
.instantiateItem(viewPager, MainActivity.currentPosition);
View view = currentFragment.getView();
if (view == null) {
return;
}
// Map the first shared element name to the child ImageView.
sharedElements.put(names.get(0), view.findViewById(R.id.image));
}
});
Adiamento da transição
As imagens que queremos usar na transição são carregadas na grade e no paginador e esse processo leva algum tempo. Para que tudo funcione da forma certa, precisamos executar um postpone (adiamento) para a transição até que as visualizações participantes estejam prontas (ou seja, dispostas e carregadas com os dados das imagens).
Fazemos isso chamando um postponeEnterTransition()
em onCreateView()
dos nossos fragmentos. Quando a imagem é carregada, começamos a transição chamando startPostponedEnterTransition()
.
Observação: o adiamento é chamado nos fragmentos da grade e do paginador para permitir transições de ida e volta durante a navegação no aplicativo.
Como estamos usando o Glide para carregar as imagens, adicionamos ouvintes que acionam a transição de entrada quando as imagens são carregadas.
Isso acontece em dois lugares:
Quando uma imagem do ImageFragment
é carregada, seu ImagePagerFragment
pai é chamado para iniciar a transição.
Em uma transição de volta para a grade, uma transição de início é chamada depois que a imagem "selecionada " é carregada.
Veja como ImageFragment
carrega uma imagem e notifica seu pai quando está pronto.
Note que a postponeEnterTransition
é feita no ImagePagerFragment
e a startPostponeEnterTransition
é chamada no ImageFragment
filho criado pelo paginador.
<ImageFragment.java>
Glide.with(this)
.load(arguments.getInt(KEY_IMAGE_RES)) // Load the image resource
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
getParentFragment().startPostponedEnterTransition();
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
getParentFragment().startPostponedEnterTransition();
return false;
}
})
.into((ImageView) view.findViewById(R.id.image));
Como você deve ter notado, também fazemos uma chamada para iniciar a transição adiada quando há uma falha no carregamento. Isso é importante para evitar que a IU trave durante a falha.
Toques finais
Para suavizar ainda mais as nossas transições, queremos esmaecer os itens da grade durante a transição da imagem para a visualização do paginador.
Para fazer isso, criamos um TransitionSet
aplicado como transição de saída do GridFragment
.
<GridFragment.java>
setExitTransition(TransitionInflater.from(getContext())
.inflateTransition(R.transition.grid_exit_transition));
<grid_exit_transition.xml>
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="375"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:startDelay="25">
<fade>
<targets android:targetId="@id/card_view"/>
</fade>
</transitionSet>
Depois de configurar a transição de saída, a nossa transição fica assim:
Como você deve ter percebido, essa configuração de finalização ainda precisa de acabamento. A animação do esmaecimento acontece para todas as visualizações de cartão da grade, incluindo o cartão que armazena a imagem que passa pela transição para o paginador.
Para resolver isso, excluímos o cartão clicado da transição de saída antes de confirmar a transação do fragmento ao GridAdapter
.
// The 'view' is the card view that was clicked to initiate the transition.
((TransitionSet) fragment.getExitTransition()).excludeTarget(view, true);
Depois dessa mudança, a animação fica bem melhor (o cartão clicado não esmaece por conta da transição de saída, mas os outros cartões, sim):
E, para dar o toque final, configuramos o GridFragment
para rolar e revelar o cartão de destino da transição quando navegamos de volta do paginador (isso é feito em onViewCreated
):
<GridFragment.java>
recyclerView.addOnLayoutChangeListener(
new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View view,
int left,
int top,
int right,
int bottom,
int oldLeft,
int oldTop,
int oldRight,
int oldBottom) {
recyclerView.removeOnLayoutChangeListener(this);
final RecyclerView.LayoutManager layoutManager =
recyclerView.getLayoutManager();
View viewAtPosition =
layoutManager.findViewByPosition(MainActivity.currentPosition);
// Scroll to position if the view for the current position is null (not
// currently part of layout manager children), or it's not completely
// visible.
if (viewAtPosition == null
|| layoutManager.isViewPartiallyVisible(viewAtPosition, false, true)){
recyclerView.post(()
-> layoutManager.scrollToPosition(MainActivity.currentPosition));
}
}
});
Conclusão
Neste artigo, implementamos uma transição suave de um RecyclerView
para um ViewPager
e vice-versa.
Mostramos como adiar uma transição até que as visualizações fiquem prontas. Também implementamos o remapeamento do elemento compartilhado para que a transição funcione quando as visualizações compartilhadas mudam dinamicamente durante a navegação no aplicativo.
Essas mudanças transformaram as transições de fragmento do aplicativo para aprimorar a continuidade visual durante a interação com os usuários.
Você pode ver o código do aplicativo de exemplo aqui .
3 comentários :
Dewapoker selalu ingin berusaha semaksimal mungkin untuk memberikan yang terbaik untuk para member yang bermain didalam situs Judi Online dewapoker 2018 , seperti misalnya layanan customer service yang selain baik, ramah, dan professional juga siap untuk melayani anda selama 24 jam full non-stop serta sigap untuk memberikan solusi-solusi untuk member yang mengalami kendala pada saat bermain. Dengan ini kami memberikan berbagai macam permainan remi dan Poker Online yang ada didalam situs dewa poker asia sudah pasti akan mejadi pilihan anda dalam bermain berbagai jenis judi online yang ada pada saat ini.
Pokerbo888 Situs Judi Poker Online Terpercaya Beberapa jenis permainan kartu /atau judi yang dinikmati oleh Pemain Judi. Pokerbo888 merupakan salah satu situs yang menyediakan Berbagai pilihan Permainan judi Kartu yang dapat nikmati Secara online di Indonesia, Yang pertama kali di Rilis pada Tahun 2000an. Tentu orang cape-cape daftar dan bermain poker melalui agen poker online pasti ingin menambah penghasilan. Dengan adanya situs Pokerbo888 semunya menjadi mudah untuk bermain judi poker online dan tidak lupa lagi banyak bonus bonus dan hadiah menarik saat anda bermain di situs kami, Gabung Sekarang dan ambil hadiah hadiah menarik lainnya.
PINGIN CEPAT KAYA ? Bingung mulai dari mana ? Baru..!! Game judi online 2019 wargapoker terpercaya. Dapatkan bonus-bonus untuk pemain baru, Ada begitu banyak jenis taruhan judi online dengan uang asli yang bisa anda mainkan di afapoker kapan saja dan dimana saja, cukup menggunakan satu user id saja. Anda dipastikan memainkan permainan judi online yang murni dominobet dimana Anda bermain 100% player vs player tanpa ada campur tangan bot link alternatif domino88 2019. Tidak perlu lagi bersusah payah mencari uang, Anda bebas menikmati waktu Anda. Situs link alternatif pokerace 2019 deposit murah yang menyediakan banyak permainan dengan pelayanan berkualitas. Jadi silahkan daftar dan segera mainkan permainan. Dijamin mudah dan cepat. Anda akan diberi pelayanan yang ramah dan cepat saat proses pendaftaran. Didukung dengan sistem terbaru dan tim profesional serta kemudahan bertransaksi. Kami menjamin kerahasiaan data member.
Wow, Amazing blog post. You may also like Best Schools In Dehradun, Best Schools In Kolkata
Postar um comentário