MDC-102 Android: 머티리얼 구조 및 레이아웃 (자바)

logo_components_color_2x_web_96dp.png

머티리얼 구성요소(MDC)를 통해 개발자는 머티리얼 디자인을 구현할 수 있습니다. Google의 엔지니어와 UX 디자이너로 구성된 팀에서 만든 MDC는 아름답고 기능적인 수십 가지의 UI 구성요소가 특징이며 Android, iOS, 웹, Flutter용으로 제공됩니다.

material.io/develop

Codelab MDC-101에서는 두 개의 머티리얼 구성요소(MDC)를 사용하여 로그인 페이지를 빌드했습니다(텍스트 입력란과 버튼). 이제 탐색, 구조, 데이터를 추가하여 이러한 기초를 확장해보겠습니다.

빌드할 항목

이 Codelab에서는 Shrine 앱(의류와 가정용품을 판매하는 전자상거래 앱)의 홈 화면을 빌드합니다. 다음 항목이 포함됩니다.

  • 상단 앱 바
  • 제품의 그리드 목록

MDC-Android 이 Codelab의 구성요소

  • AppBarLayout
  • MaterialCardView

필요한 항목

  • Android 개발 관련 기본 지식
  • Android 스튜디오(아직 다운로드하지 않은 경우 여기에서 다운로드)
  • Android Emulator 또는 기기(Android 스튜디오를 통해 사용 가능)
  • 샘플 코드(다음 단계 참고)

Android 앱 빌드 경험 수준을 평가해주세요.

초급 중급 고급

MDC-101에서 계속 진행

MDC-101을 완료했으면 이 Codelab을 위한 코드가 준비된 것입니다. 3단계: 상단 앱 바 추가로 건너뛸 수 있습니다.

처음부터 새로 시작

시작 Codelab 앱 다운로드

시작 앱 다운로드

시작 앱은 material-components-android-codelabs-102-starter/java 디렉터리에 있습니다. 시작하기 전에 이 디렉터리로 cd 이동하세요.

...또는 GitHub에서 클론

이 Codelab을 GitHub에서 클론하려면 다음 명령어를 실행하세요.

git clone https://github.com/material-components/material-components-android-codelabs
cd material-components-android-codelabs/
git checkout 102-starter

Android 스튜디오에서 시작 코드 로드

  1. 설정 마법사가 완료되고 Welcome to Android Studio 창이 표시되면 Open an existing Android Studio project를 클릭합니다. 샘플 코드를 설치한 디렉터리로 이동하여 java -> 신사(또는 컴퓨터에서 shrine 검색)를 사용하여 Shrine 프로젝트 열기
  2. Android 스튜디오 창 하단의 활동 표시기에 나타나는 것처럼 Android 스튜디오가 프로젝트를 빌드하고 동기화할 때까지 잠시 기다립니다.
  3. 이 시점에서 Android 스튜디오에 아래와 같은 빌드 오류가 발생할 수 있습니다. Android SDK나 빌드 도구가 누락되었기 때문입니다. Android 스튜디오의 안내를 따라 이러한 항목을 설치/업데이트하고 프로젝트를 동기화합니다.

프로젝트 종속 항목 추가하기

프로젝트에는 MDC Android 지원 라이브러리에 대한 종속 항목이 필요합니다. 다운로드한 샘플 코드에는 이 종속 항목이 이미 나열되어 있지만 다음 단계를 따라 실행하는 것이 좋습니다.

  1. app 모듈의 build.gradle 파일로 이동하여 dependencies 블록에 MDC Android 종속 항목이 포함되어 있는지 확인합니다.
api 'com.google.android.material:material:1.1.0-alpha06'
  1. (선택사항) 필요한 경우 build.gradle 파일을 수정하여 다음 종속 항목을 추가하고 프로젝트를 동기화합니다.
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'
}

