MDC-103 Flutter: 색상, 형태, 고도, 활자(Flutter)를 사용한 머티리얼 테마 설정

logo_components_color_2x_web_96dp.png

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

이제 MDC를 사용하여 앱의 고유한 스타일을 그 어느 때보다도 맞춤설정할 수 있습니다. 머티리얼 디자인이 최근 확장됨에 따라 디자이너와 개발자는 제품 브랜드를 더욱 유연하게 표현할 수 있습니다.

Codelab CMD-101과 MDB-102에서는 머티리얼 구성요소(MDC)를 사용하여 의류와 가정용품을 판매하는 전자상거래 앱인 Shine이라는 앱의 기본사항을 빌드했습니다. 이 앱에는 로그인 화면에서 시작하여 제품을 표시하는 홈 화면으로 이동하는 사용자 흐름이 포함되어 있습니다.

빌드할 항목

이 Codelab에서는 다음을 사용하여 Shrine 앱을 맞춤설정합니다.

  • 색상
  • 서체
  • 고도
  • 형태
  • 레이아웃

7f521db8a762f5ee.png 7ac46e5cb6b1e064.png

이 Codelab의 MMD-Flutter 구성요소 및 하위 시스템

  • 테마
  • 서체
  • 고도
  • 이미지 목록

Flutter 개발 경험 수준을 평가해주세요.

초급 중급 고급

시작하기 전에

Flutter를 사용하여 모바일 앱을 개발하려면 다음을 진행해야 합니다.

  1. Flutter SDK를 다운로드하고 설치합니다.
  2. Flutter SDK로 PATH를 업데이트합니다.
  3. Flutter와 Dart 플러그인 또는 선호하는 편집기를 사용하여 Android 스튜디오를 설치합니다.
  4. Android Emulator 또는 iOS 시뮬레이터(Mac에서는 Xcode가 필요함)를 설치하거나 실제 기기를 사용합니다.

Flutter 설치에 관한 자세한 내용은 시작하기: 설치를 참고하세요. 편집기를 설정하려면 시작하기: 편집기 설정을 참고하세요. Android Emulator를 설치할 때 최신 시스템 이미지가 있는 Pixel 3 휴대전화와 같은 기본 옵션을 자유롭게 사용하세요. VM 가속을 사용 설정하는 것이 좋지만 필수는 아닙니다. 위의 4개 단계를 완료한 후 Codelab으로 돌아가면 됩니다. 이 Codelab을 완료하려면 플랫폼(Android나 iOS) 하나에만 Flutter를 설치하면 됩니다.

Flutter SDK가 올바른 상태인지 확인

이 Codelab을 진행하기 전에 SDK가 올바른 상태인지 확인하세요. 이전에 Flutter SDK를 설치한 경우 flutter upgrade를 사용하여 SDK가 최신 상태인지 확인합니다.

 flutter upgrade

flutter upgrade를 실행하면 flutter doctor.가 자동으로 실행됩니다. 최신 Flutter가 설치되어 있어 업그레이드가 필요하지 않으면 flutter doctor를 수동으로 실행합니다. 그러면 설정 완료를 위해 설치해야 하는 종속 항목이 있는지 관련 내용이 보고됩니다. 관련 없는 체크표시는 무시해도 됩니다(예: iOS용으로 개발하지 않으려는 경우 Xcode).

 flutter doctor

자주 묻는 질문(FAQ)

MDC-102에서 계속 진행하시겠어요?

MDC-102를 완료했으면 이 Codelab을 위한 코드가 준비된 것입니다. 색상 변경 단계로 건너뜁니다.

처음부터 새로 시작

시작 Codelab 앱 다운로드

시작 앱 다운로드

시작 앱은 material-components-flutter-codelabs-103-starter_and_102-complete/mdc_100_series 디렉터리에 있습니다.

...또는 GitHub에서 클론

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

git clone https://github.com/material-components/material-components-flutter-codelabs.git
cd material-components-flutter-codelabs/mdc_100_series
git checkout 103-starter_and_102-complete

