์ด๋ฒ์๋ Flutter์ UI์ ๊ดํ์ฌ ๊ณต๋ถ๋ฅผ ํ์์ต๋๋ค.
๋ง์ฝ Flutter๊ฐ ๋ฌด์์ธ์ง ์ ๋ชจ๋ฅด์๋ ๋ถ๋ค์ ์๋์ ๊ธ์ ๋จผ์ ์ฝ๊ณ ์์ฃผ์๊ธธ ๋ฐ๋๋๋ค.
Flutter / 2ํ : Flutter ํน์ง๊ณผ ์ฅ๋จ์
๋ชฉ์ฐจ
- ๋ชจ๋ ๊ฒ์ด Widget
- ์ ์ธ์ UI ๋ฐฉ์
- Stateless, Stateful Widget
- ํ๋ฉด ์ ํ (Navigator์ Route)
- Stateful Widget์ Lifecycle (์๋ช ์ฃผ๊ธฐ)
- ๋ ์ด์์ ๋ฐฐ์น ๋ฐฉ๋ฒ
- ๋ง์น๋ฉด์
๋ชจ๋ ๊ฒ์ด Widget
Flutter์์ UI ์ ์ธ ๋ฐ ๊ตฌ์ฑ๋ฐฉ์๊ณผ ๊ด๋ จ๋ ๋ชจ๋ ๊ฒ์ ์์ ฏ์ผ๋ก ์ด๋ฃจ์ด์ ธ ์์ต๋๋ค. ๋ ์ฝ๊ฒ ๋งํด๋ณด์๋ฉด Java์์๋ ๋ชจ๋ ๊ฐ์ฒด๊ฐ Object๋ผ๋ Class๋ฅผ ์์๋ฐ์ต๋๋ค. ์ด์ ๋ง์ฐฌ๊ฐ์ง๋ก Flutter์์ UI ์ ์ธ ๋ฐ ๊ตฌ์ฑ๋ฐฉ์์ ๊ด๋ จ๋ ๋ชจ๋ ๊ฒ๋ค์ Widget์ ์์๋ฐ์ต๋๋ค.
์ ์ธ์ UI ๋ฐฉ์ (declarative style of UI)
๊ธฐ์กด์ Android, IOS์์๋ ๋ช ๋ นํ UI ๋ฐฉ์(imperative style of UI)์ ํตํด UI๋ฅผ ์์ฑํด์์ต๋๋ค. ํ์ง๋ง Flutter์์๋ React Native์ ๊ฐ์ ์ ์ธ์ UI(declarative style of UI) ๋ฐฉ์์ ์ฑํํ๊ณ ์์ต๋๋ค.
์ ์ธ์ UI ๋ฐฉ์์ด๋ UI ๊ฐ์ฒด๋ฅผ ์ง์ ๋ง๋๋ ๊ฒ์ด ์๋๋ผ, UI์ ์ค๋ช ๋ง ์์ฑํ๋ ๋ฐฉ์์ ๋ปํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด ํ๋ ์์ํฌ๊ฐ Render Object๋ฅผ ํตํด UI๊ฐ์ฒด ์์ฑ๊ณผ ์ ์ง๋ฅผ ๋ค์์ ๊ด๋ฆฌํด์ค๋๋ค. ์ฆ ์ฐ๋ฆฌ๋ UI ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ณ ์ ์ง๋๋ ์ธ์ธํ ์์ ์ ๋ชฐ๋ผ๋ ๋๋ค๋ ๊ฒ ์ ๋๋ค. ๊ทธ๋ฅ UI์ ๋ํ ์ค๋ช ์ ์ ์์ฑํ๋ฉด ํ๋ ์์ํฌ๊ฐ ๋๋จธ์ง๋ ์์์ ํด์ค๋๋ค. ํ์ง๋ง ํ๋ ์์ํฌ๊ฐ UI๊ฐ์ฒด ์์ฑ๊ณผ ์ ์ง๋ฅผ ๊ด๋ฆฌ๋ฅผ ํด์ฃผ๊ธฐ ๋๋ฌธ์, UI ๊ฐ์ฒด๋ฅผ ์ง์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. (๋ถ๋ณ) UI ๊ฐ์ฒด๋ฅผ ๋ณ๊ฒฝํ๋ ค๋ฉด UI์ ๋ํ ์ค๋ช ์ ๋ณ๊ฒฝํ ํ ๋ค์ UI ๊ฐ์ฒด๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.
์ด๋ฅผ Flutter๋ก ์นํํ๋ฉด “UI์ ๋ํ ์ค๋ช ์ Widget์ด๋ผ๊ณ ํ ์ ์๊ณ Widget์ ํตํด Flutter ํ๋ ์์ํฌ๊ฐ ์๋์ผ๋ก UI๊ฐ์ฒด๋ฅผ ์์ฑ๊ณผ ์ ์ง๋ฅผ ํด์ค๋ค. ๋ง์ฝ ๋ณ๊ฒฝ์ฌํญ์ด ์ผ์ด๋๋ฉด Widget์ ๋ณ๊ฒฝ์ํค๊ณ UI ๊ฐ์ฒด๋ฅผ ๋ค์ ์ฌ์์ฑํ๋ค.” ์ ๋๋ก ์ ๋ฆฌํ ์ ์์ ๋ฏ ํฉ๋๋ค.
Stateless, Stateful Widget
์์ ฏ์ ํฌ๊ฒ ๋ ๊ฐ์ง Stateful, Stateless Widget์ผ๋ก ๋๋์ด๊ฒ ๋ฉ๋๋ค. ์ฐ๋ฆฌ๋ ์์์ Flutter๊ฐ ์ ์ธ์ UI ๋ฐฉ์์ ํํ๋ค๋ ๊ฒ์ ๋ฐฐ์ ์ต๋๋ค. ๋ฐ๋ผ์ UI ๊ฐ์ฒด๋ ๋ณ๊ฒฝํ ์ ์์ผ๋ฉฐ Widget์ ๋ณ๊ฒฝ ํ ์ฌ์์ฑํด์ผ๋๋ค๋ ์ฌ์ค์ ์์ค ๊ฒ ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด์ ๊ดํ ๊ฐ๋ ์ด Stateless, Stateful Widget ์ ๋๋ค.
Stateless, Stateful๋ก ๊ฐ๋ ์ด ๋๋์ด์ก๋ค๊ณ ํด์ ๋ด๋ถ๋์์ด ๋ค๋ฅด๊ฒ ์ด๋ฃจ์ด์ง๋ ๊ฒ์ ์๋๋๋ค. ๋์ ๋๊ฐ์ด Widget์ ์์๋ฐ์๊ณ ๋์ผํ๊ฒ ์๋ํฉ๋๋ค. ํ์ง๋ง ๋์ค์๋ ๋งํ๊ฒ ์ง๋ง Stateful Widget์ State๋ผ๋ ์๋ธํด๋์ค๋ฅผ ๊ฐ๊ณ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๊ฒ์ด Stateless Widget๊ณผ Stateful Widget๊ฐ์ ์ ์ผํ ์ฐจ์ด์ ๋๋ค.
Stateless Widget์ ๋ํด ๋จผ์ ๋งํด๋ณด์๋ฉด ๋ง๊ทธ๋๋ก ์ํ์ ๋ณด๊ฐ ์๋ Widget์ ๋๋ค. ์ฆ ๋ณ๊ฒฝ์ด ์ผ์ด๋์ง ์๋ Widget์ด๋ผ๋ ๊ฒ ์ ๋๋ค. ๋ณ๊ฒฝ์ด ์ผ์ด๋์ง ์๊ธฐ ๋๋ฌธ์ ์ํ๋ฅผ ๊ตณ์ด ๊ด์ฐฐํ ํ์๊ฐ ์๋ ๊ฒ ์ ๋๋ค. ์ฑ ํ๋ฉด์ ๋ก๊ณ (AssetImageWidget)๋ฅผ ๋ํ์ ์ธ ์์๋ก ๋ค ์ ์์ต๋๋ค. ์ฑ์ด ์คํ๋๋ ๋์ ์ฑ ํ๋ฉด์ ๋ก๊ณ ๊ฐ ๋ณ๊ฒฝ๋๋ ์ผ์ ์์ต๋๋ค.
Stateful Widget์ Stateless Widget๊ณผ ๋ค๋ฅด๊ฒ ์ํ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ Widget์ ๋๋ค. Stateful Widgte์ State๋ผ๋ ์๋ธ ํด๋์ค๋ฅผ ํตํด ์ํ์ ๋ณด๋ฅผ ์ ์ฅํฉ๋๋ค. ๋ง์ฝ ๋ณ๊ฒฝ์ด ์ผ์ด๋ ์์๋ setState() ํจ์๋ฅผ ํธ์ถํ์ฌ State ์ ๋ณด๋ฅผ ๋ณ๊ฒฝ์ํต๋๋ค. ๊ทธ๋ฌ๋ฉด ํ๋ ์์ํฌ๊ฐ ๋ณ๊ฒฝ์ ๊ฐ์งํ์ฌ ํด๋น UI ๊ฐ์ฒด๋ฅผ ์ฌ์์ฑํ๊ฒ ๋ฉ๋๋ค. ๋ฒํผ์ ๋๋ฅด๋ฉด Text๊ฐ ๋ฐ๋๋ ๋ฑ์ ๋์์ ๋ํ์ ์ธ ์์๋ก ๋ค ์ ์์ต๋๋ค.
์๋๋ Stateless, Stateful Widget์ ์์์ ๋๋ค.
import 'package:flutter/material.dart';
void main() {
runApp(SampleApp());
}
class SampleApp extends StatelessWidget { // ์ต์์ Widget์ ๋ณ๊ฒฝ์ด ์์์ผ๋ก Stateless Widget
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
// Default placeholder text
String textToShow = "I Like Flutter";
void _updateText() {
setState(() { // State ๋ณ๊ฒฝ
textToShow = "Flutter is Awesome!";
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample App"),
),
body: Center(child: Text(textToShow)),
floatingActionButton: FloatingActionButton(
onPressed: _updateText,
tooltip: 'Update Text',
child: Icon(Icons.update),
),
);
}
}
ํ๋ฉด์ ํ (Navigator, Route)
ํ๋์ ํ๋ฉด์ผ๋ก ๋์๋๋ ์ฑ์ ์ ๋ง ๊ฑฐ์ ์์ต๋๋ค. ๊ทธ๋ ๊ธฐ์ ํ๋ฉด์ ์ ํํ ์ ์๋ ๊ฒ์ ์ฑ์ ๊ธฐ๋ณธ์ค์ ๊ธฐ๋ณธ์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ Flutter์์๋ Navigator์ Route๋ฅผ ํตํด ํ๋ฉด์ ํ์ ์ํํฉ๋๋ค. Route๋ ํ๋ฉด์ ๋ํ ์ถ์ํ์ด๋ฉฐ Navigator๋ Rotue๋ฅผ ๊ด๋ฆฌํ๋ ์์ ฏ์ ๋๋ค.
Route๋ ์ด๋ฆ ๊ทธ๋๋ก ํ๋ฉด์ ํ์ผ ๊ฒฝ๋ก์ฒ๋ผ ์ถ์ํํ ๊ฒ ์ ๋๋ค. ๋ณดํต ‘/login’, ‘/home’ ๊ณผ ๊ฐ์ด ๊ฒฝ๋ก๋ฅผ ์ค์ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ Map์ ํตํด์ ๊ฒฝ๋ก์ ํด๋น ํ๋ฉด์ ๋งค์นญ์ํต๋๋ค.
๋ค์์ Map์ ์ด์ฉํ์ฌ Route๋ฅผ ์ ์ธํ๋ ์์์ ๋๋ค.
void main() {
runApp(MaterialApp(
home: MyAppHome(), // becomes the route named '/'
routes: <String, WidgetBuilder> {
'/a': (BuildContext context) => MyPage(title: 'page A'),
'/b': (BuildContext context) => MyPage(title: 'page B'),
'/c': (BuildContext context) => MyPage(title: 'page C'),
},
));
}
Navigator๋ ์คํ์ผ๋ก Route๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.push(), pop()์ ํตํด ํ๋ฉด ๊ฒฝ๋ก๋ฅผ ์กฐ์ ํฉ๋๋ค. push(route)๋ฅผ ํ๋ฉด ํด๋น Route๋ก ํ๋ฉด์ ์ด๋ํ ์ ์๊ณ , pop()์ ํ๋ฉด ์ด์ Route๋ก ๋์๊ฐ ์ ์์ต๋๋ค. ๋ค์์ Navigator๋ฅผ ํตํด ํ๋ฉด์ ์ด๋ํ๋ ์์์ ๋๋ค.
Navigator.of(context).pushNamed('/b');
Stateful Widget์ Lifecycle (์๋ช ์ฃผ๊ธฐ)
Android๋ฅผ ์ ํด๋ณด์ ๋ถ๋ค์ Lifecycle์ ์ต์ํ์ค ๊ฒ ์ ๋๋ค. Lifecycle์ ๋ง๊ทธ๋๋ก ์๋ช ์ฃผ๊ธฐ๋ฅผ ๋ปํฉ๋๋ค. ์ธ๊ฐ์ผ๋ก ๋ฐ์ง๋ฉด (์๊ธฐ -> ์ฒญ๋ -> ์ค๋ -> ๋ ธ์ธ -> ์ฃฝ์)์ Lifecycle์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค.
Lifecycle์ด ํ์ํ ์ด์ ๋ ์์ ์ธ๊ฐ์ ์์๋ฅผ ๋ค๋ฉด ์ฝ๊ฒ ์ดํดํ ์ ์์ต๋๋ค.
1. ์๊ธฐ๋๋ ์ง์์ ์ต๋ํด์ผ ํฉ๋๋ค.
2. ์ฒญ๋ ๋๋ ๊ฟ์ ์ด๋ฃจ๊ธฐ ์ํด ๋ ธ๋ ฅํด์ผ ํฉ๋๋ค.
3. ์ค๋ ๋๋ ์์ ์ ๊ฐ์ถ๊ณ ๋จ์๊ฒ ๋์์ด ๋๊ณ ์ ๋ ธ๋ ฅํด์ผ ํฉ๋๋ค.
4. ๋ ธ์ธ๋๋ ์ฃฝ์์ ์ค๋นํด์ผ ํฉ๋๋ค.
์์ ์์์ฒ๋ผ Lifecycle์ด ์์ผ๋ฉด ๊ฐ๊ฐ์ ์ฃผ๊ธฐ๋ง๋ค ํ ํ๋์ ์ง์ ํ ์ ์์ต๋๋ค.
Stateless Widget์ ์ด๋ฐ Lifecycle์ ์ ๊ฒฝ์ธ ํ์๊ฐ ์์ต๋๋ค. ์ด์ฐจํผ ๋ณ๊ฒฝ์ด ์ผ์ด๋์ง ์๊ธฐ ๋๋ฌธ์ Framework์๊ฒ 100% ๋งก๊ธฐ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ํ์ง๋ง ๋ณ๊ฒฝ์ด ์ผ์ด๋๋ Stateful Widget์๊ฒ๋ Lifecyle์ด ํ์ํฉ๋๋ค.
์๋๋ StatefulWidge์ Lifecycle์ ๋๋ค.
- createState()
State ๊ฐ์ฒด๊ฐ ์ต์ด๋ก ์์ฑ๋๋ ์์ BuildContext๊ฐ State์ ํ ๋น๋๋ค. - mounted == true
BuildContext๊ฐ State์ ํ ๋น๋๋์ง ํ์ธํ๋ค.
ํ ๋น๋์ผ๋ฉด State๊ฐ ๋ง์ดํธ๋ ๊ฒ์ผ๋ก ๋ณด๊ณ true๋ฅผ ๋ฐํํ๋ค. - initState()
์ด Lifecycle๋ Widget ํน์ BuildContext ์ด๊ธฐํํ๋ฉด ๋๋ค. - didChangeDependencies()
์์ํ Widget์ด ์ ๋ฐ์ดํธ๋ ๋ ํธ์ถ๋๋ค. - build()
Widget์ ๋ฆฌํดํ๋ฉฐ ์ด๋ฅผ ๋ฐํ์ผ๋ก Framework๊ฐ UI๋ฅผ ๊ทธ๋ฆฐ๋ค. - didUpdateWidget()
Widget์ ๋ณ๊ฒฝ์ด ์์๋ ํธ์ถ๋๋ค. - setState()
์์์๋ ๋ดค๋ ํจ์๋ก ํ๋ ์์ํฌ์ ๋ณ๊ฒฝ์ฌํญ์ ์๋ฆฐ๋ค. - deactivatie()
State ๊ฐ์ฒด๊ฐ ์ญ์ ๋๋ค.
์ญ์ ๋๋ ์ ๋๋ฉ์ด์ ํ๋ ์์ด ๋๋๊ธฐ ์ ์ ์ฌ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. - dispose()
State ๊ฐ์ฒด๊ฐ ํธ๋ฆฌ์์ ์๊ตฌ์ ์ผ๋ก ์ญ์ ๋๋ค. - mounted == false
State์ ๋ง์ดํธ๊ฐ ์์ ํ ํด์ ๋๋ค.
์์ธํ ์ฌํญ์ ์๋์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์
๋ ์ด์์ ๋ฐฐ์น ๋ฐฉ๋ฒ
์ด์ธ์ ๊ธฐํ๋ก UI๋ฅผ ๋ฐฐ์นํ๋ ๋ฒ์ ๋ํด์ ๋งํด๋ณด์๋ฉด Flutter์์๋ Widget Tree๋ฅผ ์ด์ฉํด์ ๋ฐฐ์น๋ฅผ ํฉ๋๋ค.
์์ธํ ์ฌํญ์ ์๋์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ์ฝ๊ฒ ์ดํดํ์ค ์ ์์ ๊ฒ ์ ๋๋ค.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample App"),
),
body: Center( // ์ฌ๊ธฐ์ ์ง์ค
child: MaterialButton(
onPressed: () {}, // ์ด๋ฐ์์ Tree ๋ฐฉ์์ผ๋ก UI๋ฅผ ๊ตฌ์ฑํจ
child: Text('Hello'),
padding: EdgeInsets.only(left: 10.0, right: 10.0),
),
),
);
}
์ฌ๊ธฐ๊น์ง๊ฐ Flutter์ UI์ ๋ํ ์ค๋ช ์ด์์ต๋๋ค.
์ค๋ช ์ด ๋ถ์กฑํ์ ๋ถ์ ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์
๊ทธ๋ฆฌ๊ณ ์๋ชป๋ ์ค๋ช ์ ๋ฐ๊ฒฌํ์ ๋ถ์ ๋๊ธ๋ก ์ง์ ํด์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค :)
๋ง์น๋ฉด์
์ ๋ Google์ด ๋ง๋ค์๋ค๊ณ ํ์ฌ์ Android์ ๋น์ทํ ๋ถ๋ถ์ด ๋ง์ ์ค ์์๋๋ฐ ์ ํ ์๋์์ต๋๋ค.
์คํ๋ ค React Native์๊ฒ ํฐ ์ํฅ์ ๋ฐ์ ๋ฏ ํฉ๋๋ค.
Flutter์ ์๋ ๋ง์ ๋ฐฉ์๋ค์ด React Native์ ๋ฎ์์์ต๋๋ค. (์ ์ธ์ UI ๋ฐฉ์, Router ๋ฐฉ์, ๋ฑ๋ฑ)
๊ฐ๋ฉด ๊ฐ์๋ก Flutter๊ฐ ํฅ๋ฏธ๋ก์์ง๋ ๊ฒ ๊ฐ์ต๋๋ค. ใ ใ
๋ค์ํ์์๋ Background์ ๋ํด ๋ค๋ค๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๊ฐ์ฌํฉ๋๋ค :)
'Flutter' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Flutter Provider + '?' ํจํด (feat. ChangeNotifier, Mobx, BLoC, etc..) (0) | 2020.09.12 |
---|---|
Flutter / 4ํ : Flutter์ ์ํ๊ด๋ฆฌ (0) | 2020.08.01 |
Dart / 1ํ : Dart์ ์ค์ํ ๊ฐ๋ (0) | 2020.07.26 |
Flutter / 2ํ : Flutter ํน์ง๊ณผ ์ฅ๋จ์ (0) | 2020.07.24 |
Flutter / 1ํ : Flutter ์์, ์ค์นํ๊ธฐ (Window, Android Studio) (0) | 2020.07.24 |