Android Buttom Sheet
Aprenda a implementação do Buttom Sheet Dialog, que é a era moderna de exibição de diálogos, menus, etc …
Conteudo
O que é Buttom Sheet?
Um botton sheet é um padrão de interface do usuário ou um componente usado para exibir uma visualização descartável da parte inferior da tela. Esta visualização dispensável contém um conjunto de opções relacionadas principalmente a algumas ações. Na tendência atual, a maioria dos aplicativos está usando esse padrão para simplificar as ações. Esse padrão foi observado pela primeira vez no IOS. Em termos simples, nada mais é do que uma visualização que fica na parte inferior da tela e aparece com animação quando acionada.
“Botton sheet é que contêm conteúdo suplementar ancorado na parte inferior da tela” – de acordo com os Documentos do Material Design
Por que precisamos de Buttom Sheet?
Em vez de caixas de diálogo e menus legados, os bottom sheet fornecem uma solução animada flexível na ponta dos dedos para exibir informações ou uma seleção fácil em uma lista de opções. Como essas visualizações ficam na parte inferior, podemos acessar facilmente o conteúdo para selecionar uma opção ou fazer alguma ação. Essa tem sido a solução comum para muitos aplicativos hoje em dia para resolver a abordagem de exibir mais opções.
Que tipos de buttom sheet estão disponíveis?
Dependendo dos requisitos, existem três tipos diferentes de buttom sheet disponíveis. Esses são:
Buttom Sheet padrão
Os Buttom Sheet padrão exibem o conteúdo que complementa o conteúdo principal da tela. Eles permanecem visíveis enquanto os usuários interagem com o conteúdo principal. Ao usar as folhas inferiores padrão, o usuário pode visualizar e interagir com as folhas inferiores e o resto da tela, o que é útil no caso de multitarefa. Mais adequado para aplicativos como um reprodutor de música, pois permite que os usuários controlem suas músicas enquanto navegam pelos álbuns.
Modal bottom sheets
BottomSheetDialogFragment é uma camada fina no topo da biblioteca de suporte regular Fragment que renderiza seu fragmento como um buttom sheet modal, fundamentalmente atuando como um diálogo. Esta foi a melhor alternativa aos menus embutidos atuais ou diálogos simples. Essas caixas de diálogo da página inferior são uma sobreposição do conteúdo principal e devem ser descartadas para interagir com o conteúdo principal. Uma sobreposição de desfoque será exibida acima da página inferior e do conteúdo principal. Se o conteúdo fora da caixa de diálogo for tocado, a página inferior será descartada. As folhas inferiores modais podem ser arrastadas verticalmente e descartadas deslizando-as completamente para baixo.
Expansão dos Buttom Sheet
As folhas inferiores expansíveis fornecem uma superfície pequena e recolhida que pode ser expandida pelo usuário para acessar um recurso ou tarefa importante. Eles oferecem o acesso persistente de um buttom sheet padrão com o espaço e o foco de um buttom sheet modal.
Implementação
Vamos verificar um exemplo simples de exibição de uma caixa de diálogo de buttom sheet inferior com o clique de um botão. Vamos verificar cada etapa individualmente para melhor compreensão.
Passo 1
Adicione a dependência de design de suporte de material no arquivo build.gradle de nível de aplicativo
implementation "com.android.support:design:27.0.2"
Passo 2
Projete o arquivo de layout que deveria ser mostrado como buttom sheet.
<?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:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="8dp"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/txt_download" style="@style/BottomSheetItem" android:drawableStart="@drawable/ic_baseline_save_alt_24" android:drawableLeft="@drawable/ic_baseline_save_alt_24" android:text="Download" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/txt_copy" style="@style/BottomSheetItem" android:drawableStart="@drawable/copy_iocn" android:drawableLeft="@drawable/copy_iocn" android:text="Copy" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/txt_download" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/txt_share" style="@style/BottomSheetItem" android:layout_marginTop="8dp" android:drawableStart="@drawable/share_iocn" android:drawableLeft="@drawable/share_iocn" android:text="Share" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/txt_copy" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/txt_whats_app" style="@style/BottomSheetItem" android:drawableStart="@drawable/ic_whatsapp_new" android:drawableLeft="@drawable/ic_whatsapp_new" android:text="Whats App" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/txt_share" /> </androidx.constraintlayout.widget.ConstraintLayout>
Você pode adicionar o estilo do item em styles.xml
<style name="BottomSheetItem"> <item name="android:textSize">20sp</item> <item name="android:drawablePadding">20dp</item> <item name="android:layout_width">0dp</item> <item name="android:layout_height">wrap_content</item> <item name="android:padding">15dp</item> <item name="fontFamily">@font/mono_bold</item> </style>
Agora terminamos com a parte de design do buttom sheet.
Passo 3
Agora estenda a classe com BottomSheetDialogFragment e substitua o método onCreateView para fornecer o layout.
package com.sample import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.sample.R import kotlinx.android.synthetic.main.bottom_sheet_options.* import java.lang.ref.WeakReference class OptionsBottomSheetFragment : BottomSheetDialogFragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.bottom_sheet_options, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setUpViews() } private fun setUpViews() { // We can have cross button on the top right corner for providing elemnet to dismiss the bottom sheet //iv_close.setOnClickListener { dismissAllowingStateLoss() } txt_download.setOnClickListener { dismissAllowingStateLoss() Toast.makeText(application, "Download option clicked", Toast.LENGTH_LONG) .show() } txt_share.setOnClickListener { dismissAllowingStateLoss() Toast.makeText(application, "Share option clicked", Toast.LENGTH_LONG) .show() } } companion object { @JvmStatic fun newInstance(bundle: Bundle): OptionsBottomSheetFragment { val fragment = OptionsBottomSheetFragment() fragment.arguments = bundle return fragment } } }
“Observação: podemos definir uma interface e enviar o retorno de chamada à atividade pai para lidar com as ações de acordo.”
Com o retorno de chamada (callback) da interface, ele será modificado da seguinte maneira
package com.sample import android.content.Context import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.sample.R import kotlinx.android.synthetic.main.bottom_sheet_layiut.* class OptionsBottomSheetFragment : BottomSheetDialogFragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.bottom_sheet_options, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setUpViews() } private fun setUpViews() { // We can have cross button on the top right corner for providing elemnet to dismiss the bottom sheet //iv_close.setOnClickListener { dismissAllowingStateLoss() } txt_download.setOnClickListener { dismissAllowingStateLoss() mListener?.onItemClick("Download") } txt_share.setOnClickListener { dismissAllowingStateLoss() mListener?.onItemClick("Share") } } private var mListener: ItemClickListener? = null override fun onAttach(context: Context) { super.onAttach(context) if (context is ItemClickListener) { mListener = context as ItemClickListener } else { throw RuntimeException( context.toString() .toString() + " must implement ItemClickListener" ) } } override fun onDetach() { super.onDetach() mListener = null } interface ItemClickListener { fun onItemClick(item: String) } companion object { @JvmStatic fun newInstance(bundle: Bundle): OptionsBottomSheetFragment { val fragment = OptionsBottomSheetFragment() fragment.arguments = bundle return fragment } } }
Passo 4
Projete um layout com um botão para mostrar a caixa de diálogo ao clicar.
<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/tv_click_me" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="30sp" android:padding="@dimen/spacing_20" android:background="@color/grey3" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" tools:text="Click Me" /> </androidx.constraintlayout.widget.ConstraintLayout>
Passo 5
A etapa final é mostrar o diálogo na atividade
package com.sample import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import kotlinx.android.synthetic.main.main.* class SampleActivity :AppCompatActivity(),OptionsBottomSheetFragment.ItemClickListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.amin) tv_click_me?.setOnClickListener { supportFragmentManager.let { OptionsBottomSheetFragment.newInstance(Bundle()).apply { show(it, tag) } } } } override fun onItemClick(param:String) { when(param){ "share"->{ //Handle data } "Download"->{ //Handle data } else->{ //Handle data } } } }
Agora declare a atividade no manifesto e execute o aplicativo, podemos ver a saída como abaixo
Bônus
Podemos até expandir a caixa de diálogo da página inferior para a altura total, definindo o atributo de altura de peek para 0
override fun setupDialog(dialog: Dialog, style: Int) { super.setupDialog(dialog, style) val rootView = View.inflate(context, R.layout.dialog_layout, null) dialog.setContentView(rootView) val bottomSheet = dialog.window?.findViewById(R.id.design_bottom_sheet) as FrameLayout val behaviour = BottomSheetBehavior.from(bottomSheet) behaviour.peekHeight = 0 }
Resumo
É isso que terminamos. Esta foi a implementação de BottomSheetDialog.