프로젝트 설정

다음 안내에서는 Android 스튜디오(IntelliJ)를 사용한다고 가정합니다.

프로젝트 열기

1. Android 스튜디오를 엽니다.

2 시작 화면이 표시되면 Open an existing Android Studio project를 클릭합니다.

3. material-components-flutter-codelabs/mdc_100_series 디렉터리로 이동하고 'Open'을 클릭합니다. 프로젝트가 열립니다. 프로젝트를 한 번 빌드할 때까지는 Dart Analysis에 표시되는 오류를 무시해도 됩니다.

4. 메시지가 표시되면 다음 단계를 따릅니다.

  • 플랫폼 및 플러그인 업데이트나 FlutterRunConfigurationType을 설치합니다.
  • Dart 또는 Flutter SDK가 구성되지 않은 경우 Flutter 플러그인용 Flutter SDK 경로를 설정합니다.
  • Android 프레임워크를 구성합니다.
  • 'Get dependencies' 또는 'Run ‘flutter packages get''을 클릭합니다.

그런 다음 Android 스튜디오를 다시 시작합니다.

시작 앱 실행

다음 안내에서는 Android Emulator 또는 기기에서 테스트한다고 가정하지만 Xcode가 설치된 경우 iOS 시뮬레이터 또는 기기에서 테스트해도 됩니다.

1. 기기나 에뮬레이터를 선택합니다. Android Emulator가 아직 실행되지 않은 경우 Tools -> Android -> AVD Manager를 선택하여 가상 기기를 만들고 에뮬레이터를 시작합니다. AVD가 이미 있는 경우 다음 단계와 같이 Android 스튜디오의 기기 선택기에서 바로 에뮬레이터를 시작할 수 있습니다. iOS 시뮬레이터의 경우 아직 실행되고 있지 않으면 Flutter Device Selection -> Open iOS Simulator를 선택하여 개발 머신에서 시뮬레이터를 실행합니다.

2 Flutter 앱을 시작합니다.

  • 편집기 화면 상단에서 Flutter Device Selection 드롭다운 메뉴를 찾아 기기를 선택합니다(예: <version>용으로 빌드된 iPhone SE 또는 Android SDK).
  • 재생 아이콘()을 누릅니다.

완료되었습니다. 이전 Codelab의 Shrine 로그인 페이지가 시뮬레이터 또는 에뮬레이터에 표시됩니다.

Android

iOS

'Next'를 클릭하면 이전 Codelab의 홈페이지가 표시됩니다.

Android

iOS

Shrine 브랜드를 표현하는 색 구성표가 만들어져 있습니다. 디자이너 입장에서는 Shrine 앱에 이 색 구성표가 구현되기를 바랄 것입니다.

시작하려면 해당 색상을 프로젝트에 가져옵니다.

colors.dart 만들기

libcolors.dart라는 새 Dart 파일을 만듭니다. 머티리얼 구성요소를 가져오고 const Color 값을 추가합니다.

import 'package:flutter/material.dart';

const kShrinePink50 = Color(0xFFFEEAE6);
const kShrinePink100 = Color(0xFFFEDBD0);
const kShrinePink300 = Color(0xFFFBB8AC);
const kShrinePink400 = Color(0xFFEAA4A4);

const kShrineBrown900 = Color(0xFF442B2D);

const kShrineErrorRed = Color(0xFFC5032B);

const kShrineSurfaceWhite = Color(0xFFFFFBFA);
const kShrineBackgroundWhite = Colors.white;

맞춤 색상 팔레트

이 색상 테마는 디자이너가 맞춤 색상으로 만든 것입니다(아래 그림 참고). 색상 테마는 Shrine 분기에서 선택되어 Material Theme Editor에 적용된 색상을 포함하고 있으며, 더 풍부한 팔레트를 만들기 위해 색상을 확장했습니다. 이러한 색상은 2014 머티리얼 색상 팔레트의 색상이 아닙니다.

