1. Wprowadzenie
Komponenty Material (MDC) pomagają deweloperom wdrażać Material Design. MDC zostało stworzone przez zespół inżynierów i projektantów UX w Google. Zawiera dziesiątki atrakcyjnych i funkcjonalnych komponentów interfejsu, które są dostępne na platformach Android, iOS, internetowej i Flutter.material.io/develop |
Czym są Material Design i Material Components na Androida?
Material Design to system tworzenia atrakcyjnych i funkcjonalnych produktów cyfrowych. Łącząc styl, branding, interakcje i ruch w spójny zestaw zasad i komponentów, zespoły produktowe mogą w pełni wykorzystać swój potencjał projektowy.
W przypadku aplikacji na Androida Material Components for Android (MDC Android) łączy projektowanie i inżynierię z biblioteką komponentów, aby zapewnić spójność w całej aplikacji. Wraz z rozwojem systemu Material Design te komponenty są aktualizowane, aby zapewnić spójną implementację z dokładnością do piksela i zgodność ze standardami Google dotyczącymi tworzenia interfejsu. MDC jest też dostępny w przeglądarce, na iOS i we Flutterze.
W tym ćwiczeniu dowiesz się, jak utworzyć stronę logowania za pomocą kilku komponentów MDC Androida.
Co utworzysz
Te ćwiczenia to pierwsze z 4 ćwiczeń, które pomogą Ci w utworzeniu aplikacji Shrine – aplikacji na Androida e-commerce, w której można kupować odzież i artykuły gospodarstwa domowego. Pokazujemy w nim, jak dostosować komponenty do dowolnej marki lub stylu za pomocą MDC-Android.
W tym ćwiczeniu utworzysz stronę logowania do aplikacji Shrine, która będzie zawierać:
- Dwa pola tekstowe: jedno do wpisania nazwy użytkownika, a drugie do wpisania hasła.
- 2 przyciski: „Anuluj” i „Dalej”.
- Nazwa aplikacji (Shrine)
- Obraz logo Shrine

Komponenty MDC Android użyte w tym ćwiczeniu
- Pole tekstowe
- Przycisk
Czego potrzebujesz
- Podstawowa wiedza na temat programowania aplikacji na Androida
- Android Studio (jeśli nie masz jeszcze tego środowiska, pobierz je tutaj).
- emulator lub urządzenie z Androidem (dostępne w Androidzie Studio);
- Przykładowy kod (patrz następny krok)
Jak oceniasz swoje doświadczenie w tworzeniu aplikacji na Androida?
2. Konfigurowanie środowiska programistycznego
Uruchom Android Studio
Po otwarciu Androida Studio powinno się wyświetlić okno „Welcome to Android Studio” (Witamy w Androidzie Studio). Jeśli jednak uruchamiasz Android Studio po raz pierwszy, wykonaj czynności opisane w Kreatorze konfiguracji Androida Studio, używając wartości domyślnych. Pobranie i zainstalowanie niezbędnych plików może potrwać kilka minut, więc możesz pozostawić to działanie w tle i przejść do następnej sekcji.
Pobierz aplikację Codelabs
Aplikacja startowa znajduje się w katalogu material-components-android-codelabs-101-starter/java.
...lub sklonuj go z GitHub
Aby skopiować ten codelab z GitHuba, uruchom te polecenia:
git clone https://github.com/material-components/material-components-android-codelabs cd material-components-android-codelabs/ git checkout 101-starter
Wczytaj kod startowy w Android Studio
- Gdy kreator konfiguracji zakończy działanie i wyświetli się okno Witamy w Android Studio, kliknij Otwórz istniejący projekt Android Studio. Przejdź do katalogu, w którym został zainstalowany przykładowy kod, i wybierz java -> shrine (lub wyszukaj na komputerze shrine), aby otworzyć projekt Shrine.
- Poczekaj chwilę, aż Android Studio utworzy i zsynchronizuje projekt. Wskaźniki aktywności u dołu okna Android Studio będą pokazywać postęp.
- W tym momencie Android Studio może zgłosić błędy kompilacji, ponieważ brakuje Ci pakietu SDK Androida lub narzędzi do kompilacji, np. takich jak te pokazane poniżej. Postępuj zgodnie z instrukcjami w Android Studio, aby zainstalować lub zaktualizować te komponenty i zsynchronizować projekt.
Dodawanie zależności projektu
Projekt musi mieć zależność od biblioteki pomocy MDC na Androida. Pobrany przykładowy kod powinien już zawierać tę zależność, ale warto wykonać poniższe czynności, aby się upewnić.
- Otwórz plik
build.gradlemodułuappi upewnij się, że blokdependencieszawiera zależność od MDC Android:
api 'com.google.android.material:material:1.1.0-alpha06'
- (Opcjonalnie) W razie potrzeby edytuj plik
build.gradle, aby dodać te zależności, i zsynchronizuj projekt.
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'
}
Uruchom aplikację startową
|
Gotowe! Kod startowy strony logowania Shrine powinien być uruchomiony w emulatorze. Powinna się wyświetlić nazwa „Shrine” i logo Shrine tuż pod nią.

