1. Introdução
Os componentes do Material Design (MDC, na sigla em inglês) ajudam os desenvolvedores a implementar o Material Design. Criados por uma equipe de engenheiros e designers de UX do Google, os MDC apresentam dezenas de componentes de interface bonitos e funcionais e estão disponíveis para Android, iOS, Web e Flutter.material.io/develop |
O que são o Material Design e os componentes dele para Android?
O Material Design é um sistema para criar produtos digitais bonitos e arrojados. Ao combinar estilo, branding, interação e movimento em um conjunto consistente de princípios e componentes, as equipes de produto podem atingir o maior potencial de design.
Nos apps Android, os componentes do Material Design para Android (MDC Android) combinam design e engenharia com uma biblioteca de componentes para criar consistência em todo o app. À medida que o sistema do Material Design evolui, esses componentes são atualizados para garantir uma implementação consistente com perfeição e a adesão aos padrões de desenvolvimento de front-end do Google. Os MDC também estão disponíveis para Web, iOS e Flutter.
Neste codelab, você criará uma página de login usando vários componentes MDC do Android.
O que você vai criar
Este é o primeiro de quatro codelabs que vão guiar você na criação de um app chamado Shrine, um app de e-commerce para Android que vende roupas e artigos domésticos. Ele demonstrará como você pode personalizar componentes para refletir qualquer marca ou estilo usando o MDC-Android.
Neste codelab, você criará uma página de login para o Shrine que contém:
- Dois campos de texto: um para inserir um nome de usuário e outro para uma senha.
- Dois botões, um para "Cancelar" e outra para "Próximo"
- O nome do app (Shrine).
- A imagem do logotipo do Shrine.
Componentes do MDC do Android neste codelab
- Campo de texto
- Botão
O que é necessário
- Conhecimento básico de desenvolvimento para Android.
- Android Studio (faça o download dele aqui, caso ainda não tenha feito)
- Um dispositivo ou emulador Android (disponível no Android Studio)
- O exemplo de código (confira a próxima etapa)
Como você classificaria seu nível de experiência na criação de apps Android?
2. Configurar o ambiente de desenvolvimento
Iniciar o Android Studio
Ao abrir o Android Studio, você verá uma janela com o título "Welcome to Android Studio". No entanto, se você estiver iniciando essa ferramenta pela primeira vez, siga as etapas do assistente de configuração do Android Studio com os valores padrão. O sistema pode demorar vários minutos para fazer o download e instalar os arquivos necessários, então você pode deixar o programa em execução em segundo plano enquanto acompanha a próxima seção.
Faça o download do app inicial do codelab
O app inicial está localizado no diretório material-components-android-codelabs-101-starter/java
.
... ou clone-o do GitHub
Para clonar este codelab do GitHub, execute estes comandos:
git clone https://github.com/material-components/material-components-android-codelabs cd material-components-android-codelabs/ git checkout 101-starter
Carregar o código inicial no Android Studio
- Quando o assistente de configuração for concluído e a janela Welcome to Android Studio for exibida, clique em Open an existing Android Studio project. Navegue até o diretório em que você instalou o exemplo de código e selecione java -> santuário (ou pesquise por shrine no computador) para abrir o projeto do Shrine.
- Aguarde um pouco enquanto o Android Studio cria e sincroniza o projeto, conforme mostrado nos indicadores de atividade na parte inferior da janela.
- Como o SDK do Android ou as ferramentas de compilação não estão presentes, o Android Studio poderá encontrar alguns erros de compilação. Veja um exemplo a seguir. Siga as instruções no Android Studio para instalar/atualizar essas ferramentas e sincronizar o projeto.
Adicionar dependências do projeto
O projeto precisa de uma dependência na Biblioteca de Suporte do Android para MDC. O exemplo de código que você baixou já deve ter essa dependência listada, mas é recomendável seguir as etapas a seguir para ter certeza.
- Navegue até o arquivo
build.gradle
do móduloapp
e verifique se o blocodependencies
inclui uma dependência no MDC Android:
api 'com.google.android.material:material:1.1.0-alpha06'
- (Opcional) Se necessário, edite o arquivo
build.gradle
para adicionar as dependências a seguir e sincronizar o projeto.
dependencies { api 'com.google.android.material:material:1.1.0-alpha06' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'com.android.volley:volley:1.1.1' implementation 'com.google.code.gson:gson:2.8.5' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21" testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:core:1.1.0' androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test:runner:1.2.0-alpha05' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha05' }
Executar o app inicial
|
Pronto. O código inicial da página de login do Shrine será executado no emulador. O nome "Shrine" vai aparecer, e o logotipo do Shrine logo abaixo dela.
Vamos analisar o código. Disponibilizamos um framework de navegação Fragment
simples no exemplo de código para exibir fragmentos e navegar entre eles.
Abra MainActivity.java
no diretório shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.java.shrine
. Ele conterá o código a seguir:
MainActivity.java
package com.google.codelabs.mdc.java.shrine;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
public class MainActivity extends AppCompatActivity implements NavigationHost {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.shr_main_activity);
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.add(R.id.container, new LoginFragment())
.commit();
}
}
/**
* Navigate to the given fragment.
*
* @param fragment Fragment to navigate to.
* @param addToBackstack Whether or not the current fragment should be added to the backstack.
*/
@Override
public void navigateTo(Fragment fragment, boolean addToBackstack) {
FragmentTransaction transaction =
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment);
if (addToBackstack) {
transaction.addToBackStack(null);
}
transaction.commit();
}
}
Essa atividade mostra o arquivo de layout R.layout.shr_main_activity
, definido em shr_main_activity.xml
.
Observe que, em onCreate(),
, o MainActivity.java
inicia uma transação Fragment
para mostrar o LoginFragment
. LoginFragment.
É isso que vamos modificar para este codelab. A atividade também implementa um método navigateTo(Fragment)
, definido em NavigationHost
, que permite que qualquer fragmento navegue para um fragmento diferente.
Command + Click (ou Control + Click) shr_main_activity
no arquivo de atividade para abrir o arquivo de layout, ou navegue até o arquivo de layout em app -> res -> layout -> shr_main_activity.xml
.
shr_main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" />
Aqui, vemos um <FrameLayout>
simples, que atua como um contêiner para todos os fragmentos exibidos pela atividade. Vamos abrir LoginFragment.java
.
LoginFragment.java
package com.google.codelabs.mdc.java.shrine;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
/**
* Fragment representing the login screen for Shrine.
*/
public class LoginFragment extends Fragment {
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.shr_login_fragment, container, false);
// Snippet from "Navigate to the next Fragment" section goes here.
return view;
}
// "isPasswordValid" from "Navigate to the next Fragment" section method goes here
}
LoginFragment
infla o arquivo de layout shr_login_fragment
e o exibe em onCreateView()
. Vamos dar uma olhada no arquivo de layout shr_login_fragment.xml
para ver a aparência da página de login.
shr_login_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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"
android:background="@color/loginPageBackgroundColor"
tools:context=".LoginFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
android:padding="24dp"
android:paddingTop="16dp">
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="48dp"
android:layout_marginBottom="16dp"
app:srcCompat="@drawable/shr_logo" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="132dp"
android:text="@string/shr_app_name"
android:textAllCaps="true"
android:textSize="16sp" />
<!-- Snippet from "Add text fields" section goes here. -->
<!-- Snippet from "Add buttons" section goes here. -->
</LinearLayout>
</ScrollView>
Aqui, podemos ver um <LinearLayout>
com um <ImageView>
na parte de cima, representando o "Santuário". logotipo.
Depois disso, há uma tag <TextView>
representando "SHRINE" rótulo. O texto desse rótulo é um recurso de string chamado @string/shr_app_name
. Se você clicar com Command + clique (ou Control + clicar) no nome do recurso de string ou abrir app -> res -> values -> strings.xml
, vai encontrar o arquivo strings.xml
em que os recursos de string estão definidos. Quando mais recursos de string forem adicionados no futuro, eles serão definidos aqui. Todos os recursos nesse arquivo precisam ter um prefixo shr_
para indicar que fazem parte do app Shrine.
Agora que você já conhece o código inicial, vamos implementar nosso primeiro componente.
3. Adicionar campos de texto
Para começar, vamos adicionar dois campos de texto à página de login para as pessoas digitarem o nome de usuário e a senha. Usaremos o componente campo de texto dos MDC, que inclui uma funcionalidade integrada que exibe um rótulo flutuante e mensagens de erro.
Adicionar o XML
Em shr_login_fragment.xml
, adicione dois elementos TextInputLayout
com um TextInputEditText
filho dentro de <LinearLayout>
, abaixo de "SHRINE". marcador <TextView>
:
shr_login_fragment.xml
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/shr_hint_username">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_text_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/shr_hint_password">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
O snippet acima representa dois campos de texto, cada um consistindo em um elemento <TextInputLayout>
e um filho <TextInputEditText>
. O texto de dica para cada campo de texto é especificado no atributo android:hint
.
Incluímos dois novos recursos de string para o campo de texto: @string/shr_hint_username
e @string/shr_hint_password
. Abra strings.xml
para conferir esses recursos de string.
strings.xml
...
<string name="shr_hint_username">Username</string>
<string name="shr_hint_password">Password</string>
...
Adicionar validação de entrada
Os componentes TextInputLayout
oferecem funcionalidade integrada de feedback de erros.
Para mostrar o feedback sobre o erro, faça as seguintes alterações em shr_login_fragment.xml
:
- Defina o atributo
app:errorEnabled
como verdadeiro no elementoTextInputLayout
Password . Isso vai adicionar padding extra para a mensagem de erro abaixo do campo de texto. - Definir o atributo
android:inputType
como "textPassword
" no elemento SenhaTextInputEditText
. Isso ocultará o texto de entrada no campo da senha.
Com essas mudanças, os campos de texto em shr_login_fragment.xml
vão ficar assim:
shr_login_fragment.xml
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/shr_hint_username">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_text_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/shr_hint_password"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>
Agora tente executar o app. Uma página com dois campos de texto para "Nome de usuário" vai aparecer. e "Senha"!
Veja a animação de etiquetas flutuantes:
4. Adicionar botões
Em seguida, adicionaremos dois botões à página de login: "Cancel" e "Next". Vamos usar o componente Botão MDC, que vem com o icônico efeito de ondulação de tinta do Material Design integrado.
Adicionar o XML
No shr_login_fragment.xml
, adicione um <RelativeLayout>
ao <LinearLayout>
, abaixo dos elementos TextInputLayout
. Em seguida, adicione dois elementos <MaterialButton>
ao <RelativeLayout>
.
O arquivo XML resultante ficará assim:
shr_login_fragment.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.button.MaterialButton
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:text="@string/shr_button_next" />
<com.google.android.material.button.MaterialButton
android:id="@+id/cancel_button"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:layout_marginRight="12dp"
android:layout_toStartOf="@id/next_button"
android:layout_toLeftOf="@id/next_button"
android:text="@string/shr_button_cancel" />
</RelativeLayout>
Pronto! Ao executar o app, uma ondulação de tinta vai aparecer quando você tocar em cada botão.
5. Navegar para o próximo fragmento
Por fim, vamos adicionar código Java a LoginFragment.java
para conectar o "NEXT" para outro fragmento. Você notará que cada um dos componentes que adicionamos ao layout tinha um id
atribuído a ele. Vamos usar essas id
s para referenciar os componentes no código e adicionar algumas verificações de erros e navegação.
Vamos adicionar um método booleano privado isPasswordValid
em LoginFragment.java
abaixo de onCreateView()
, com uma lógica para determinar se a senha é válida ou não. Para esta demonstração, vamos verificar se a senha tem pelo menos oito caracteres:
LoginFragment.java
/*
In reality, this will have more complex logic including, but not limited to, actual
authentication of the username and password.
*/
private boolean isPasswordValid(@Nullable Editable text) {
return text != null && text.length() >= 8;
}
Em seguida, adicione um listener de clique ao botão "Next". que define e limpa o erro com base no método isPasswordValid()
que acabamos de criar. Em onCreateView()
, esse listener de clique precisa ser colocado entre a linha infladora e a linha return view
.
Em seguida, vamos adicionar um listener de tecla à senha TextInputEditText
para detectar eventos de tecla que limpariam o erro. Esse listener também precisa usar isPasswordValid()
para verificar se a senha é válida ou não. Você pode adicionar isso diretamente abaixo do listener de clique em onCreateView()
.
Seu método onCreateView() agora vai ficar assim:
LoginFragment.java
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.shr_login_fragment, container, false);
final TextInputLayout passwordTextInput = view.findViewById(R.id.password_text_input);
final TextInputEditText passwordEditText = view.findViewById(R.id.password_edit_text);
MaterialButton nextButton = view.findViewById(R.id.next_button);
// Set an error if the password is less than 8 characters.
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!isPasswordValid(passwordEditText.getText())) {
passwordTextInput.setError(getString(R.string.shr_error_password));
} else {
passwordTextInput.setError(null); // Clear the error
}
}
});
// Clear the error once more than 8 characters are typed.
passwordEditText.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int i, KeyEvent keyEvent) {
if (isPasswordValid(passwordEditText.getText())) {
passwordTextInput.setError(null); //Clear the error
}
return false;
}
});
return view;
}
Agora, podemos navegar para outro fragmento. Atualize o OnClickListener
em onCreateView()
para navegar para outro fragmento quando a validação de erro for bem-sucedida. Você pode fazer isso adicionando a seguinte linha para navegar até ProductGridFragment
no caso else
do listener de clique:
LoginFragment.java
...
((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
...
Seu listener de clique será semelhante a este:
LoginFragment.java
...
MaterialButton nextButton = view.findViewById(R.id.next_button);
// Set an error if the password is less than 8 characters.
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!isPasswordValid(passwordEditText.getText())) {
passwordTextInput.setError(getString(R.string.shr_error_password));
} else {
passwordTextInput.setError(null); // Clear the error
((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
}
}
});
...
Essa nova linha de código chama o método navigateTo()
do MainActivity
para navegar até um novo fragmento, ProductGridFragment
. No momento, esta é uma página vazia em que você trabalhará no MDC-102.
Agora, crie o app. Pressione o botão "Próxima".
Você conseguiu! Essa tela será o ponto de partida do nosso próximo codelab, em que você vai trabalhar no MDC-102.
6. Tudo pronto
Usando marcação XML básica e aproximadamente 30 linhas de Java, a biblioteca Material Components para Android ajudou você a criar uma bela página de login que está em conformidade com as diretrizes do Material Design, além de ter uma aparência e um comportamento consistentes em todos os dispositivos.
Próximas etapas
O campo de texto e o botão são dois componentes principais da biblioteca Android MDC, mas há muito mais. Você pode explorar o restante dos componentes no MDC Android. Como alternativa, consulte MDC 102: estrutura e layout do Material Design para saber mais sobre a barra de apps superior, a visualização de card e o layout de grade. Agradecemos por testar os componentes do Material Design. Esperamos que tenha gostado deste codelab.