Como Criar a UI de Configurações de Conta de Usuário - Android M-Commerce

Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog. Você receberá um email de confirmação. Somente depois de confirma-lo é que poderei lhe enviar os conteúdos exclusivos.

Email inválido.
Blog /Android /Como Criar a UI de Configurações de Conta de Usuário - Android M-Commerce

Como Criar a UI de Configurações de Conta de Usuário - Android M-Commerce

Vinícius Thiengo
(1050) (5)
Go-ahead
"Falhar é duro. Mas é muito mais difícil lidar com o fato de nunca ter tentado."
Theodore Teddy Roosevelt
Kotlin Android
Capa do livro Desenvolvedor Kotlin Android - Bibliotecas para o dia a dia
TítuloDesenvolvedor Kotlin Android - Bibliotecas para o dia a dia
CategoriasAndroid, Kotlin
AutorVinícius Thiengo
Edição
Capítulos19
Páginas1035
Acessar Livro
Treinamento Oficial
Android: Prototipagem Profissional de Aplicativos
CursoAndroid: Prototipagem Profissional de Aplicativos
CategoriaAndroid
InstrutorVinícius Thiengo
NívelTodos os níveis
Vídeo aulas186
PlataformaUdemy
Acessar Curso
Receitas Android
Capa do livro Receitas Para Desenvolvedores Android
TítuloReceitas Para Desenvolvedores Android
CategoriaDesenvolvimento Android
AutorVinícius Thiengo
Edição
Ano2017
Capítulos20
Páginas936
Acessar Livro
Código Limpo
Capa do livro Refatorando Para Programas Limpos
TítuloRefatorando Para Programas Limpos
CategoriaEngenharia de Software
AutorVinícius Thiengo
Edição
Capítulos46
Páginas599
Acessar Livro
Quer aprender a programar para Android? Acesse abaixo o curso gratuito no Blog.
Conteúdo Exclusivo
Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog.
Email inválido

Tudo bem?

Neste artigo vamos continuar com o projeto Android BlueShoes, nosso aplicativo de mobile-commerce. Aqui vamos a construção da interface de usuário da área de configurações de conta.

Animação da tela de configurações conta de usuário

Vamos também a algumas atualizações importantes na atividade principal do projeto, preparando ela para também trabalhar com opções de menu gaveta que abrem outras atividades ao invés de somente fragmentos.

Antes de continuar com o projeto, não deixe de se inscrever 📩 na lista de emails do Blog para ter acesso exclusivo aos novos conteúdos desta série e também acesso a outros artigos e vídeos sobre desenvolvimento Android.

A seguir os tópicos do artigo:

Estou iniciando no projeto Android BlueShoes

Você chegou a está série de Android mobile-commerce somente agora? Então saiba que já existem outras 10 aulas disponíveis antes desta, aulas que devem ser estudas primeiro do que esta para que você não fique "perdido" no projeto:

Estratégia para a tela de configurações de conta:

O roteiro adotado no desenvolvimento da tela de configurações de conta de usuário não será diferente de outros roteiros já praticados neste projeto.

Vamos, então, seguir:

  • Primeiro as configurações estáticas que dispensam a necessidade de a atividade de configurações de conta já estar pronta;
  • Depois os códigos dinâmicos da nova atividade de configurações de conta, incluindo os códigos estáticos que somente podem ser trabalhados depois da existência de alguns dos códigos dinâmicos;
  • Por fim a atualização na atividade principal de projeto, pois é ela que permitirá o acesso a área de configurações de conta. Neste trecho teremos um pouco mais de trabalho do que o comum, principalmente em classes auxiliares à atividade principal.

Protótipo estático

A seguir o protótipo estático da tela de configurações de conta de usuário:

 Opções de configuração

Opções de configuração

 Bem simples, certo? A dificuldade mesmo estará no modo de acesso a tela acima.

Trabalhando a atividade de configurações de conta

