오늘은 디자인을 직접 플러터 코드로 옮겨보겠습니다. 여러분 인생에서 코딩을 할거라고 상상이나 해보셨나요? 저에게도 참 두근대는 시간이네요. 오늘의 작업 순서는 아래와 같습니다.
1. 새 플러터 프로젝트 만들기
2. 에뮬레이터(시뮬레이터) 실행하기
3. 디자인을 코드로 옮기기
자, 프로젝트 폴더 만들기부터 시작해볼까요?
1. 새 플러터 프로젝트 만들기
먼저 프로젝트를 만들고 싶은 폴더 위치에서 터미널(윈도우는 명령 프롬프트)를 실행해야 합니다. 저는 바탕화면에 Dev라는 폴더를 만들고 그 안에 모든 프로젝트를 관리하고 있습니다.
flutter create는 새로운 플러터 프로젝트를 만드는 명령어입니다. create 옆에 my_app은 프로젝트 이름이죠.
flutter create my_app
이 명령어를 실행하면 window, macos, web, ios, android까지 플러터가 지원하는 여러 플랫폼 폴더까지 만들어지는데요. 우리는 앱을 만들거니까 window, macos, web 폴더는 지워주세요.
이 명령어만 실행하면 프로젝트 폴더 만들기는 성공입니다.
2. 에뮬레이터(시뮬레이터) 실행하기
지금부터 Visual Studio Code를 통해 플러터 코딩을 할 건데요. 여러분의 앱을 시뮬레이터(에뮬레이터)에서 실시간으로 보면서 코딩을 할 거예요. 여러분이 사용하시는 휴대폰을 컴퓨터에 연결해놓지 않은 이상, Visual Studio Code가 자동으로 시뮬레이터를 실행해줍니다.
1. 새로 만든 프로젝트 폴더를 Visual Studio Code로 열어주세요.
2. main.dart를 열어주세요.
3. 맥을 사용하시는 분은 fn+F5, 윈도우를 사용하시는 분은 F5 키를 눌러주세요.
그러면 상단에 사용 가능한 시뮬레이터 목록이 나오는데요. 각각 원하시는 시뮬레이터를 고르면 바로 앱이 빌드됩니다.
이렇게 휴대폰 화면과 앱 화면이 나오면 성공입니다!
3. 디자인을 코드로 옮기기
지난 시간에 만들었던 위 디자인을 코드로 옮겨볼텐데요. 이 화면을 만들기 위해 필요한 건 총 5가지 입니다.
1. 세로로 정렬하기
2. 로고 이미지
3. 질문 텍스트
4. 숫자 텍스트
5. 버튼
하나씩 해보겠습니다. 먼저 main.dart를 열면 아래에 MyHomePage이라는게 보일텐데요. 그 안에 build라고 쓰여진 곳에 있는 코드가 화면을 그려주는 코드입니다. 화면을 그려주는 요소들을 우리들은 이제부터 [위젯]이라고 부르겠습니다.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
이 코드를 수정해서 여러분이 했던 디자인처럼 만들건데요. 로고, 텍스트, 숫자, 버튼 순서로 세로로 정렬해주는 위젯이 있습니다. 바로 [Column]이라는 위젯이죠. Column은 여러 자식 위젯들을 가질 수 있습니다. (프로그래밍에서는 무언가 가지거나 어딘가에 속할 때, 부모와 자식의 관계로 많이 표현해요.) 자세히 보시면 children: 이라는 단어가 보이시죠? 이 안에 로고를 위한 이미지 위젯, 텍스트 위젯, 버튼 위젯 이렇게 3가지를 추가해줄 겁니다.
우선 프로젝트에 필요 없는 부분부터 지워보겠습니다. 여러분도 아래처럼 코드를 만들어주세요. appBar와 floatingActionButton에 관련된 부분을 지웠습니다. appBar는 상단에 있는 파란색 제목 영역이구요. floatingActionButton은 오른쪽 아래에 있는 +버튼입니다. 우리가 했던 앱 디자인에는 없으니 지우는 거죠. 관련된 코드가 어디까지냐면 :가 시작해서 괄호가 열린 부분부터 닫힌 부분까지가 관련된 코드입니다.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
],
),
),
);
}
가장 처음으로 이미지 위젯을 사용할 건데요. 이미지를 사용하기 위해 먼저 해야할 일이 있습니다. pubspec.yaml이라는 문서에 우리가 사용하고 싶은 이미지가 담긴 폴더를 사용하겠다고 미리 신고하는거죠. 먼저 프로젝트 폴더에 assets이라는 폴더를 만들고, 그 안에 images라는 폴더를 만드세요. 그리고 그 안에 로고 파일을 넣으세요. 파일을 넣었다면 pubspec.yaml 파일을 열어 조금 내리면 이런 부분이 있습니다.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
이렇게 생긴 부분을 아래와 같이 바꿔줍니다. 폴더 안에 있는 모든 이미지를 사용한다는 의미로 바꿔주겠습니다. 이때 들여쓰기에 주의해야하는데요, assets는 왼쪽에서 2칸, - assets/images/는 왼쪽에서 4칸을 스페이스로 띄워주시면 됩니다. - assets/fonts/ 폴더에는 디자인에 사용한 폰트를 넣어줄 거니까 미리 폴더를 만들어 둘게요.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- assets/images/
- assets/fonts/
다 되었다면 이제 이미지를 사용할 준비가 된겁니다. 이제 이미지는 Image.asset()이라는 위젯을 통해서 사용할 수 있습니다. (보통 asset에 이미지나 동영상등의 미디어 파일들을 넣는 편입니다.) 로고 파일의 이름을 logo.png라고 지어서 assets/images 폴더에 넣어주세요. 그리고 아래와 같이 작성해주세요.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset("assets/images/logo.png"),
],
),
),
);
}
Image위젯하고 .asset() 안에 "assets/images/logo.png"라고 작성하면 [asset/images] 폴더 안에 있는 logo.png 이미지 파일을 불러오겠다는 의미입니다. 화면에 나오죠?
만약 이런 화면이 보인다면 앱을 종료했다가 다시 빌드해보세요!
다음은 텍스트를 써볼 건데요. 텍스트는 Text() 위젯을 사용해서 화면에 그릴 수 있습니다. Text("내용물") 이렇게 괄호 안에 쌍따옴표와 함께 텍스트 내용을 써넣으면 화면에 그대로 나타나는 걸 확인할 수 있습니다. 저는 "How many cups of coffee have you had so far?"라는 문장을 써넣겠습니다.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset("assets/images/logo.png"),
Text("How many cups of coffee have you had so far?"),
],
),
),
);
}
이제 텍스트를 꾸밀 차례인데요. 우리가 디자인할 때 골랐던 폰트를 사용하려면 이미지와 마찬가지로 pubspec.yaml이라는 곳에 신고를 해줘야 합니다. assets 폴더 안에 font라는 폴더를 만들고 여러분이 사용했던 폰트 파일을 넣어주세요. 구글 폰트에 있다면 폰트를 바로 다운로드 받을 수 있습니다.
위는 구글폰트 링크이구요.
디자인에 사용했던 폰트를 검색하면 위처럼 리스트가 나옵니다. 들어가면 오른쪽에 [Download family] 버튼을 통해 폰트를 다운로드받을 수 있습니다.
그리고 pubspec.yaml 하단에 아래와 같이 적으면 됩니다. - asset: assets/fonts/ 다음에는 여러분의 폰트 파일 이름을 적어주시면 됩니다! weight는 폰트의 굵기를 의미하는데요. 특정 굵기의 폰트를 사용하고 싶을 때 어떤 수치를 적어주어야 할지 정의해주는 거라고 생각하시면 됩니다. 작성하셨으면 [윈도우는 Ctrl+S, 맥은 Cmd+S 눌러서 저장]하는 거 잊지마시구요!
fonts:
- family: SpectralSC
fonts:
- asset: fonts/SpectralSC-Bold.ttf
여기서 잠깐! 앱을 실행하고 있는 상태에서 pubspec.yaml에 asset 파일을 새로 추가한 경우, 앱을 다시 빌드해야만 플러터가 새로 추가한 파일들을 인식할 수 있어요. 혹시나 '미디어 파일들을 추가했는데 왜 화면에 안 나오지?' 라며 헤매시는 분들은 참고하시길 바랍니다.
자, 이제 텍스트에 디자인했던 폰트를 적용해보겠습니다. 폰트 적용 방법은 Text() 위젯 안에 style 설명을 써주면 되는데요. TextStyle()이라는 설명서가 있습니다. 이 안에 fontFamily라는 항목이 있는데 여기에 pubspec.yaml에 신고했던 family: 옆에 쓰여있는 글을 그대로 써주면 됩니다. 저는 SpectralSC라고 이름지어 사용했습니다.
글자색은 TextStyle()안에 color라는 항목에 Colors.white라고 써넣으면 글자를 흰색으로 바꿀 수 있습니다. Colors는 플러터에서 만들어놓은 자주 사용하는 컬러들을 모아놓은 집합이라고 생각하시면 되는데요. Colors까지 입력하고 .을 입력하면 어떤 색을 사용할 수 있는지 확인할 수 있으니 한 번 해보세요! 가운데 정렬도 함께 해줄게요. (저는 흰 글씨를 써서 Scaffold에 배경색을 추가했습니다.)
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0XFF493422),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset("assets/images/logo.png"),
Text(
"How many cups of coffee have you had so far?",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "SpectralSC",
color: Colors.white,
),
),
],
),
),
);
}
여러분의 문장이 보이나요? 문장 아래에 이제 카운팅하는 숫자를 넣을 차례입니다. 똑같이 Text() 위젯을 사용하면 되는데요. 일단 0부터 셈을 시작하니까 0을 적어보겠습니다. 폰트와 글자색도 동일하니 똑같이 적어주고, 글자 크기만 조금 키워보겠습니다. fontSize라는 항목을 적어주면 되는데요. 플러터의 기본 글자크기는 16입니다. 저는 64로 적어주겠습니다.
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0XFF493422),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset("assets/images/logo.png"),
Text(
"How many cups of coffee have you had so far?",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "SpectralSC",
color: Colors.white,
fontSize:32,
),
),
Text(
"0",
style: TextStyle(
fontFamily: "SpectralSC",
color: Colors.white,
fontSize:64,
),
),
],
),
),
);
}
로고 이미지가 너무 커서 줄이고 싶네요. 텍스트도 마찬가지로 2줄로 줄이고 싶군요. 조금 조절해보겠습니다. 이미지 크기를 줄이는 방법은 SizedBox 위젯으로 감싸서 크기를 지정해주면 이미지가 알아서 줄어들게 됩니다.
SizedBox(
width: 160,
child: Image.asset("assets/images/logo.png"),
),
이제 버튼만 만들어주면 되겠네요. 버튼은 ElevatedButton() 위젯을 사용하겠습니다.
ElevatedButton(
onPressed: () {
},
child: Text("ONE MORE!")
)
이 버튼에는 onPressed 라는 항목이 있는데요. 버튼을 눌렀을 때 어떤 일이 일어나게 하고 싶은지 적는 곳입니다. { } 괄호 안에 적어주면 되는데 이건 나중에 하고, 우선 버튼부터 디자인처럼 똑같이 만들어보겠습니다.
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(24),
primary: Colors.brown,
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0),
),
),
child: const Text(
"ONE MORE!",
style: TextStyle(
fontFamily: "SpectralSC",
fontSize: 24,
color: Colors.white,
),
),
),
primary 항목은 버튼의 컬러입니다. 저는 브라운 컬러를 사용했기에 플러터 컬러세트에 있는 브라운 컬러를 사용했습니다. (이후에 실제 사용한 색으로 교체했습니다.) elevation은 얼마만큼 버튼이 공중에 떠있어서 그림자가 생기는지를 결정하는 항목입니다. 숫자가 높을수록 그림자가 짙어집니다. 한 층씩 올라간다고 생각하시면 됩니다. padding은 버튼 안쪽으로 얼마만큼의 여백을 줄지 결정하는 항목입니다. 보통 디자인에서는 8의 배수만큼 여백을 조정하곤 하는데요. 절대적이지는 않습니다.
이제 버튼을 누르면 위에 써있는 0 숫자가 바뀌게 만들면 되는데요. 사실 그렇게 해주는 기능이 이미 만들어져 있었습니다!
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
위처럼 기본 예제에서 만들어주는 부분인데요. _counter는 우리가 1씩 더할 숫자로 0부터 시작하도록 했습니다. _incrementCounter()는 직역하면 [Counter 증가] 입니다. _incrementCounter()라는 심부름을 받으면 _counter를 1씩 더하도록 하게 돼있죠.
_counter++; 라는 코드는 아래 코드와 뜻이 같습니다.
_counter = _counter + 1;
코드를 해석하자면 이렇습니다.
1. =의 왼쪽 부분(_counter)에 =의 오른쪽의 내용(_counter + 1)을 새로 담는다.
2. _counter는 원래 0이었고, 0 + 1을 새로 담는다.
3. 결과적으로 _counter는 1이 되었다!
만약 _counter가 1일때 _incrementCounter() 심부름을 시키면 _counter는 1 + 1이 되어 2가 되겠죠.
증가하는 숫자를 텍스트로 표시해야 하니까 0 대신에 _counter를 써야겠죠? "$_counter"를 Text위젯 안에 넣으면 _counter의 값을 그대로 나타내줍니다.
Scaffold(
backgroundColor: const Color(0XFF493422),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
width: 160,
child: Image.asset("assets/images/logo.png"),
),
const Text(
"How many cups of coffee have you had so far?",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "SpectralSC",
color: Colors.white,
fontSize: 24,
),
),
Text(
"$_counter",
style: const TextStyle(
fontFamily: "SpectralSC",
color: Colors.white,
fontSize: 64,
),
),
ElevatedButton(
onPressed: () {
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(24),
primary: Colors.brown,
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0),
),
),
child: const Text(
"ONE MORE!",
style: TextStyle(
fontFamily: "SpectralSC",
fontSize: 24,
color: Colors.white,
),
),
),
],
),
),
);
그런데 _counter를 증가시키는 코드가 setState(() {}); 안에 들어있는 이유는 뭘까요?
setState 심부름은 바로 화면을 새로 그려달라는 겁니다!
int _counter = 0;
void _incrementCounter() {
_counter++;
}
코드를 이렇게 변경하면 버튼을 아무리 눌러봐야 숫자가 증가하지 않습니다. setState 심부름을 시켜야만 화면에 증가된 숫자를 제대로 표시해주죠.
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
위처럼 써야 합니다. 숫자를 증가시키는 심부름은 버튼을 눌렀을때 시키면 되니까 아래처럼 코드를 작성하면 됩니다.
ElevatedButton(
onPressed: () {
_incrementCounter();
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(24),
primary: Colors.brown,
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0),
),
),
child: const Text(
"ONE MORE!",
style: TextStyle(
fontFamily: "SpectralSC",
fontSize: 24,
color: Colors.white,
),
),
),
onPressed는 직역하면 "눌렸을 때"이죠. 버튼이 눌렸을 때 숫자를 증가시켜라~ 라는 의미가 되는 겁니다.
자 이렇게 여러분만의 계수기를 만들어 봤는데요. 어려운 점 없이 잘 만드셨나요? 궁금하신 점이 있다면 언제든 문의주세요! 다음에는 이 계수기를 발전시켜볼 건데요. 바로 날짜별로 숫자를 세어볼 겁니다. 제 컨셉은 "그동안 커피를 몇 잔 마셨는가?"이니까 며칠에 몇 잔을 마셨는지 세어볼 겁니다. 준비되셨다면 아래 링크를 눌러주세요!
'비전공자를 위한 Flutter > 앱 개발 강의보기' 카테고리의 다른 글
Flutter (영업비밀) 앱개발 자주 쓰이는 금주의 위젯 살펴보기 frequently used widgets (0) | 2022.06.14 |
---|---|
Flutter 앱 만들기 3단계 : 5분만에 앱 디자인하기 (0) | 2022.05.12 |
Flutter 앱 만들기 2단계 : 앱 퀄리티 높아보이는 디자인 준비하기 (0) | 2022.05.07 |
Flutter 앱 만들기 1단계 : 기획하기 (0) | 2022.05.03 |
Flutter 첫 프로젝트 - my_app 코드 간단 설명 (2/2) (0) | 2022.04.29 |
댓글