Przyjrzyjmy się kodowi. W przykładowym kodzie udostępniliśmy prosty Fragmentszkielet nawigacji, który umożliwia wyświetlanie fragmentów i przechodzenie między nimi.
Otwórz plik MainActivity.java w katalogu shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.java.shrine. Powinien zawierać te informacje:
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();
}
}
Ta aktywność wyświetla R.layout.shr_main_activityplik układushr_main_activity.xml zdefiniowany w shr_main_activity.xml.
Możesz to zobaczyć w onCreate(),. MainActivity.java rozpoczyna transakcję Fragment, aby wyświetlić LoginFragment. LoginFragment. Właśnie to zmodyfikujemy w tym ćwiczeniu z programowania. Aktywność implementuje też metodę navigateTo(Fragment) zdefiniowaną w NavigationHost, która umożliwia dowolnemu fragmentowi przejście do innego fragmentu.
Command + kliknięcie (lub Control + kliknięcie) shr_main_activity w pliku aktywności, aby otworzyć plik układu, lub przejdź do pliku układu w 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" />
Widzimy tu prosty element <FrameLayout>, który działa jako kontener dla wszystkich fragmentów wyświetlanych przez aktywność. Otwórzmy 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 rozszerza plik układu shr_login_fragment i wyświetla go w onCreateView(). Przyjrzyjmy się plikowi układu shr_login_fragment.xml, aby zobaczyć, jak wygląda strona logowania.
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>
Widzimy tu <LinearLayout> z <ImageView> u góry, co oznacza logo „Shrine”.
Następnie znajduje się tag <TextView> reprezentujący etykietę „SHRINE”. Tekst tej etykiety to zasób tekstowy o nazwie @string/shr_app_name. Jeśli klikniesz nazwę zasobu tekstowego z naciśniętym klawiszem Command (lub Control) albo otworzysz plik app -> res -> values -> strings.xml, zobaczysz plik strings.xml, w którym zdefiniowane są zasoby tekstowe. Gdy w przyszłości dodamy więcej zasobów ciągów tekstowych, będą one zdefiniowane w tym miejscu. Każdy zasób w tym pliku powinien mieć prefiks shr_, aby wskazywać, że jest częścią aplikacji Shrine.
Znasz już kod startowy, więc teraz zaimplementujmy pierwszy komponent.
3. Dodawanie pól tekstowych
Na początek dodamy do strony logowania 2 pola tekstowe, w których użytkownicy będą mogli wpisać nazwę użytkownika i hasło. Użyjemy komponentu MDC Text Field, który ma wbudowaną funkcję wyświetlania pływającej etykiety i komunikatów o błędach.

Dodawanie pliku XML
W sekcji shr_login_fragment.xml dodaj 2 elementy TextInputLayout z elementem podrzędnym TextInputEditText w sekcji <LinearLayout> pod etykietą „SHRINE” <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>
Powyższy fragment kodu zawiera 2 pola tekstowe, z których każde składa się z elementu <TextInputLayout> i elementu podrzędnego <TextInputEditText>. Tekst podpowiedzi w każdym polu tekstowym jest określony w atrybucie android:hint.
Dodaliśmy 2 nowe zasoby ciągów znaków dla pola tekstowego – @string/shr_hint_username i @string/shr_hint_password. Otwórz strings.xml, aby wyświetlić te zasoby ciągów znaków.
strings.xml
...
<string name="shr_hint_username">Username</string>
<string name="shr_hint_password">Password</string>
...
Dodawanie weryfikacji danych wejściowych
Komponenty TextInputLayout mają wbudowaną funkcję informacji o błędach.
Aby wyświetlać informacje o błędach, wprowadź w pliku shr_login_fragment.xml te zmiany:
- Ustaw atrybut
app:errorEnabledna wartość true w elemencie HasłoTextInputLayout. Spowoduje to dodanie dodatkowego dopełnienia komunikatu o błędzie pod polem tekstowym. - Ustaw atrybut
android:inputTypena „textPassword” w elemencie HasłoTextInputEditText. Spowoduje to ukrycie wpisanego tekstu w polu hasła.
Po wprowadzeniu tych zmian pola tekstowe w shr_login_fragment.xml powinny wyglądać tak:
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>
Teraz spróbuj uruchomić aplikację. Powinna pojawić się strona z 2 polami tekstowymi: „Nazwa użytkownika” i „Hasło”.
Sprawdź animację etykiety pływającej:

4. Dodawanie przycisków
Następnie dodamy do strony logowania 2 przyciski: „Anuluj” i „Dalej”. Użyjemy komponentu MDC Button, który ma wbudowany charakterystyczny efekt fali atramentu Material Design.

Dodawanie pliku XML
W sekcji shr_login_fragment.xml dodaj <RelativeLayout> do <LinearLayout> pod elementami TextInputLayout. Następnie dodaj do elementu <RelativeLayout> 2 elementy <MaterialButton>.
Wynikowy plik XML powinien wyglądać tak:
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>
To wszystko. Gdy uruchomisz aplikację, po naciśnięciu każdego przycisku pojawi się efekt rozchodzącego się atramentu.

5. Przejdź do następnego fragmentu
Na koniec dodamy kod Java do LoginFragment.java, aby połączyć przycisk „DALEJ” z innym fragmentem. Zauważysz, że każdy komponent dodany do układu ma przypisany symbol id. Użyjemy tych id, aby odwoływać się do komponentów w naszym kodzie i dodać sprawdzanie błędów oraz nawigację.
Dodajmy prywatną metodę logiczną isPasswordValid w LoginFragment.java pod onCreateView(), która będzie określać, czy hasło jest prawidłowe. Na potrzeby tej wersji demonstracyjnej sprawdzimy tylko, czy hasło ma co najmniej 8 znaków:
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;
}
Następnie dodaj do przycisku „Dalej” detektor kliknięć, który ustawia i usuwa błąd na podstawie utworzonej przez nas metody isPasswordValid(). W onCreateView() detektor kliknięć powinien znajdować się między wierszem inflatera a wierszem return view.
Następnie dodajmy detektor klawiszy do pola hasła TextInputEditText, aby nasłuchiwać zdarzeń klawiszy, które spowodują usunięcie błędu. Ten odbiorca powinien też użyć isPasswordValid(), aby sprawdzić, czy hasło jest prawidłowe. Możesz dodać go bezpośrednio pod detektorem kliknięć w onCreateView().
Metoda onCreateView() powinna teraz wyglądać mniej więcej tak:
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;
}
Teraz możemy przejść do innego fragmentu. Zaktualizuj OnClickListener w onCreateView(), aby przejść do innego fragmentu, gdy weryfikacja błędów zakończy się powodzeniem. Aby to zrobić, dodaj ten wiersz, aby przejść z ProductGridFragment do przypadku else w detektorze kliknięć:
LoginFragment.java
...
((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
...
Detektor kliknięć powinien teraz wyglądać tak:
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
}
}
});
...
Ten nowy wiersz kodu wywołuje metodę navigateTo() z MainActivity, aby przejść do nowego fragmentu – ProductGridFragment. Obecnie jest to pusta strona, nad którą będziesz pracować w module MDC-102.
Teraz skompiluj aplikację. Kliknij przycisk Dalej.
Udało się! Ten ekran będzie punktem początkowym naszych kolejnych zajęć z programowania, które odbędą się w ramach MDC-102.
6. Wszystko gotowe
Korzystając z podstawowego znacznika XML i około 30 wierszy kodu Java, biblioteka Material Components for Android pomogła Ci utworzyć atrakcyjną stronę logowania zgodną z wytycznymi Material Design, która wygląda i działa spójnie na wszystkich urządzeniach.
Dalsze kroki
Pole tekstowe i przycisk to 2 podstawowe komponenty biblioteki MDC Android, ale jest ich znacznie więcej. Pozostałe komponenty MDC Android znajdziesz tutaj. Możesz też zapoznać się z artykułem MDC 102: Material Design Structure and Layout, aby dowiedzieć się więcej o górnym pasku aplikacji, widoku kart i układzie siatki. Dziękujemy za wypróbowanie komponentów Material. Mamy nadzieję, że to ćwiczenie było dla Ciebie przydatne.