Bom, chegou o momento de "colocar a mão na massa", mesmo que seja iniciando pela parte simples: codificação estática.

Mas antes de prosseguir é importante lembrar que o projeto Android BlueShoes está gratuitamente disponível no repositório dele em: https://github.com/viniciusthiengo/blueshoes-kotlin-android.

Mas, de preferência, utilize os códigos do repositório somente se você enfrentar alguma dificuldade quando seguindo os artigos de construção do projeto, pois são os artigos que contém as explicações passo a passo do porquê de determinado algoritmo ou API em uso, além, claro, dos códigos completos.

Arquivo de cores

No arquivo de configurações de cores, /res/values/colors.xml, adicione as cores em destaque a seguir:

<?xml version="1.0" encoding="utf-8"?>
<resources>
...

<color name="colorTextBox">#EEEEEE</color>
<color name="colorLightGrey">#AAAAAA</color>
<color name="colorLighterGrey">#EFEFEF</color>
</resources>

Lembrando que os arquivos estáticos atualizados ou criados antes do desenvolvimento dos códigos de atividade são assim feitos, pois o protótipo estático nos fornece informações suficientes para seguirmos assim.

Arquivo de Strings

Para o arquivo de Strings temos de realizar algumas adições. Em /res/values/strings.xml adicione os trechos em destaque abaixo:

<resources>
...

<!-- AccountSettingsActivity -->
<string name="title_activity_account_settings">
Configurações de conta
</string>

<string name="connected">Conectado:</string>

<string name="setting_item_profile">Perfil</string>
<string name="setting_item_profile_desc">
Para atualização de nome e foto de perfil.
</string>

<string name="setting_item_login">Conexão (login)</string>
<string name="setting_item_login_desc">
Para atualização de e-mail ou senha de acesso.
</string>

<string name="setting_item_address">Endereços</string>
<string name="setting_item_address_desc">
Para adição, remoção ou atualização de endereços de entrega.
</string>

<string name="setting_item_credit_cards">Cartões de crédito</string>
<string name="setting_item_credit_cards_desc">
Para adição e remoção de cartões de crédito.
</string>
</resources>

Atualizando o pacote de domínio do problema

Como você deve ter percebido no protótipo estático, nós utilizaremos algum framework de lista na área de configurações de conta. Mais precisamente, o framework será o RecyclerView.

Framework de lista RecyclerView da tela de configurações de conta

Com isso é uma escolha inteligente ampliarmos o nosso conjunto de classes de domínio de problema, adicionando a classe responsável por ser a origem dos objetos que vão conter os dados de cada item de lista.

Em /domain adicione a classe AccountSettingItem com o código a seguir:

class AccountSettingItem(
val label: String,
val description: String
)

Base de dados local para itens de configuração de conta

Com a nossa nova classe de domínio, podemos já colocar em algum ponto do projeto os dados que preencherão o framework de lista da UI de configurações de conta.

Lembrando que as opções desta lista são estáticas e se futuramente passarem por atualizações, essas virão em novas versões do aplicativo, ou seja, não faz sentido utilizar uma persistência de dados dinâmica para guardar esses dados.

Em /data crie a classe AccountSettingsItemsDataBase com o código abaixo:

class AccountSettingsItemsDataBase {

companion object{

fun getItems( context: Context )
= listOf(
AccountSettingItem(
context.getString( R.string.setting_item_profile ),
context.getString( R.string.setting_item_profile_desc )
),
AccountSettingItem(
context.getString( R.string.setting_item_login ),
context.getString( R.string.setting_item_login_desc )
),
AccountSettingItem(
context.getString( R.string.setting_item_address ),
context.getString( R.string.setting_item_address_desc )
),
AccountSettingItem(
context.getString( R.string.setting_item_credit_cards ),
context.getString( R.string.setting_item_credit_cards_desc )
)
)
}
}

 