Material Theme Editor는 색상을 숫자 라벨(각 색상에 지정된 50, 100, 200에서 900까지의 라벨 포함)이 지정된 셰이드로 구성합니다. Shrine은 분홍색 견본에서 셰이드 50, 100, 300만, 갈색 견본에서 900만 사용합니다.

wlq5aH94SfU47pcalUqOSK57OCX4HnJJTpMVzVrBZreUOE-CrkX2akKrnTbgwf6BQNMBi-nn16jpgQHDeQZixTCeh1A0qTXcxDMTcc2-e6uJg0LPjkXWEVlV7cwS0U1naqpnHToEIQ 1HLdzGp-TIhg2ULijquMw_KQdk18b080CVQN_oECAhiCnFI11Nm3nbcsCIXvZBXULMajAW9NEmGZ7iR_j-eEF6NiODuaike96xVpLwUIzfV4dzTg9uQHsmNG-BDTOd04e6_eRLs--Q

위젯의 각 색상 매개변수가 이러한 구성표의 색상에 매핑됩니다. 예를 들어, 입력을 적극적으로 받는 텍스트 필드 장식의 색상이 테마의 기본 색상이 됩니다. 해당 색상에 액세스(배경과 쉽게 구분)할 수 없는 경우 대신 PrimaryVariant를 사용합니다.

2014 머티리얼 가이드라인용으로 만든 것이지만 현재 가이드라인(색상 시스템 도움말)과 MDC-Flutter에도 사용할 수 있습니다. 코드로 변형에 액세스하려면 기본 색상과 셰이드(보통 백 자리의 값)를 차례대로 호출하면 됩니다. 예를 들어 분홍색 400은 Colors.pink[400] 명령어로 가져옵니다.

이러한 팔레트를 디자인 및 코드에 사용해도 아주 좋습니다. 이미 브랜드에 특화된 색상이 있는 경우 팔레트 생성 도구 또는 Material Theme Editor를 사용하여 적합한 팔레트를 직접 생성할 수 있습니다.

이제 사용할 색상이 있으므로 해당 색상을 UI에 적용할 수 있습니다. 적용하려면 위젯 계층 구조 상단에서 MaterialApp 인스턴스에 적용되는 ThemeData 위젯의 값을 설정하면 됩니다.

ThemeData.light() 맞춤설정

Flutter에는 몇 가지 테마가 내장되어 있습니다. 밝은 테마는 그 중 하나입니다. ThemeData 위젯을 처음부터 만들지 않고 밝은 테마를 복사한 다음 값을 변경하여 앱에 맞춤설정해 보겠습니다.

app.dart.에서 colors.dart를 가져옵니다.

import 'colors.dart';

그런 다음 ShrineApp 클래스 범위를 벗어나 app.dart에 다음을 추가합니다.

// TODO: Build a Shrine Theme (103)
final ThemeData _kShrineTheme = _buildShrineTheme();

ThemeData _buildShrineTheme() {
  final ThemeData base = ThemeData.light();
  return base.copyWith(
    accentColor: kShrineBrown900,
    primaryColor: kShrinePink100,
    buttonTheme: base.buttonTheme.copyWith(
      buttonColor: kShrinePink100,
      colorScheme: base.colorScheme.copyWith(
        secondary: kShrineBrown900,
      ),
    ),
    buttonBarTheme: base.buttonBarTheme.copyWith(
      buttonTextTheme: ButtonTextTheme.accent,
    ),
    scaffoldBackgroundColor: kShrineBackgroundWhite,
    cardColor: kShrineBackgroundWhite,
    textSelectionColor: kShrinePink100,
    errorColor: kShrineErrorRed,
    // TODO: Add the text themes (103)
    // TODO: Add the icon themes (103)
    // TODO: Decorate the inputs (103)
  );
}

이제 (MaterialApp 위젯의) ShrineApp build() 함수 끝에서 theme:를 새 테마로 설정합니다.

  // TODO: Add a theme (103)
  theme: _kShrineTheme, // New code

