이번에 자율동아리를 따로 진행하면서 해야 할 일도 많아지고... 했는데, 그중에 하나가 flutter 겨울 프로젝트이다. 같은 동기들끼리 진행하게 되었는데, 종강을 질질 끌어서 어제 하는 바람에 코딩 셰프가 만든 강의를 들여다본다는 게 늦어진 데다 펑크까지 내버렸다. 그래서 어떻게 든 빠르고 정확하게 이 실수를 만회해야 한다. 내가 제일 (생각 없이) 잘하는 건 글을 끄적이는 것이기 때문에 이걸 이용해서 배운걸 한번 빠르게 정리해보고자 한다.
Flutter는 앱을 만들 수 있는 일종의 Framework이다. 놀라운 것은 이 프레임워크하나로 안드로이드에서도, IOS에서도, Chrome에서도 돌아갈 앱을 만들 수 있다.(물론 최적화 이슈는 있겠지만..) 코셰 님의 말에 따르면 나중에 구글이 만들 OS의 안배라고 하던데... 중요한 것은 듣도 보도 못한 Dart라는 언어를 사용하는 것이다. 느낌은... c++인데, 메서드나 namedargument같은 문법은 ruby나 python, void main()으로 닥치고 시작하는 느낌은 c를 닮아서, 이리저리 짬뽕된 느낌이다. 내가 아는 언어의 세계가 뒤지게 좁다는 걸 체감한 뒤라서 별 거부감은 없었다.
아무튼 이론은 대강 이렇고, Flutter App의 구조 자체는 tree형식으로 크게 복잡하지는 않다. 단지 무지막지하게 복잡하게 만들 수 있고 메서드도 많을 뿐...
시작 코드는 대강 이렇다 :
import 'package:flutter/material.dart';
import 'profile.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({ Key? key }) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'It\'s over anakin',
theme: ThemeData(
primarySwatch: Colors.blue
),
home: const Profile(),
//home: MyHomePage(),
);
}
}
main이 runApp을 호출하고, StatelessWidget인 MyApp()이 리턴된다. 여기서 재미있는 것은 build함수 내부에 "위젯"이라 불리는 UI단위들을 rescursive하게 넣어서 갖가지 기능을 구현할 수 있다.
일반적으로 Flutter의 Dart에 대한 기본적인 컨벤션은 :
class 이름은 첫자 포함 낙타체
변수 이름 / namedArgument 이름은 첫차 제외 낙타체
1. MaterialApp
앱의 최상단에 위치하는 거대한 껍데기.
(1).debugShowCheckedModeBanner : bool
오른쪽 위에 위치한 빨간색 Demo표식을 지우고 싶으면 false
(2).home : Widget
여타 다른 Widget의 child와 비슷하나, 여기서 부터 진짜로 drawing이 되는 속성이 부여되는 듯싶다.
(3).theme : ThemeData
앱의 전체적인 theme을 만들 수 있는 것 같다. 저 위의 예제에서는 primarySwatch 정도만 부여했다.
2. Scaffold
처음에 이 낱말을 보자마자 든 생각은 :
아무튼 앱의 제일 큰 뼈대이다. 처음에 body만 생각하면 대수롭지 않게 생각할지도 모르겠지만, 상단의 appbar / 좌단의 drawer / 중앙의 body로 큼직큼직한 구획을 나누는 역할을 맡는, 말 그대로 스케폴딩 같은 역할일지도 모르겠다.
(1).backgroundColor : Color
(2).appbar : Appbar
상단 AppBar, 따로 Class도 있으니 쓰자.
(3).drawer : Drawer
좌단 Drawer, 마찬가지로 따로 Class도 있으니 쓰자.
(4).body : Widget
얘는 예외, Padding도 좋고 Center도 좋고... 일단 말이 되는 위젯이면 된다.
3. AppBar
앱의 상단에 위치하는, 어째서인지 있으면 구려 보일 때가 많은, 그 UI이다.
(1).backgroundColor : Color
(2).centerTitle : bool
false일시 좌측 정렬
(3).elevation : float
AppBar의 아래에 비칠 그림자 크기. 아래쪽이 아니라 아예 AppBar 아래의 여백에 그림자가 생긴다. 0이면 그림자가 생기지 않는다.
(4).actions : <Widget>[]
AppBar 오른쪽에 아이콘을 여러 개 추가할 수 있다.
(5).leading : Widget
AppBar 왼쪽에 아이콘을 한 개 추가할 수 있다.
예제 :
AppBar(
title: const Text("Profile"),
backgroundColor: Colors.blue[700],
centerTitle: true,
elevation: 0.0,
actions: <Widget>[
Builder(builder: (context) =>
IconButton(
icon: Icon(Icons.menu),
onPressed: () => Scaffold.of(context).openDrawer(),
))],
leading: IconButton(
icon: Icon(Icons.access_alarm_outlined),
onPressed: () {},
),
)
4. Drawer
앱의 왼쪽에서 보이지 않다가 튀어나오는 그 UI. 오른쪽 버전도 있을 것 같다.
(1).child : Widget
AppBar랑은 다르게 이 녀석은 크게 특징이... 없다? API를 찾아보면 또 있겠지만 (예를 들어 튀어나오는 속도라던가)
암튼 직접 이렇게 ListView로 구현해주어야한다.
예제 :
Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
UserAccountsDrawerHeader(
currentAccountPicture: CircleAvatar(
backgroundImage: AssetImage('assets/github_bruh.png'),
),
accountEmail: Text('Yee@naver.com'),
accountName: Text('WhatThe...'),
onDetailsPressed: () {
print("Arrow");
},
decoration: BoxDecoration(
color: Colors.amber[800],
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(40.0),
bottomRight: Radius.circular(40.0)
)
),
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
tileColor: Colors.grey[300],
onTap: () {
},
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Settings'),
tileColor: Colors.grey[300],
onTap: () {
},
),
ListTile(
leading: Icon(Icons.chat),
title: Text('Q&A'),
tileColor: Colors.grey[300],
onTap: (){
},
)
],
),
),
암튼 복습은 오늘은 여기까지! 진도도 나가야하니까. 어떤 모 책에 의하면, 일단 동기부여를 하는 첫 번째는 죄다 쪼개는 거라고 한다. 그러니까 글도 쪼갤거다.