Como desta vez não há a necessidade de mantermos ativos os objetos de lista, mesmo com a possibilidade de reconstrução da atividade de configurações de conta quando em execução, não estamos utilizando, por exemplo, a API SelectionTracker (ela não é útil aqui).

Assim podemos seguramente fazer o uso de companion object para retirarmos das classes clientes de AccountSettingsItemsDataBase a necessidade de uma inicialização e gerenciamento de objeto.

Classe adaptadora de itens de configuração

Sim, sim, sim! Ainda há mais entidades a serem criadas antes da atividade de configurações de conta. Neste ponto do artigo já não é novidade que estaremos utilizando o RecyclerView como o framework de lista nesta tela.

Sendo assim, vamos primeiro à construção do layout de item.

Em /res/layout adicione o XML account_settings_item.xml com o código a seguir:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingRight="16dp"
android:paddingEnd="16dp"
android:paddingLeft="16dp"
android:paddingStart="16dp"
android:paddingTop="18dp"
android:paddingBottom="18dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:id="@+id/tv_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:textStyle="bold"
android:textColor="@color/colorText"/>

<TextView
android:id="@+id/tv_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/colorLightGrey"/>
</LinearLayout>

 

Layout bem simples, certo? O diagrama dele comprova isso:

Diagrama do layout account_settings_item.xml

Agora, em /view, crie a classe adaptadora AccountSettingsItemsAdapter com o código a seguir:

class AccountSettingsItemsAdapter(
private val items: List<AccountSettingItem>
) :
RecyclerView.Adapter<AccountSettingsItemsAdapter.ViewHolder>() {

override fun onCreateViewHolder(
parent: ViewGroup,
type: Int ): ViewHolder {

val layout = LayoutInflater
.from( parent.context )
.inflate(
R.layout.account_settings_item,
parent,
false
)

return ViewHolder( layout )
}

override fun onBindViewHolder(
holder: ViewHolder,
position: Int ) {

holder.setData( items[ position ] )
}

override fun getItemCount() = items.size

inner class ViewHolder( itemView: View ) :
RecyclerView.ViewHolder( itemView ){

private val tvLabel : TextView
private val tvDescription : TextView

init{
tvLabel = itemView.findViewById( R.id.tv_label )
tvDescription = itemView.findViewById( R.id.tv_description )
}

fun setData( item: AccountSettingItem ){
tvLabel.text = item.label
tvDescription.text = item.description
}
}
}

 

Assim podemos prosseguir à atividade de configurações de conta.

Criando a AccountSettingsActivity

Siga, no pacote /view do projeto:

  • Clique com o botão direito do mouse;
  • Acesse New;
  • Então acesse Activity;
  • Clique em Basic Activity;
  • Na caixa de diálogo aberta:
    • Em Activity Name coloque AccountSettingsActivity;
    • Em Layout Name continue com activity_account_settings;
    • Não marque a opção Launcher Activity;
    • Não marque a opção Use a Fragment;
    • Deixe Hierarchical Parent sem alteração;
    • Em Package Name permaneça com"Nome do pacote".view;
    • Em Source Language permaneça com Kotlin;
    • Por fim clique em Finish.

Criação da atividade AccountSettingsActivity

Pode ser que uma tela de alerta seja apresentada. Caso sim, clique em Proceed anyway.

Ao final da criação da atividade AccountSettingsActivity nós teremos o seguinte código:

class AccountSettingsActivity : 
AppCompatActivity() {

override fun onCreate( savedInstanceState: Bundle? ) {
super.onCreate( savedInstanceState )
setContentView( R.layout.activity_account_settings )
setSupportActionBar( toolbar )

fab.setOnClickListener { view ->
Snackbar
.make(
view,
"Replace with your own action",
Snackbar.LENGTH_LONG
)
.setAction(
"Action",
null
)
.show()
}
supportActionBar?.setDisplayHomeAsUpEnabled( true )
}
}

 

Seguramente remova o código do FloatingActionButton. Assim teremos:

class AccountSettingsActivity : 
AppCompatActivity() {

override fun onCreate( savedInstanceState: Bundle? ) {
super.onCreate( savedInstanceState )
setContentView( R.layout.activity_account_settings )
setSupportActionBar( toolbar )

supportActionBar?.setDisplayHomeAsUpEnabled( true )
}
}

 

Agora coloque os códigos que permitem a volta à atividade anterior, MainActivity, que permitiu o acesso a área de configurações de conta:

class AccountSettingsActivity :
AppCompatActivity() {

override fun onCreate( ... ) {
...

supportActionBar?.setDisplayShowHomeEnabled( true )
}

override fun onOptionsItemSelected( item: MenuItem ): Boolean {
if( item.itemId == android.R.id.home ){
finish()
return true
}
return super.onOptionsItemSelected( item )
}
}

 

Assim adicione os códigos de inicialização da lista de opções de configurações de conta:

class AccountSettingsActivity :
AppCompatActivity() {

override fun onCreate( ... ) {
...

initItems()
}
...

/*
* Método que inicializa a lista de itens de configurações
* de conta.
* */
private fun initItems(){
rv_account_settings_items.setHasFixedSize( false )

val layoutManager = LinearLayoutManager( this )
rv_account_settings_items.layoutManager = layoutManager

val divider = DividerItemDecoration(
this,
layoutManager.getOrientation()
)
divider.setDrawable(
ContextCompat.getDrawable(
this,
R.drawable.light_grey_divider_line
)!!
)
rv_account_settings_items.addItemDecoration( divider )

rv_account_settings_items.adapter = AccountSettingsItemsAdapter(
AccountSettingsItemsDataBase.getItems( this )
)
}
}

 

Ops! E sobre o drawable light_grey_divider_line utilizado em ContextCompat.getDrawable()?

Sim, sim. Este é necessário para que possamos manter o uso de DividerItemDecoration, a maneira correta de colocar linhas divisoras entre os itens do RecyclerView, porém com a cor que quisermos.

DividerItemDecoration na cor cinza claro

Em /res/drawable adicione o XML light_grey_divider_line.xml com o código a seguir:

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

<size
android:width="1dp"
android:height="1dp" />

<solid android:color="@color/colorLighterGrey" />
</shape>

 

E o layout principal?

Este é o nosso próximo assunto.

Layout principal

Na verdade o layout principal da atividade de configurações de conta é feito também por outros layouts.

Vamos iniciar com o layout de conteúdo, o que contém também o framework de lista. Em /res/layout crie (ou atualize) o XML content_account_settings.xml com o código abaixo:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:id="@+id/tv_user_connected"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:textColor="@color/colorText"
android:textStyle="bold"
android:background="@color/colorTextBox"/>

<android.support.v7.widget.RecyclerView
android:id="@+id/rv_account_settings_items"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="vertical"/>

</LinearLayout>

 

O TextView de topo é o que conterá o nome do usuário conectado:

Cabeçalho da área de configurações de conta

A seguir o diagrama do layout anterior:

Diagrama do layout content_account_settings.xml

Agora o layout principal. Isso, pois o layout de topo, app_bar.xml, já existe em projeto. Em /res/layout atualize o XML activity_account_settings.xml com o código a seguir:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">

<include layout="@layout/app_bar" />

<include layout="@layout/content_account_settings" />

</android.support.design.widget.CoordinatorLayout>

 

Abaixo o simples diagrama do layout anterior:

Diagrama do layout activity_account_settings.xml

Assim a atualização final em AccountSettingsActivity para que seja possível colocar o nome do usuário na área destinada a ele em tela. No onCreate() desta atividade adicione os códigos em destaque:

...
override fun onCreate( ... ) {
...

/*
* Colocando em tela o usuário conectado.
* */
val user = intent.getParcelableExtra<User>( User.KEY )
tv_user_connected.text = String.format(
"%s %s",
getString( R.string.connected ),
user.name
)

initItems()
}
...

 

