Flutter 의 Layout 로직
iOS 에서 UIView에 대응되는 것이 Widget 이다. 그리고 이 Widget 은 StatefulWidget과 StatelessWidget 두가지 타입이 있다. 말 그대로 State를 갖는 Widget 과 State가 없는 Widget.
여기에서 먼저 State Driven UI에 대해서 알아볼 필요가 있다.
State Driven UI
Flutter가 UI는 방식이다. State가 변하면 UI가 State에 맞게 변경되는 방식이다. 사용자가 버튼을 누르는 것, 네트워크, realm 등 외부의 저장소에서 데이터를 가져오는 것은 모두 State 를 변경시킨다.
React 의 UseState를 사용하는 것과 유사하다. 사실 같다고 느꼈다.
그렇다면 각 Widget 의 의미는 무엇일까?
•
StatefulWidget
상태를 갖는 Widget이다 ⇒ 상태는 변할 수 있고, 상태가 변하면 UI가 바뀐다 ⇒ 상태에 따라서 값이 변하는 Widget 을 만들때 사용한다
•
StatelessWidget
상태를 갖지 않는 Widget이다 ⇒ 상태가 없으니 변할 수 없고, UI도 변경할 수 없다 ⇒ 처음 생성된 상태에서 변경될 가능성이 없다
앞으로 UI를 만들 때, 변경이 없는 단순 정보성 UILabel 느낌의 View 라면 StatelessWidget, 사용자와 인터렉션을 통해 다양한 정보를 표시하는 View 라면 StatefulWidget 이라는 정답을 내릴 수 있다.
StatefulWidget
StatefulWidget을 만들기 위해서 2개의 클래스를 생성해야 한다
•
Widget
•
State
Widget과 State 가 한 쌍으로 함께 붙어다니게 된다.
Widget
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
Swift
복사
State
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Swift
복사
위 코드는 Android Studio 에서 Flutter 프로젝트 생성할 때 자동으로 생성되는 Sample code 입니다.
StatefulWidget에서 Widget은 굉장히 가볍습니다. State 를 들고(?)있는 게 가장 큰 임무입니다. 실질적으로 UI를 그리는 것은 build 함수를 갖고 있는 State 입니다.
State 앞에 _ 언더바를 붙이는 것은 컨벤션 같습니다.
주의깊게 살펴볼 내용
•
_incrementCounter()
state는 함수를 갖습니다. 외부에서 UI 변경을 위해서 State 를 변경해야 하는데, State 를 변경하는 방법으로 State의 함수를 호출합니다.
•
setState()
_incrementCounter() 함수 내부에서 setState 라는 함수를 호출하고 있습니다. setState 함수를 호출하는 것은 State 를 변경할 테니, UI를 갱신해야한다. 라는 명령을 내리는 것과 같습니다.
•
@override build
build 함수를 override 하고 UI 로직을 구현하는 부분입니다. setState 함수를 활용해 State 를 변경하고 나면, 변경된 state 를 UI에 반영하기 위해 build 함수가 호출됩니다. 개발자가 State를 활용해 UI를 만들어야 하는 부분이 이곳 build 함수입니다.
iOS에서 setNeedLayout() 으로 갱신 필요 flag 를 찍는 것과 같다고 생각하면 됩니다.
StatelessWidget
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
Swift
복사
위 코드는 Android Studio 에서 Flutter 프로젝트 생성할 때 자동으로 생성되는 Sample code 입니다.
StatelessWidget 의 코드는 간단한 편입니다.
UI를 그리는 build 함수가 StatelessWidget 클래스 내에 구현됩니다.
심화학습
1.
State의 하나의 함수 내에서 setState() 를 두번 그리는 경우, 화면은 2번 그려질까 한번만 그려질까 (= build 함수가 1번 불릴까? 두번 불릴까?)
2.
StatelessWidget 은 당연히 StatefulWidget 에 비해서 성능상 이점이 있을 듯 한데, 어느정도 일까?