재생 버튼을 클릭합니다. 이제 로그인 화면이 다음과 같이 표시됩니다.

Android

iOS

홈 화면이 다음과 같이 표시됩니다.

Android

iOS

색상 변화 외에도 디자이너는 사용할 특정 서체도 제공했습니다. Flutter의 ThemeData에는 3가지 텍스트 테마가 포함되어 있습니다. 각 텍스트 테마는 '헤드라인', '제목' 같은 텍스트 스타일의 모음입니다. 앱에 두 가지 스타일을 사용하고 일부 값을 변경할 것입니다.

텍스트 테마 맞춤설정

글꼴을 프로젝트에 가져오려면 pubspec.yaml 파일에 해당 글꼴을 추가해야 합니다.

pubspec.yaml에서 flutter: 태그 바로 뒤에 다음을 추가합니다.

  # TODO: Insert Fonts (103)
  fonts:
    - family: Rubik
      fonts:
        - asset: fonts/Rubik-Regular.ttf
        - asset: fonts/Rubik-Medium.ttf
          weight: 500

이제 Rubik 글꼴에 액세스하여 사용할 수 있습니다.

pubspec 파일 문제 해결

위의 선언을 복사하여 붙여넣으면 pub get을 실행할 때 오류가 발생할 수 있습니다. 오류가 발생하면 선행 공백을 삭제한 후 2칸 들여쓰기를 사용한 공백으로 바꿉니다. (다음 앞에 공백 두 개

fonts:

, 다음 앞에 공백 네 개

family: Rubik

등)

Mapping values are not allowed here가 표시되면 문제가 있는 라인의 들여쓰기와 그 라인 위에 있는 라인의 들여쓰기를 확인합니다.

login.dart에서 Column()의 다음 항목을 변경합니다.

Column(
  children: <Widget>[
    Image.asset('assets/diamond.png'),
    SizedBox(height: 16.0),
    Text(
      'SHRINE',
      style: Theme.of(context).textTheme.headline5,
    ),
  ],
)

app.dart에서 _buildShrineTheme() 뒤에 다음을 추가합니다.

// TODO: Build a Shrine Text Theme (103)
TextTheme _buildShrineTextTheme(TextTheme base) {
  return base.copyWith(
    headline5: base.headline5.copyWith(
      fontWeight: FontWeight.w500,
    ),
    headline6: base.headline6.copyWith(
        fontSize: 18.0
    ),
    caption: base.caption.copyWith(
      fontWeight: FontWeight.w400,
      fontSize: 14.0,
    ),
    bodyText1: base.bodyText1.copyWith(
      fontWeight: FontWeight.w500,
      fontSize: 16.0,
    ),
  ).apply(
    fontFamily: 'Rubik',
    displayColor: kShrineBrown900,
    bodyColor: kShrineBrown900,
  );
}

그러면 TextTheme가 가져와지고 헤드라인, 제목 및 설명의 모습이 변경됩니다.

이 방식으로 fontFamily를 적용하면 copyWith()에 지정된 서체 조정 값(헤드라인, 제목, 설명)에만 변경 사항이 적용됩니다.

일부 글꼴에는 맞춤 fontWeight를 설정하고 있습니다. FontWeight 위젯은 100s에 관한 편리한 값을 가집니다. 글꼴에서 w500(500 weight)이 보통 중간 크기이고 w400이 보통 일반 크기입니다.

새로운 텍스트 테마 사용

errorColor 뒤에 나오는 _buildShrineTheme에 다음 테마를 추가합니다.

// TODO: Add the text themes (103)

textTheme: _buildShrineTextTheme(base.textTheme),
primaryTextTheme: _buildShrineTextTheme(base.primaryTextTheme),
accentTextTheme: _buildShrineTextTheme(base.accentTextTheme),

중지 버튼을 클릭한 다음 재생 버튼을 클릭합니다.