Thiengo, por que o uso de getParcelableExtra<User>(), sendo que eu não lembro de a classe User ser um Parcelable?

Calma, ainda chegaremos a este ponto do projeto.

Configuração do AndroidManifest

Note que no AndroidManifest.xml a nova atividade deverá estar configurada como a seguir:

<?xml version="1.0" encoding="utf-8"?>
<manifest
...>

<application
...>
...

<activity
android:name=".view.AccountSettingsActivity"
android:label="@string/title_activity_account_settings"
android:theme="@style/AppTheme.NoActionBar"/>
</application>
</manifest>

User precisa ser um Parcelable

Lembra de sua dúvida sobre o User não ter a implementação da Interface Parcelable?

Então, este é o momento. Atualize a classe User para a nova configuração dela:

class User(
val name: String,
val image: Int,
val status: Boolean = false
) : Parcelable {

constructor(source: Parcel) : this(
source.readString(),
source.readInt(),
1 == source.readInt()
)

override fun describeContents() = 0

override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {
writeString(name)
writeInt(image)
writeInt((if (status) 1 else 0))
}

companion object {
const val KEY = "user-key"

@JvmField
val CREATOR: Parcelable.Creator<User> = object : Parcelable.Creator<User> {
override fun createFromParcel(source: Parcel): User = User(source)
override fun newArray(size: Int): Array<User?> = arrayOfNulls(size)
}
}
}

 

Assim será possível enviar o objeto User, que está presente na MainActivity, para a AccountSettingsActivity, isso utilizando apenas uma Intent.

Atualização da atividade principal

Chegamos a um outro passo importante da adição da área de configurações de conta do usuário.

O acesso a está área é por meio do menu gaveta de usuário conectado. Já temos todos os códigos estáticos prontos, aqui trabalharemos somente códigos dinâmicos, Kotlin.

Mas há um sério problema que surge junto ao conhecimento de: a tela de configurações de conta é uma atividade e não um fragmento.

Problema! Desta vez é uma atividade

Pela tela de configurações de conta ser uma atividade, quase todos os algoritmos de item selecionado em menu gaveta não serão úteis. Mas mesmo assim o comportamento visual do menu gaveta deve ser consistente.

A primeira ideia em mente poderia ser: vamos apenas colocar um bloco condicional em onItemStateChanged() para saber quando chamar o algoritmo de mudança de fragmento e quando chamar o algoritmo de mudança de atividade.

Certo, mas somente assim provavelmente teríamos o seguinte resultado:

Animação do problema no menu gaveta

Veja como fica o menu gaveta na volta da atividade de configurações de conta. O item errado permanece selecionado.

Mas a simples ideia apresentada não está errada não, a solução é por ai mesmo, porém com ainda mais APIs de auxílio, incluindo uma API de persistência!

Proposta de solução

Como uma proposta de solução, sem necessitar de APIs externas ao Android SDK, podemos:

  • Persistir em uma base local, antes de abrir uma atividade acionada por item de menu, o ID do fragmento aberto em tela atualmente;
  • Salvar, também em uma base local, que a entidade que está sendo acionada é uma atividade e não um fragmento;
  • Então abrir a atividade;
  • Na volta da atividade acionada para a MainActivity, acessar o ID do último fragmento apresentado em tela e assim invocar novamente a seleção dele em menu gaveta;
  • Também atualizar o estado do último item de menu gaveta acionado, digo, atualizar na persistência, deixando claro que não mais é uma atividade.

Os fluxogramas a seguir certamente vão facilitar o entendimento da estrutura da solução proposta. Primeiro o fluxograma de acionamento de fragmento ou atividade:

Fluxograma de acionamento de fragmento ou atividade

Assim o fluxograma de "volta a MainActivity":

Fluxograma de acionamento da volta a MainActivity

Com isso vamos por a "mão na massa".

Configurando o SharedPreferences na base de itens de menu

Como base local utilizaremos o SharedPreferences, por ser simples e rápido.