시작 앱 실행

  1. Run / Play 버튼 왼쪽에 있는 빌드 구성이 app인지 확인합니다.
  2. 녹색 실행/재생 버튼을 눌러 앱을 빌드하고 실행합니다.
  3. 사용 가능한 기기에 이미 Android 기기가 나열되어 있다면 Select Deployment Target 창에서 8단계로 건너뜁니다. 나열되어 있지 않으면 Create New Virtual Device를 클릭합니다.
  4. Select Hardware 화면에서 Pixel 2와 같은 휴대전화 기기를 선택한 후 Next를 클릭합니다.
  5. System Image 화면에서 최신 Android 버전(가장 높은 API 수준 권장)을 선택합니다. 설치되어 있지 않은 경우 표시되는 다운로드 링크를 클릭하고 다운로드를 완료합니다.
  6. 다음을 클릭합니다.
  7. Android Virtual Device (AVD) 화면에서 설정을 그대로 두고 Finish를 클릭합니다.
  8. 배포 대상 대화상자에서 Android 기기를 선택합니다.
  9. 확인을 클릭합니다.
  10. Android 스튜디오가 앱을 빌드하고 배포한 후 자동으로 대상 기기에서 앱을 엽니다.

완료되었습니다. MDC-101 Codelab의 Shrine 로그인 페이지가 표시됩니다.

로그인 화면이 잘 표시되므로 이제 제품으로 앱을 채워보겠습니다.

로그인 페이지를 닫으면 홈 화면이 표시되며 이 화면에 '축하합니다!' 메시지가 표시됩니다. 훌륭합니다. 그러나 이제 사용자는 실행할 작업이 없거나 앱 내에서 사용자의 위치를 파악할 수 없습니다. 이러한 문제를 해결하기 위해 탐색을 추가해 보겠습니다.

머티리얼 디자인은 높은 수준의 사용성을 보장하는 탐색 패턴을 제공합니다. 가장 눈에 띄는 탐색 구성요소 중 하나는 상단 앱 바입니다.

탐색 기능을 제공하고 사용자가 다른 작업에 빠르게 액세스할 수 있도록 상단 앱 바를 추가해보겠습니다.

AppBar 위젯 추가

shr_product_grid_fragment.xml에서 "and it!"가 포함된 <LinearLayout> 태그를 삭제합니다. TextView로 바꾸고 다음을 바꿉니다.

shr_product_grid_fragment.xml

<com.google.android.material.appbar.AppBarLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

   <androidx.appcompat.widget.Toolbar
       android:id="@+id/app_bar"
       style="@style/Widget.Shrine.Toolbar"
       android:layout_width="match_parent"
       android:layout_height="?attr/actionBarSize"
       app:title="@string/shr_app_name" />
</com.google.android.material.appbar.AppBarLayout>

shr_product_grid_fragment.xml은 다음과 같이 표시됩니다.

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
   tools:context=".ProductGridFragment">

   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>
  
</FrameLayout>

대다수 앱 바에는 제목 옆에 버튼이 있습니다. 메뉴 아이콘을 추가해보겠습니다.

탐색 아이콘 추가하기

계속 shr_product_grid_fragment.xml에서 다음을 방금 추가한 Toolbar XML 구성요소에 추가합니다.

shr_product_grid_fragment.xml

app:navigationIcon="@drawable/shr_menu"

shr_product_grid_fragment.xml은 다음과 같이 표시됩니다.

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
   tools:context=".ProductGridFragment">
  
   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:navigationIcon="@drawable/shr_menu"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>
  
</FrameLayout>

작업 버튼 추가 및 상단 앱 바 스타일 지정하기

앱 바의 끝에 버튼을 추가할 수도 있습니다. Android에서는 이를 작업 버튼이라고 합니다.

상단 앱 바의 스타일을 지정하고 프로그래매틱 방식으로 작업 버튼을 메뉴에 추가합니다.

먼저 툴바를 설정하는 메서드를 만듭니다. 이 메서드는 id를 사용하여 툴바 참조를 가져오고 getActivity()를 사용하여 활동 참조도 가져와야 합니다. 활동이 null이 아니면 setSupportActionBar을 사용하여 ActionBar로 사용하도록 설정합니다.

ProductGridFragment.java

private void setUpToolbar(View view) {
   Toolbar toolbar = view.findViewById(R.id.app_bar);
   AppCompatActivity activity = (AppCompatActivity) getActivity();
   if (activity != null) {
       activity.setSupportActionBar(toolbar);
   }
}

