개요
본격적으로 플러터를 학습하기 전에, 이번 포스팅에서 기본적인 플러터의 예제 어플리케이션의 코드를 살펴본다.
Symbols
다음은 flutter run
명령어로 실행되는 기본 엔트리포인트 lib/main.dart
의 심볼 목록이다.
dart
의 엔트리포인트 main
함수, 그리고 다음의 3가지 클래스로 이루어져있다.
MyApp
MyHomePage
_MyHomePageState
main
void main() {
runApp(const MyApp());
}
- runApp() 함수의 인자로
MyApp()
을 실행한다. - Dart의 상수 생성자 기능을 이용한다.
- 상수 생성자를 이용하려면 조건이 필요한데, 모든 필드가 final로 초기화 되어야한다.
- 해당 내용은 여기를 참고했다.
- 객체가 한번 빌드되면 어플리케이션 생명주기동안 동일하게 유지되므로 성능 향상에 도움이 된다.
- 그리고, 변경 사항을 기반으로 재빌드할 위치와 대상을 알기때문에 플러터의 핫 리로딩의 성능도 향상시킨다.
MyApp Class
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
),
home: const MyHomePage(title: 'example'),
);
}
}
StatelessWidget
은 상태 변화를 하지 않는 위젯을 생성할 때 상속 받아야한다.- 여기서 상태란, 내부에 변경되는 속성이 있는 위젯
StatelessWidget Class
abstract class StatelessWidget extends Widget {
const StatelessWidget({super.key});
@override
StatelessElement createElement() => StatelessElement(this);
@protected
Widget build(BuildContext context);
}
@protected
어노테이션을 사용하는데 기본적으로protected
는 Dart에서 지원하지 않는 키워드다. 따라서 어노테이션으로 따로 구현한 것으로 보인다.@protected
로 선언된 멤버는 해당 클래스 또는 서브 클래스에서만 접근할 수 있고, 서브 클래스에서 재정의를 허용한다. 따라서 외부 클래스나 라이브러리에서는@protected
멤버에 직접 접근할 수 없다.- 어쨌든 이
build
메서드를 서브 클래스에서 재정의하여 사용자 인터페이스를 반환하는 것으로 보인다.
MyHomePage Class
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
- 상수 생성자를
StatefulWidget
에서도 사용하고 있는데, 이는title
속성이 변하지 않음을 의미하는 것이지 상태 변화와는 관계가 없다고 볼 수 있다final title
멤버는 부모 위젯으로부터 전달받은 값이고, State의build
에 사용된다.createState
메서드는MyHomePage
위젯의 상태를 관리하는_MyHomePageState
객체를 생성하여 반환한다.
_MyHomePageState()
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.onPrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text("Hello, Flutter."),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
- 이 클래스는 제네릭 클래스
State<MyHomePage>
를 상속 받는다. - 상위 위젯에
widget
속성으로 접근할 수 있다. - 내부에 변화하는 상태
_counter
와, 동적 UI가build
메서드에 정의되어 있다. _incrementCount()
가 호출되면 해당 함수 내에서setState()
가 호출되고, 플러터 프레임워크가 상태 변화를 인지하고 다음 프레임 렌더링 시에build()
를 재호출하여 변경한다.
결론
- 플러터는 크게 두 가지 위젯 StatelessWidget과 StatefulWidget을 이용하여 렌더링한다.
- 상태 변화가 필요한 위젯은 최소한의 컴포넌트 형태로 만들어야 불필요한 렌더링을 최소화하고, 성능을 향상시킬 수 있겠다.