A seguir a lista do que precisaremos do SharedPreferences:

  • Salvar o ID do último item de fragmento apresentado em tela;
  • Obter o ID do último item de fragmento apresentado em tela;
  • Salvar se o item acionado atualmente é um item que aciona uma atividade;
  • Obter se o último item acionado foi um item que aciona uma atividade.

No pacote /data do projeto nós já temos uma classe que contém dados de itens de menu gaveta, NavMenuItemsDataBase. Sendo assim vamos adicionar a ela os novos códigos necessários aos trabalhos com o SharedPreferences em nosso domínio de problema:

class NavMenuItemsDataBase( ... ) {
...

companion object{
const val SP_NAME = "SP_NAV_MENU"
const val SP_ITEM_ID_KEY = "item-id"
const val SP_IS_ACTIVITY_KEY = "is-activity"
}

private fun getSP( context: Context )
= context.getSharedPreferences(
SP_NAME,
Context.MODE_PRIVATE
)

/*
* Salva o ID do último item de menu selecionado que
* aciona um fragmento.
* */
fun saveLastSelectedItemFragmentID( context: Context, itemID: Long ){
val sp = getSP( context )
sp.edit().putLong( SP_ITEM_ID_KEY, itemID ).apply()
}

/*
* Retorna o ID do último item de menu selecionado que
* aciona um fragmento.
* */
fun getLastSelectedItemFragmentID( context: Context ) : Long {
val sp = getSP( context )
return sp.getLong( SP_ITEM_ID_KEY, 0 )
}

/*
* Salva se o último item de menu acionado foi ou não
* um item que aciona uma atividade.
* */
fun saveIsActivityItemFired( context: Context, isActivity: Boolean ){
val sp = getSP( context )
sp.edit()
.putBoolean( SP_IS_ACTIVITY_KEY, isActivity )
.apply()
}

/*
* Informa se o último item de menu acionado foi ou não
* um item que aciona uma atividade.
* */
fun wasActivityItemFired( context: Context ) : Boolean {
val sp = getSP( context )
return sp.getBoolean( SP_IS_ACTIVITY_KEY, false )
}
}

 

Assim vamos às atualizações reais na MainActivity.

Algoritmos de abertura da AccountSettingsActivity

É certo que utilizaremos algum objeto do tipo NavMenuItemsDataBase na MainActivity. Na verdade nós precisamos somente de um e já existe um na atividade principal, porém não como uma propriedade de classe:

...
private fun initNavMenu( ... ){

val navMenu = NavMenuItemsDataBase( this )
...
}
...

 

Vamos atualizar a MainActivity para que primeiro o navMenu se torne uma propriedade de classe. Assim, nesta classe adicione os códigos em destaque:

class MainActivity :
AppCompatActivity() {
...

lateinit var navMenu: NavMenuItemsDataBase
...

private fun initNavMenu( ... ){

navMenu = NavMenuItemsDataBase( this )
...
}
...
}

 

Agora precisamos invocar o método de navMenu que salva o ID do último item de fragmento acionado. Para isso vamos criar um novo método na MainActivity que vai conter todo o algoritmo de seleção de fragmento.

Crie o método itemCallFragment() com o código a seguir:

...
private fun itemCallFragment(
key: Long,
callbackRemoveSelection: ()->Unit
){
/*
* Para garantir que somente um item de lista se
* manterá selecionado, é preciso acessar o objeto
* de seleção da lista de itens de usuário conectado
* para então remover qualquer possível seleção
* ainda presente nela. Sempre haverá somente um
* item selecionado, mas infelizmente o método
* clearSelection() não estava respondendo como
* esperado, por isso a estratégia a seguir.
* */
callbackRemoveSelection()

navMenu.saveLastSelectedItemFragmentID( this, key )

if( !navMenu.wasActivityItemFired( this ) ){
/*
* Somente permiti a real seleção de um fragmento e o
* fechamento do menu gaveta se o item de menu anterior
* selecionado não tiver sido um que aciona uma atividade.
* Caso contrário o fragmento já em tela deve continuar
* e o menu gaveta deve permanecer aberto.
* */

val fragment = getFragment( key )
replaceFragment( fragment )

/*
* Fechando o menu gaveta.
* */
drawer_layout.closeDrawer( GravityCompat.START )
}
else{
navMenu.saveIsActivityItemFired( this, false )
}
}
...

 