다음으로, 앞서 추가한 setUpToolbar 메서드 바로 아래에 onCreateOptionsMenu를 재정의하여 shr_toolbar_menu.xml의 콘텐츠를 툴바로 확장합니다.

ProductGridFragment.java

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
   menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
   super.onCreateOptionsMenu(menu, menuInflater);
}

이제 다음 메서드를 사용하여 onCreateView() 메서드의 콘텐츠에 추가한 setUpToolbar 메서드 호출을 추가합니다.

ProductGridFragment.java

@Override
public View onCreateView(
       @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   // Inflate the layout for this fragment with the ProductGrid theme
   View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);

   // Set up the toolbar
   setUpToolbar(view);

   return view;
}

마지막으로 onCreate() 메서드를 ProductGridFragment.java에 추가합니다. 메서드 본문에서 setHasOptionMenu의 매개변수를 true로 설정합니다.

메서드는 다음과 같습니다.

ProductGridFragment.java

@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setHasOptionsMenu(true);
}

위의 코드는 XML 레이아웃의 앱 바를 이 활동의 작업 모음으로 설정합니다. 콜백 onCreateOptionsMenu는 활동에 사용할 메뉴입니다. 이 경우에는 R.menu.shr_toolbar_menu의 메뉴 항목을 앱 바에 넣습니다.

메뉴 파일에는 "Search" 및 "Filter"라는 두 항목이 있습니다.

shr_툴바_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
       android:id="@+id/search"
       android:icon="@drawable/shr_search"
       android:title="@string/shr_search_title"
       app:showAsAction="always" />
   <item
       android:id="@+id/filter"
       android:icon="@drawable/shr_filter"
       android:title="@string/shr_filter_title"
       app:showAsAction="always" />
</menu>

변경 후 ProductGridFragment.java 파일은 다음과 같습니다.

ProductGridFragment.java

package com.google.codelabs.mdc.java.shrine;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;


public class ProductGridFragment extends Fragment {

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setHasOptionsMenu(true);
   }
  
   @Override
   public View onCreateView(
           @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       // Inflate the layout for this fragment with the ProductGrid theme
       View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);

       // Set up the toolbar
       setUpToolbar(view);

       return view;
   }
  
   private void setUpToolbar(View view) {
       Toolbar toolbar = view.findViewById(R.id.app_bar);
       AppCompatActivity activity = (AppCompatActivity) getActivity();
       if (activity != null) {
           activity.setSupportActionBar(toolbar);
       }
   }

   @Override
   public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
       super.onCreateOptionsMenu(menu, menuInflater);
   }

}

빌드와 실행 홈 화면이 다음과 같이 표시됩니다.

이제 툴바에 탐색 아이콘, 제목, 오른쪽에 작업 아이콘 두 개가 표시됩니다. 툴바는 또한 미묘한 그림자를 사용하여 고도를 표시하며, 이를 통해 콘텐츠와 다른 레이어에 고도가 표시됩니다.

이제 앱에 구조가 생겼으므로 콘텐츠를 카드에 배치하여 구성합니다.

카드 추가

이제 상단 앱 바 아래에 카드 하나를 추가해보겠습니다. 카드에는 이미지 영역, 제목, 보조 텍스트 라벨이 있어야 합니다.

shr_product_grid_fragment.xml에서 AppBarLayout 아래에 다음을 추가합니다.

shr_product_grid_fragment.xml

<com.google.android.material.card.MaterialCardView
   android:layout_width="160dp"
   android:layout_height="180dp"
   android:layout_marginBottom="16dp"
   android:layout_marginLeft="16dp"
   android:layout_marginRight="16dp"
   android:layout_marginTop="70dp"
   app:cardBackgroundColor="?attr/colorPrimaryDark"
   app:cardCornerRadius="4dp">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="bottom"
       android:background="#FFFFFF"
       android:orientation="vertical"
       android:padding="8dp">

       <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:padding="2dp"
           android:text="@string/shr_product_title"
           android:textAppearance="?attr/textAppearanceHeadline6" />

       <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:padding="2dp"
           android:text="@string/shr_product_description"
           android:textAppearance="?attr/textAppearanceBody2" />
   </LinearLayout>