로그인 및 홈 화면의 텍스트가 다르게 표시됩니다. Rubrik 글꼴을 사용하는 텍스트도 있고, 검은색이나 흰색이 아닌 갈색으로 렌더링된 텍스트도 있습니다.

Android

iOS

아이콘은 계속 흰색입니다. 별도의 아이콘 테마가 있기 때문입니다.

맞춤설정된 기본 아이콘 테마 사용

_buildShrineTheme() 함수에 다음을 추가합니다.

    // TODO: Add the icon theme (103)
    primaryIconTheme: base.iconTheme.copyWith(
      color: kShrineBrown900
    ),

재생 버튼을 클릭합니다.

Android

iOS

앱 바의 아이콘이 갈색이 되었습니다.

텍스트 축소

라벨이 너무 큽니다.

home.dart에서 가장 안쪽 Column의 children:을 변경합니다.

// TODO: Change innermost Column (103)
children: <Widget>[
// TODO: Handle overflowing labels (103)

  Text(
    product == null ? '' : product.name,
    style: theme.textTheme.button,
    softWrap: false,
    overflow: TextOverflow.ellipsis,
    maxLines: 1,
  ),
  SizedBox(height: 4.0),
  Text(
    product == null ? '' : formatter.format(product.price),
    style: theme.textTheme.caption,
  ),
  // End new code
],

중앙에 텍스트 배치

라벨을 중앙에 배치하고 텍스트를 각 이미지 하단이 아닌 각 카드 하단에 맞추고자 합니다.

라벨을 기본 축의 끝(하단)으로 옮긴 다음 중앙에 오도록 변경합니다.

// TODO: Align labels to the bottom and center (103)

  mainAxisAlignment: MainAxisAlignment.end,
  crossAxisAlignment: CrossAxisAlignment.center,

프로젝트를 저장합니다.

Android

iOS

거의 근접하게 되었지만 텍스트가 카드 중앙에 오지 않았습니다.

상위 Column의 교차 축 정렬을 다음과 같이 변경합니다.

// TODO: Center items on the card (103)

    crossAxisAlignment: CrossAxisAlignment.center,

프로젝트를 저장합니다. 이제 홈 화면이 다음과 같이 표시됩니다.

Android

iOS

훨씬 보기 좋습니다.

텍스트 필드 테마 지정

InputDecorationTheme를 사용하여 텍스트 필드의 장식에 테마를 지정할 수도 있습니다.

app.dart_buildShrineTheme() 메서드에 inputDecorationTheme: 값을 지정합니다.

// TODO: Decorate the inputs (103)
inputDecorationTheme: InputDecorationTheme(
  border: OutlineInputBorder(),
),

현재 텍스트 필드에는 filled 장식이 있습니다. 그 장식을 삭제해 보겠습니다. filled를 삭제하고 inputDecorationTheme를 지정하면 텍스트 필드에 윤곽선 스타일이 적용됩니다.

login.dart에서 filled: true 값을 삭제합니다.

// Remove filled: true values (103)
TextField(
  controller: _usernameController,
  decoration: InputDecoration(
    // Removed filled: true
    labelText: 'Username',
  ),
),
SizedBox(height: 12.0),
TextField(
  controller: _passwordController,
  decoration: InputDecoration(
    // Removed filled: true
    labelText: 'Password',
  ),
  obscureText: true,
),

Run 메뉴에서 Flutter Hot Restart 버튼을 클릭하여 처음부터 앱을 다시 시작합니다. 활성화된 Username 필드에 입력하려고 하면 로그인 화면이 다음과 같이 표시됩니다.

Android

iOS

텍스트 필드에 입력합니다. 그러면 장식과 플로팅 자리표시자가 기본 색상으로 렌더링됩니다. 하지만 아주 쉽게 눈에 띄지는 않습니다. 색상 대비가 그렇게 높지 않은 픽셀을 구분하기 어려운 사용자는 액세스할 수 없습니다. 자세한 내용은 Material Guidelines Color 도움말 에서 'Accessible colors'를 참고하세요. 텍스트 필드의 강조 색상을 위 색상 테마에서 디자이너가 제공한 PrimaryVariant로 재정의하기 위해 inputDecorationTheme:focusedBorder:를 지정해 보겠습니다.