Note que temos mais um bloco condicional dentro dos algoritmos de seleção de fragmento. Isso para garantir que o fragmento que já estava aberto não seja recarregado quando a volta for de uma atividade acionada por um item de menu.

Esse recarregamento seria desnecessário e em alguns casos serviria somente para consumir banda de Internet do usuário.

Agora precisamos do algoritmo de itens de menu que acionam atividades.

Na MainActivity adicione o método itemCallActivity() com o código a seguir:

...
private fun itemCallActivity(
key: Long,
callbackRemoveSelection: ()->Unit
){
callbackRemoveSelection()

lateinit var intent : Intent

when( key ){
R.id.item_settings.toLong() -> {
intent = Intent(
this,
AccountSettingsActivity::class.java
)
intent.putExtra( User.KEY, user )
}
}

navMenu.saveIsActivityItemFired( this, true )

startActivity( intent )
}
...

 

Assim precisamos de um método que informa quando o item de menu acionado é ou não um item que aciona uma atividade. Ainda na MainActivity adicione o método isActivityCallInMenu() com o código abaixo:

...
/*
* Alguns itens do menu gaveta de usuário conectado acionam
* a abertura de uma atividade e não a abertura de um novo
* fragmento, dessa forma o método abaixo será útil em
* lógicas de negócio para informar quais são os itens que
* acionam atividades.
* */
fun isActivityCallInMenu( key: Long )
= when( key ){
R.id.item_settings.toLong() -> true
else -> false
}
...

 

Assim podemos partir para o novo código do método onItemStateChanged() da classe SelectObserverNavMenuItems, uma classe interna a MainActivity:

...
override fun onItemStateChanged(
key: Long,
selected: Boolean ) {
super.onItemStateChanged( key, selected )

/*
* Padrão Cláusula de Guarda para não seguirmos
* com o processamento em caso de item perdendo
* seleção. O processamento posterior ao condicional
* abaixo é somente para itens obtendo a seleção,
* selected = true.
* */
if( !selected ){
return
}

if( isActivityCallInMenu( key ) ) {
itemCallActivity( key, callbackRemoveSelection )
}
else {
itemCallFragment( key, callbackRemoveSelection )
}
}
...

 

Por fim precisamos do algoritmo responsável por acionar o último item de fragmento ativo antes do acionamento de um item de atividade.

Na MainActivity coloque o método onResume() com a seguinte configuração:

...
override fun onResume() {
super.onResume()

/*
* Se o último item de menu gaveta selecionado foi um
* que aciona uma atividade, então temos de colocar a
* seleção de item correta em menu gaveta, item que
* estava selecionado antes do acionamento do item que
* invoca uma atividade.
* */
if( navMenu.wasActivityItemFired( this ) ){
selectNavMenuItems.select(
navMenu.getLastSelectedItemFragmentID( this )
)
}
}
...

 

Somente o objeto de seleção de item selectNavMenuItems é que deve estar no algoritmo de onResume(), pois é nesta parte da lista de itens de menu gaveta que estão os itens que acionam fragmentos.

Assim podemos partir para os testes e resultados.

Testes e resultados

Com o Android Studio aberto, vá ao menu de topo e siga para "Build", logo depois clique em "Rebuid project". Ao final do rebuild execute o projeto em seu aparelho ou emulador Android de testes.

Note que o objeto user, presente na MainActivity, deve estar com a configuração de um usuário conectado (terceiro argumento como true):