</com.google.android.material.card.MaterialCardView>

빌드 및 실행:

이 미리보기에서는 카드가 화면 왼쪽 가장자리에서 삽입되어 있고 모서리와 그림자가 둥근 카드 (카드의 고도를 표현함)가 있는 것을 확인할 수 있습니다. 전체 영역을 "container."라고 합니다. 컨테이너 자체를 제외한 다른 모든 요소는 선택사항입니다.

헤더 텍스트, 썸네일 또는 아바타, 부제목 텍스트, 구분선, 버튼 및 아이콘과 같은 요소를 컨테이너에 추가할 수 있습니다. 예를 들어 방금 만든 카드는 카드 하단에 정렬된 LinearLayout에 두 개의 TextView (제목 및 하위 텍스트 하나씩)를 포함합니다.

카드는 보통 다른 카드와 함께 컬렉션으로 표시됩니다. 이 Codelab의 다음 섹션에서는 이를 그리드로 컬렉션으로 배치합니다.

화면에 여러 카드가 있는 경우 하나 이상의 컬렉션으로 그룹화됩니다. 그리드의 카드는 동일 평면상에 있습니다. 즉, 픽업 또는 드래그되지 않는 한 서로 동일한 휴면 고도를 공유하지만 이 Codelab에서는 다루지 않습니다.

카드 그리드 설정

제공된 shr_product_card.xml 파일을 살펴보세요.

shr_product_card.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView 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"
   app:cardBackgroundColor="@android:color/white"
   app:cardElevation="2dp"
   app:cardPreventCornerOverlap="true">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical">

       <com.android.volley.toolbox.NetworkImageView
           android:id="@+id/product_image"
           android:layout_width="match_parent"
           android:layout_height="@dimen/shr_product_card_image_height"
           android:background="?attr/colorPrimaryDark"
           android:scaleType="centerCrop" />

       <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:orientation="vertical"
           android:padding="16dp">

           <TextView
               android:id="@+id/product_title"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="@string/shr_product_title"
               android:textAppearance="?attr/textAppearanceHeadline6" />

           <TextView
               android:id="@+id/product_price"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="@string/shr_product_description"
               android:textAppearance="?attr/textAppearanceBody2" />
       </LinearLayout>
   </LinearLayout>
</com.google.android.material.card.MaterialCardView>

이 카드 레이아웃에는 이미지 (URL의 이미지를 포함할 수 있는 NetworkImageView)와 두 개의 TextViews가 포함된 카드가 포함되어 있습니다.

다음으로 저희가 제공하는 ProductCardRecyclerViewAdapter을 살펴보세요. ProductGridFragment와 동일한 패키지에 포함되어 있습니다.

ProductCardRecyclerViewAdapter.java

package com.google.codelabs.mdc.java.shrine;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.google.codelabs.mdc.java.shrine.network.ImageRequester;
import com.google.codelabs.mdc.java.shrine.network.ProductEntry;

import java.util.List;

/**
* Adapter used to show a simple grid of products.
*/
public class ProductCardRecyclerViewAdapter extends RecyclerView.Adapter<ProductCardViewHolder> {

   private List<ProductEntry> productList;
   private ImageRequester imageRequester;

   ProductCardRecyclerViewAdapter(List<ProductEntry> productList) {
       this.productList = productList;
       imageRequester = ImageRequester.getInstance();
   }

   @NonNull
   @Override
   public ProductCardViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
       View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.shr_product_card, parent, false);
       return new ProductCardViewHolder(layoutView);
   }

   @Override
   public void onBindViewHolder(@NonNull ProductCardViewHolder holder, int position) {
       // TODO: Put ViewHolder binding code here in MDC-102
   }

   @Override
   public int getItemCount() {
       return productList.size();
   }
}

위의 어댑터 클래스는 그리드의 콘텐츠를 관리합니다. 각 뷰가 주어진 콘텐츠로 실행해야 할 작업을 결정하기 위해 곧 onBindViewHolder()의 코드를 작성합니다.