app.dart에서 inputDecorationTheme: 아래에 focusedBorder:를 지정합니다.

// TODO: Decorate the inputs (103)
inputDecorationTheme: InputDecorationTheme(
  focusedBorder: OutlineInputBorder(
    borderSide: BorderSide(
      width: 2.0,
      color: kShrineBrown900,
    ),
  ),
  border: OutlineInputBorder(),
),

이제 디자이너가 제공한 색상 테마의 라벨에 색상을 지정하기 위해 두 텍스트 필드의 labelStyle 속성을 변경합니다.

login.dart에서 두 TextField 위젯 InputDecoration() 아래에 labelStyle:을 추가합니다.

TextField(
  controller: _usernameController,
  decoration: InputDecoration(
    labelText: 'Username',
    labelStyle: TextStyle(color: Theme.of(context).accentColor),
  ),
),
SizedBox(height: 12.0),
TextField(
  controller: _passwordController,
  decoration: InputDecoration(
    labelText: 'Password',
    labelStyle: TextStyle(color: Theme.of(context).accentColor),
  ),
),

텍스트 필드에 포커스가 있거나 없을 때 서로 다른 라벨 스타일이 적용되도록 각 TextField 위젯에 FocusNode를 설정하고 위젯에 포커스가 있는지에 따라 labelStyle을 동적으로 만들기 위한 조건도 설정하고자 합니다.

login.dart에서 _LoginPageState 클래스 상단의 텍스트 필드 컨트롤러 아래에서 FocusNodes 및 포커스가 없는 라벨 색상을 초기화하겠습니다.

class _LoginPageState extends State<LoginPage> {
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();
  final _unfocusedColor = Colors.grey[600];
  final _usernameFocusNode = FocusNode();
  final _passwordFocusNode = FocusNode();

initState를 재정의하고 FocusNodes의 리스너를 추가합니다.

@override
void initState() {
  super.initState();
  _usernameFocusNode.addListener(() {
      setState(() {
        //Redraw so that the username label reflects the focus state
      });
   });
  _passwordFocusNode.addListener(() {
      setState(() {
        //Redraw so that the password label reflects the focus state
      });
   });
}

마지막으로 TextField 위젯 내에 focusNode: 속성을 추가하고 InputDecoration() 아래에 labelStyle:에 관한 조건을 추가합니다.

TextField(
  controller: _usernameController,
  decoration: InputDecoration(
    labelText: 'Username',
    labelStyle: TextStyle(
        color: _usernameFocusNode.hasFocus
           ? Theme.of(context).accentColor
           : _unfocusedColor),
  ),
  focusNode: _usernameFocusNode,
),
SizedBox(height: 12.0),
TextField(
  controller: _passwordController,
  decoration: InputDecoration(
    labelText: 'Password',
    labelStyle: TextStyle(
        color: _passwordFocusNode.hasFocus
           ? Theme.of(context).accentColor
           : _unfocusedColor),
  ),
  focusNode: _passwordFocusNode,
),

재생 버튼을 클릭합니다.

Android

iOS

지금까지 Shrine에 어울리는 특정 색상과 서체로 페이지의 스타일을 지정했습니다. 이제 Shrine의 제품을 보여주는 카드를 살펴보겠습니다. 현재 카드는 사이트 탐색 옆의 흰색 노출 영역에 놓여 있습니다.

카드 고도 조정

home.dart에서 elevation: 값을 카드에 추가합니다.

// TODO: Adjust card heights (103)