...
val user = User(
"Thiengo Vinícius",
R.drawable.user,
true /* Usuário conectado. */
)
...

 

Acessando a área de configurações de conta de usuário e voltando a MainActivity, temos:

Animação do acesso a tela de configurações de conta de usuário

Com isso finalizamos mais um importante trecho da interface de usuário de nosso projeto Android de mobile-commerce.

Não esqueça de se inscrever na 📩 lista de emails do Blog, caso você ainda não seja inscrito, para receber todas as aulas do projeto Android BlueShoes.

Se inscreva também no canal do Blog em: YouTube Thiengo.

Vídeos

Abaixo os vídeos com o passo a passo da criação da tela de configurações de conta de usuário e a atualização da atividade principal:

O projeto também pode ser acessado pelo GitHub em: https://github.com/viniciusthiengo/blueshoes-kotlin-android.

Conclusão

O desenvolvimento da tela de configurações de conta de usuário foi simples, certo? Porém os algoritmos que permitem o acesso a essa tela não foram tão triviais.

Mas com os recursos que conhecemos do Android foi possível trabalhar uma solução ainda viável sem remover códigos que estavam, a principio, dando também uma "dor de cabeça" (os códigos da SelectionTracker API principalmente).

De qualquer forma, a tela foi construída sem problemas e assim já podemos, "por que não?", seguirmos aos formulários do projeto vinculados a essa tela.

Caso você tenha dúvidas ou dicas para este projeto, incluindo uma melhor solução do que a utilizando a SharedPreferences API, deixe logo abaixo nos comentários ou me envie por e-mail, também respondo a dúvidas por lá.

Curtiu o conteúdo? Não esqueça de compartilha-lo. E, por fim, não deixe de se inscrever na 📩 lista de emails.

Abraço.

Fontes 

Set drawable for DividerItemDecoration - Resposta de Jonathan Vicente

Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog.
Email inválido

Relacionado

ViewModel Android, Como Utilizar Este Componente de ArquiteturaViewModel Android, Como Utilizar Este Componente de ArquiteturaAndroid
Trabalhando Análise Qualitativa em seu Aplicativo AndroidTrabalhando Análise Qualitativa em seu Aplicativo AndroidAndroid
Lottie API Para Animações no AndroidLottie API Para Animações no AndroidAndroid
5 livros que não são de TI, mas que um desenvolvedor deveria ler5 livros que não são de TI, mas que um desenvolvedor deveria lerEmpreendedorismo

Compartilhar

Comentários Facebook

Comentários Blog (5)

Para código / script, coloque entre [code] e [/code] para receber marcação especifica.
Forneça seu nome válido.
Forneça seu email válido.
Forneça o comentário.
Enviando, aguarde...
16/05/2019
Esse site é top demais, conteúdo de primeira.
Thiengo, ensina como adicionar video reward do admob no android studio.
Tentei a documentação dele, segui os passos, só que mostra um erro MobileAds cannot be applied, e fiquei travado nisso kkk

mRewardedVideoAd = MobileAds.getRewardedVideoAdInstance(this);
mRewardedVideoAd.setRewardedVideoAdListener(this);

da um help ai brother. valeu, abraço
Responder
Vinícius Thiengo (0) (0)
24/05/2019
Luiz, tudo bem?

Você tentou colocar o import a seguir?

import com.google.android.gms.ads.MobileAds;

Isso na atividade onde a API do AdMob está sendo utilizada.

Abraço.
Responder
25/05/2019
Sim, coloquei.
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;
import com.google.android.gms.ads.MobileAds;
mandei um e-mail pra você.
Responder
Vinícius Thiengo (0) (0)
31/05/2019
Luiz, ok.

Vou lhe responder lá.

Abraço.
Responder
10/05/2019
....parabéns e novamente obrigado Thiengo pelos seus ensinamentos e por repassar seus conhecimento a todos nós.... ficamos no aguardo da continuidade dessas aulas, com ansiedade para chegarmos logo ao final.... abraços....
Responder