같은 패키지에서 ProductCardViewHolder를 살펴볼 수도 있습니다. 이 클래스는 카드 레이아웃에 영향을 주는 뷰를 저장하므로 나중에 수정할 수 있습니다.

ProductCardViewHolder.java

package com.google.codelabs.mdc.java.shrine;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;

public class ProductCardViewHolder extends RecyclerView.ViewHolder {

   public ProductCardViewHolder(@NonNull View itemView) {
       super(itemView);
       // TODO: Find and store views from itemView
   }
}

그리드를 설정하려면 먼저 shr_product_grid_fragment.xml에서 MaterialCardView 자리표시자를 삭제합니다. 이제 카드 그리드를 나타내는 구성요소를 추가해야 합니다. 이 경우 RecyclerView 구성요소를 AppBarLayout XML 구성요소 아래 shr_product_grid_fragment.xml에 추가합니다.

shr_product_grid_fragment.xml

<androidx.core.widget.NestedScrollView
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_marginTop="56dp"
   android:background="@color/productGridBackgroundColor"
   android:paddingStart="@dimen/shr_product_grid_spacing"
   android:paddingEnd="@dimen/shr_product_grid_spacing"
   app:layout_behavior="@string/appbar_scrolling_view_behavior">

   <androidx.recyclerview.widget.RecyclerView
       android:id="@+id/recycler_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />

</androidx.core.widget.NestedScrollView>

shr_product_grid_fragment.xml은 다음과 같이 표시됩니다.

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
   tools:context=".ProductGridFragment">

   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:navigationIcon="@drawable/shr_menu"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>

   <androidx.core.widget.NestedScrollView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_marginTop="56dp"
       android:background="@color/productGridBackgroundColor"
       android:paddingStart="@dimen/shr_product_grid_spacing"
       android:paddingEnd="@dimen/shr_product_grid_spacing"
       app:layout_behavior="@string/appbar_scrolling_view_behavior">

       <androidx.recyclerview.widget.RecyclerView
           android:id="@+id/recycler_view"
           android:layout_width="match_parent"
           android:layout_height="match_parent" />

   </androidx.core.widget.NestedScrollView>

</FrameLayout>

마지막으로 onCreateView()에서 setUpToolbar(view)를 호출한 후 return 문 앞에 RecyclerView 초기화 코드를 ProductGridFragment.java에 추가합니다.

ProductGridFragment.java

@Override
public View onCreateView(
       @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   ...
   setUpToolbar(view);

   // Set up the RecyclerView
   RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
   recyclerView.setHasFixedSize(true);
   recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2, GridLayoutManager.VERTICAL, false));
   ProductCardRecyclerViewAdapter adapter = new ProductCardRecyclerViewAdapter(
           ProductEntry.initProductEntryList(getResources()));
   recyclerView.setAdapter(adapter);
   int largePadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing);
   int smallPadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small);
   recyclerView.addItemDecoration(new ProductGridItemDecoration(largePadding, smallPadding));

   return view;
}

위의 코드 스니펫에는 RecyclerView를 설정하는 데 필요한 초기화 단계가 포함되어 있습니다. 여기에는 RecyclerView의 레이아웃 관리자 설정, RecyclerView 어댑터 초기화 및 설정이 포함됩니다.

이제 ProductGridFragment.java 파일이 다음과 같이 표시됩니다.

ProductGridFragment.java

package com.google.codelabs.mdc.java.shrine;

import android.os.Bundle;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;


import com.google.codelabs.mdc.java.shrine.network.ProductEntry;

public class ProductGridFragment extends Fragment {

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setHasOptionsMenu(true);
   }

   @Override
   public View onCreateView(
           @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       // Inflate the layout for this fragment with the ProductGrid theme
       View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);

       // Set up the toolbar
       setUpToolbar(view);

       // Set up the RecyclerView
       RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
       recyclerView.setHasFixedSize(true);
       recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2, GridLayoutManager.VERTICAL, false));
       ProductCardRecyclerViewAdapter adapter = new ProductCardRecyclerViewAdapter(
               ProductEntry.initProductEntryList(getResources()));
       recyclerView.setAdapter(adapter);
       int largePadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing);
       int smallPadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small);
       recyclerView.addItemDecoration(new ProductGridItemDecoration(largePadding, smallPadding));

       return view;
   }

   private void setUpToolbar(View view) {
       Toolbar toolbar = view.findViewById(R.id.app_bar);
       AppCompatActivity activity = (AppCompatActivity) getActivity();
       if (activity != null) {
           activity.setSupportActionBar(toolbar);
       }
   }

   @Override
   public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
       super.onCreateOptionsMenu(menu, menuInflater);
   }

}