    elevation: 0.0,

프로젝트를 저장합니다.

Android

iOS

카드 아래에 있던 그림자를 없앴습니다.

로그인 화면의 구성요소 고도를 변경해 그림자를 넣어 보겠습니다.

NEXT 버튼의 고도 변경

RaisedButton의 기본 고도는 2입니다. 좀 더 올려보겠습니다.

login.dart에서 elevation: 값을 NEXT RaisedButton에 추가합니다.

RaisedButton(
  child: Text('NEXT'),
  elevation: 8.0, // New code

Run 메뉴에서 Flutter Hot Restart 버튼을 클릭하여 처음부터 앱을 다시 시작합니다. 이제 로그인 화면이 다음과 같이 표시됩니다.

Android

iOS

Shrine은 8각형 또는 직사각형 형태의 요소를 정의하는 근사한 기하학 스타일을 가집니다. 홈 화면의 카드와 로그인 화면의 텍스트 필드 및 버튼에 이 형태 스타일을 구현해 보겠습니다.

로그인 화면의 텍스트 필드 형태 변경

app.dart에서 특수한 cut corners border 파일을 가져옵니다.

import 'supplemental/cut_corners_border.dart';

계속 app.dart에서 모서리가 잘린 형태를 텍스트 필드 장식 테마에 추가합니다.

// TODO: Decorate the inputs (103)
inputDecorationTheme: InputDecorationTheme(
  focusedBorder: CutCornersBorder(
    borderSide: BorderSide(
      width: 2.0,
      color: kShrineBrown900,
    ),
  ),
  border: CutCornersBorder(), // Replace code
),

로그인 화면의 버튼 형태 변경

login.dart에서 CANCEL 버튼에 입체 직사각형 테두리를 추가합니다.

FlatButton(
  child: Text('CANCEL'),
  shape: BeveledRectangleBorder(
    borderRadius: BorderRadius.all(Radius.circular(7.0)),
  ),

FlatButton에는 표시 가능한 형태가 없는데 왜 테두리 형태를 추가하는 걸까요? 그래서 터치하면 물결 효과 애니메이션이 동일한 형태에 바인딩됩니다.

이제 NEXT 버튼에 동일한 형태를 추가합니다.

RaisedButton(
  child: Text('NEXT'),
  elevation: 8.0,
  shape: BeveledRectangleBorder(
    borderRadius: BorderRadius.all(Radius.circular(7.0)),
  ),

app.dart에서 buttonTheme를 업데이트하여 모든 버튼의 형태를 변경할 수도 있습니다. 이 방법은 과제로 남겨두겠습니다.

Run 메뉴에서 Flutter Hot Restart 버튼을 클릭하여 처음부터 앱을 다시 시작합니다.

Android

iOS

이제 각 카드가 서로 독특하게 표시되도록 레이아웃을 변경해 다양한 가로세로 비율과 크기로 카드를 표시해 보겠습니다.

GridView를 AsymmetricView로 대체

이미 비대칭 레이아웃을 구현하기 위한 파일을 작성했습니다.

home.dart에서 전체 파일을 다음으로 변경합니다.

import 'package:flutter/material.dart';

import 'model/products_repository.dart';
import 'model/product.dart';
import 'supplemental/asymmetric_view.dart';

class HomePage extends StatelessWidget {
  // TODO: Add a variable for Category (104)

  @override
  Widget build(BuildContext context) {
  // TODO: Return an AsymmetricView (104)
  // TODO: Pass Category variable to AsymmetricView (104)
    return Scaffold(
      appBar: AppBar(
        brightness: Brightness.light,
        leading: IconButton(
          icon: Icon(Icons.menu),
          onPressed: () {
            print('Menu button');
          },
        ),
        title: Text('SHRINE'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.search),
            onPressed: () {
              print('Search button');
            },
          ),
          IconButton(
            icon: Icon(Icons.tune),
            onPressed: () {
              print('Filter button');
            },
          ),
        ],
      ),
      body: AsymmetricView(products: ProductsRepository.loadProducts(Category.all)),
    );
  }
}

프로젝트를 저장합니다.

Android

iOS

이제 제품이 직물 느낌의 패턴으로 가로로 스크롤됩니다. 또한 상태 표시줄 텍스트(상단의 시간 및 네트워크)가 이제 검은색입니다. AppBar의 밝기를 밝게(brightness: Brightness.light)로 변경했기 때문입니다.

색상은 브랜드를 표현하는 강력한 방법이므로, 작은 색상 변화도 사용자 경험에 큰 영향을 미칠 수 있습니다. 이 사항을 테스트하기 위해 브랜드의 색 구성표가 완전히 달라지면 Shrine이 어떻게 표시되는지 살펴보겠습니다.

색상 수정

colors.dart에서 다음을 추가합니다.

const kShrinePurple = Color(0xFF5D1049);
const kShrineBlack = Color(0xFF000000);

app.dart에서 _buildShrineTheme()_buildShrineTextTheme 함수를 다음으로 변경합니다.

ThemeData _buildShrineTheme() {
  final ThemeData base = ThemeData.light();
  return base.copyWith(
    primaryColor: kShrinePurple,
    buttonTheme: base.buttonTheme.copyWith(
      buttonColor: kShrinePurple,
      textTheme: ButtonTextTheme.primary,
      colorScheme: ColorScheme.light().copyWith(primary: kShrinePurple)
    ),
    scaffoldBackgroundColor: kShrineSurfaceWhite,
    textTheme: _buildShrineTextTheme(base.textTheme),
    primaryTextTheme: _buildShrineTextTheme(base.primaryTextTheme),
    accentTextTheme: _buildShrineTextTheme(base.accentTextTheme),
    primaryIconTheme: base.iconTheme.copyWith(
      color: kShrineSurfaceWhite
    ),
    inputDecorationTheme: InputDecorationTheme(
      focusedBorder: CutCornersBorder(
        borderSide: BorderSide(
          width: 2.0,
          color: kShrinePurple,
        ),
      ),
      border: CutCornersBorder(),
    ),
  );
}

TextTheme _buildShrineTextTheme(TextTheme base) {
  return base.copyWith(
    headline5: base.headline5.copyWith(
      fontWeight: FontWeight.w500,
    ),
    headline6: base.headline6.copyWith(
        fontSize: 18.0,
    ),
    caption: base.caption.copyWith(
      fontWeight: FontWeight.w400,
      fontSize: 14.0,
    ),
    bodyText1: base.bodyText1.copyWith(
      fontWeight: FontWeight.w500,
      fontSize: 16.0,
    ),
  ).apply(
    fontFamily: 'Rubik',
  );
}

login.dart에서 로고 다이아몬드를 검은색으로 지정합니다.

Image.asset(
  'assets/diamond.png',
  color: kShrineBlack, // New code
),

home.dart에서 다음과 같이 AppBar의 밝기를 어둡게로 변경합니다.

brightness: Brightness.dark,

프로젝트를 저장합니다. 이제 새 테마가 표시됩니다.

Android

iOS

Android

iOS

결과가 아주 달라졌습니다. 104로 넘어가기 전에 이 색상 코드를 되돌려 보겠습니다.

MDC-104 시작 코드 다운로드

지금까지 디자이너의 디자인 사양과 유사한 앱을 만들어 보았습니다.

다음 단계

지금까지 테마, 서체, 고도, 형태의 MDC 구성요소를 사용했습니다. MDC-Flutter 라이브러리에서 더 많은 구성요소와 하위 시스템을 탐색할 수 있습니다.

Google에서 가로로 스크롤되는 비대칭 레이아웃 그리드를 만든 방법은 supplemental 디렉터리의 파일을 자세히 살펴보세요.

계획된 앱 디자인에서 MDC 라이브러리의 구성요소를 사용하지 않는 요소가 있으면 어떻게 해야 할까요? MDC 라이브러리로 맞춤 구성요소를 만들어 특별한 모습을 구현하는 방법이 MDC-104: 머티리얼 디자인 고급 구성요소에 나와 있습니다.

다음 Codelab

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

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

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

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