플러터의 Material Design 과 Material Components 란 무엇인가?
Material Design 시스템은 일관된 원칙과 구성요소로 디자인 잠재력을 실현할 수 있는 것이다.
플러터용 Material App 과 Material Component 는 일관된 사용자 경험을 제공한다. Material Design 시스템이 발전함에 따라 Material 컴포넌트들은 구글의 프론트엔드 개발 표준을 준수하여 일관된 완벽한 구현을 보장하도록 업데이트 된다. MDC 는 AOS, IOS, Web 모두 사용 가능하다.
이 코드 랩에서는 MDC Flutter 구성 요소를 사용하여 로그인 페이지를 작성한다.
이 코드 랩은 의류 및 가정용품을 판매하는 전자상거래 앱인 Shrine 이라는 앱을 만드는 과정을 안내하는 네 개의 코드랩 중 첫번째이다.
MDC-Flutter 를 사용하여 브랜드나 스타일을 반영하도록 구성요소를 사용자정의 하는 방법을 알려준다.
이 코드 랩에서는 다음을 포함하는 Shrine 에 대한 로그인 페이지를 작성한다.
Flutter 작성 때 필요한 요구사항들이 나열되어있다. 필요하면 받아서 사용한다.
Github 에서 클론하여 사용한다.
git clone https://github.com/material-components/material-components-flutter-codelabs.git
cd material-components-flutter-codelabs
git checkout 101-starter
cd mdc_100_series
flutter run
![image-20200128220810395](/Users/ashe/Library/Application Support/typora-user-images/image-20200128220810395.png)
Pubspec 이 편집되었다는 경고가 표시되면 그대로 둔다. Flutter 실행 시 자동으로
flutter packages get
이 실행된다.
login.dart
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
// TODO: Add text editing controllers (101)
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
padding: EdgeInsets.symmetric(horizontal: 24.0),
children: <Widget>[
SizedBox(height: 80.0),
Column(
children: <Widget>[
Image.asset('assets/diamond.png'),
SizedBox(height: 16.0),
Text('SHRINE'),
],
),
SizedBox(height: 120.0),
// TODO: Wrap Username with AccentColorOverride (103)
// TODO: Remove filled: true values (103)
// TODO: Wrap Password with AccentColorOverride (103)
// TODO: Add TextField widgets (101)
// TODO: Add button bar (101)
],
),
),
);
}
}
// TODO: Add AccentColorOverride (103)
여기에는 import
문과 두 클래스가 포함되어 있다.
import
파일에서 Material 컴포넌트를 제공한다.LoginPage
클래스는 시뮬레이터에 표시되는 전체 페이지를 나타낸다._LoginPageState
클래스의 build
기능을 사용하여 UI 에 있는 위젯들이 생성된다.유저 이름과 비밀번호를 작성하는 텍스트 필드를 추가한다. 이 페이지에서는 스크롤 가능한 ListView
에 배치한다.
두 텍스트 필드와 빈 공간인 SizedBox
를 추가한다.
// TODO: Add TextField widgets (101)
// [Name]
TextField(
decoration: InputDecoration(
filled: true,
labelText: 'Username',
),
),
// spacer
SizedBox(height: 12.0),
// [Password]
TextField(
decoration: InputDecoration(
filled: true,
labelText: 'Password',
),
obscureText: true,
),
텍스트 필드에는 각각 InputDecoration
위젯을 사용하는 decoration
필드가 존재한다. 이 필드의 filled
속성은 텍스트 필드를 탭 할 때 배경이 가볍게 채워져 대상영역을 인식하는데 도움이 된다. 두 번째 필드의 obscureText
속성은 암호화 처리에 적합하다.
이제 Cancel
버튼과 Next
버튼을 만든다. MDC 버튼 위젯인 FlatButton
(텍스트 버튼이라고도 함) 과 RaisedButton
(포함되어 있는 버튼이라고도 함)을 사용한다.
Text, Contained 버튼 중 선택하는 방법
Text 버튼은 덜 중요하다는 것을 분명히 한다. Contained 버튼은 원하는 우리가 원하는 행동이다.
우리가 목표하는 버튼은 Login 을 하게하는 버튼이므로 Next 버튼을 Contained 버튼으로, 로그인 취소를 Text 버튼으로 사용한다.
텍스트 필드 하위에 다음 ButtonBar
를 추가한다.
// TODO: Add button bar (101)
ButtonBar(
// TODO: Add a beveled rectangular border to CANCEL (103)
children: <Widget>[
// TODO: Add buttons (101)
],
),
ButtonBar
는 자식 버튼을 정렬한다.
ButtonBar
안에 두 버튼을 추가한다.
// TODO: Add buttons (101)
FlatButton(
child: Text('CANCEL'),
onPressed: () {
// TODO: Clear the text fields (101)
},
),
// TODO: Add an elevation to NEXT (103)
// TODO: Add a beveled rectangular border to NEXT (103)
RaisedButton(
child: Text('NEXT'),
onPressed: () {
// TODO: Show the next page (101)
},
),
ButtonBar
는 레이아웃을 담당하고 ButtonTheme
의 패딩 속성에 따라 하위 버튼들이 정렬되어 나타난다. ( 현재의 경우 가로로 배치됨 )
텍스트 필드 값을 수정할 수 있도록 TextEditingControllers
를 추가한다.
_LoginPageState
클래스 선언 바로 아래 final
변수를 추가한다.
// TODO: Add text editing controllers (101)
final _usernameController = TextEditingController();
final _passwordController = TextEditingController();
그리고 각 텍스트 필드에 컨트롤러를 추가한다.
// [Name]
TextField(
controller: _usernameController,
// [Password]
TextField(
controller: _passwordController,
그리고 FlatButton
이 눌렸을 때 이 필드들을 지우는 동작을 추가한다.
// TODO: Clear the text fields (101)
_usernameController.clear();
_passwordController.clear();
현재 페이지를 탐색 스택에서 제거하기 위해 팝 하려한다.
Navigator 는 IOS 에서 UINavigationController 와 같은 경로 스택을 유지 관리한다. Push 는 새 페이지를 스택에 상단에 배치하고, Pop 은 가장 최근 추가된 상단의 페이지를 제거한다.
RaisedButton
의 onPressed
함수에서 네비게이터의 가장 최근 경로를 제거한다.
// TODO: Show the next page (101)
RaisedButton(
child: Text('NEXT'),
onPressed: () {
Navigator.pop(context);
},
),
마지막으로 home.dart
를 열고 resizeToAvoidBottomInset
을 false
로 설정한다.
return Scaffold(
// TODO: Add app bar (102)
// TODO: Add a grid view (102)
body: Center(
child: Text('You did it!'),
),
// TODO: Set resizeToAvoidBottomInset (101)
resizeToAvoidBottomInset: false,
);
이렇게하면 키보드가 나올 때 위젯의 크기가 변경되지 않는다.