빌드와 실행

카드가 도착했습니다! 아직 아무 것도 표시되지 않으므로 제품 데이터를 추가합니다.

이미지 및 텍스트 추가하기

각 카드에 이미지, 제품 이름, 가격을 추가합니다. ViewHolder 추상화는 각 카드의 뷰를 보유합니다. ViewHolder에서 다음과 같이 세 가지 뷰를 추가합니다.

ProductCardViewHolder.java

package com.google.codelabs.mdc.java.shrine;

import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;

import com.android.volley.toolbox.NetworkImageView;

public class ProductCardViewHolder extends RecyclerView.ViewHolder {

   public NetworkImageView productImage;
   public TextView productTitle;
   public TextView productPrice;

   public ProductCardViewHolder(@NonNull View itemView) {
       super(itemView);
       productImage = itemView.findViewById(R.id.product_image);
       productTitle = itemView.findViewById(R.id.product_title);
       productPrice = itemView.findViewById(R.id.product_price);
   }
}

RecyclerView'의 어댑터에서 ViewHolder,onBindViewHolder() 메서드를 업데이트하여 각 뷰에 정보를 설정합니다.

ProductCardRecyclerViewAdapter.java

@Override
public void onBindViewHolder(@NonNull ProductCardViewHolder holder, int position) {
   if (productList != null && position < productList.size()) {
       ProductEntry product = productList.get(position);
       holder.productTitle.setText(product.title);
       holder.productPrice.setText(product.price);
       imageRequester.setImageFromUrl(holder.productImage, product.url);
   }
}

위의 코드는 ViewHolder를 사용하여 RecyclerView 및 각 카드를 할 작업을 어댑터에 알립니다.

여기서는 각 ViewHolderTextView에 텍스트 데이터를 설정하고 ImageRequester을 호출하여 URL에서 이미지를 가져옵니다. ImageRequester는 편의를 위해 제공된 클래스이며, Volley 라이브러리를 사용합니다 (이 Codelab에서 다루지 않는 주제이지만 자유롭게 코드를 직접 살펴보세요.).

빌드 및 실행:

이제 제품이 앱에 표시됩니다.

앱에는 사용자를 로그인 화면에서 제품을 볼 수 있는 홈 화면으로 안내하는 기본적인 흐름이 있습니다. 코드 몇 줄만으로 상단 앱 바와 제목 버튼 3개, 앱 그리드를 추가한 카드 그리드를 추가했습니다. 이제 홈 화면이 기본적인 구조와 실행 가능한 콘텐츠로 간단하고 기능적입니다.

다음 단계

상단 앱 바와 카드, 텍스트 입력란, 버튼으로 이제 MDC-Android 라이브러리의 핵심 머티리얼 디자인 구성요소 4개를 사용했습니다. MDC Android 카탈로그의 MDC Android 구성요소에서 더 많은 구성요소를 살펴볼 수 있습니다.

앱이 완전히 작동하지만 아직 특정 브랜드를 표현하지는 않습니다. MDC-103: 색상, 모양, 고도, 유형을 사용한 머티리얼 디자인 테마에서 이러한 구성요소의 스타일을 맞춤설정하여 생동감 있고 현대적인 브랜드를 표현합니다.

적절한 시간과 노력을 들여 이 Codelab을 완료할 수 있었습니다.

매우 동의함 동의함 보통 동의하지 않음 전혀 동의하지 않음

앞으로 머티리얼 구성요소를 계속 사용하고 싶습니다.

매우 동의함 동의함 보통 동의하지 않음 전혀 동의하지 않음