flutter에서 거의 모든 것이 위젯이며, 위젯은 뷰를 묘사하는 다트 클래스이다. 위젯은 요소를 화면에 표시할 때 플러터가 사용하는 청사진이다. 위젯 클래스는 플러터가 이해할 수 있는 뷰 모델이다. 위젯에는 컨트롤러나 뷰가 따로 없다.
위젯은 특정 UI를 정의하는 클래스다!
리액트나 다른 프레인워크 컴포넌트와 달리 위젯은 앱 뷰의 모든 사항을 정의할 수 있다. 예를 들어, css에서 원하는 컴포넌트에 패딩을 추가할 수 있다면 플러터에서는 스타일을 다른 위젯으로 설정한다. 심지어 앱의 경로도 위젯이다. build라는 메서드로 다른 위젯을 반환하는 커스텀 위젯을 정의한다.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp()); //앱의 진입점
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
//슈퍼클래스의 메소드 createState를 오버라이드한다.
State<MyHomePage> createState() => _MyHomePageState();
//StatefulWidget은 State객체를 반환하는 createState를 반드시 정의해야 한다.
}
class _MyHomePageState extends State<MyHomePage> {
//상태 클래스는 flutter의 State를 상속받는다.
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
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),
),
);
}
}
위는 새 프로젝트를 실행하면 기본으로 구현되어 있는 카운트 앱의 위젯트리구조 이다.
플러터 라이브러리의 대부분의 위젯들은 StatelessWidget이나, StatefulWidget의 형식을 갖는다.
플러터 UI를 개발한다는 것은 여러 위젯들을 조합해 위젯 트리 를 만들겠다는 의미이다.
트리의 각 노드는 위젯이고 이 노드가 모여 트리가 된다.
build 메서드에서 위젯을 추가할 때마다 트리에 새 노드를 추가하는 것이고 각 노드는 부모 자식관계로 연결된다.
개미정도로 작은 꿀팁
st...라고 입력하는 것 만으로 간단하게 StatelessWidget을 구현할 수 있다.
심지어 multiple line edit도 지원한다!🤪개꿀이다.(멍꿀멍꿀)
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
//슈퍼클래스의 메소드 createState를 오버라이드한다.
State<MyHomePage> createState() => _MyHomePageState();
//StatefulWidget은 State객체를 반환하는 createState를 반드시 정의해야 한다.
}
class _MyHomePageState extends State<MyHomePage> {
//상태 클래스는 flutter의 State를 상속받는다.
Widget build(BuildContext context) {//StatefulWidget의 필수 메소드이다.
return Container();
}
}
ThemeData에서 테마를 바꾸거나 타이틀을 변경하면 모든 자식 위젯을 변경 및 갱신한다. How is that possible?
위젯의 모든 build 메서드는 위젯트리에서 위젯의 위치를 참조하는 BuildContext 하나를 인수로 받는다. build는 프레임워크가 호출하므로 BuildContext를 개발자가 관리할 필요는 없지만 자주 이를 사용하게 된다.
모든 위젯은 자신만의 BuildContext를 가지며 한 위젯이 다양한 테마를 반환하게 만들어 한 트리에 여러 테마를 적용할 수 있다. 카운터 앱의 테마나 다른 of 메서드는 트리에서 형식이 같은 가장 가까운 부모를 반환한다.
예를 들어 Scaffold > Center > Column > Text:
context.ancestorWidgetOfExactType(Scaffold) => Text 컨텍스트에서 트리 구조로 올라가서 첫 번째 Scaffold를 반환한다.
상위 BuildContext에서 하위 위젯(= 하위) 위젯 을 찾는 것도 가능 하지만 그렇게 하지 않는 것이 좋다.
BuildContext는 특정 위젯을 정확하게 어떻게 표현할지 결정한다.
예를 들어 플러터는 BuildContext를 통해 모달(modal)과 라우트(route)를 표시한다. 모달을 만드는 메서드에 BuildContext를 전달한다.
BuildContext는 빌드된 모든 위젯의 트리 구조 내 위젯 위치에 대한 참조일 뿐이다.
stateful 위젯의 경우 state는 buildContext와 연결된다. 이 연결은 영구적이며, State개체는 BuildContext를 변경하지 않는다. 트리구조에서 이동할 수 있는 경우에도 State는 해당 BuildContext와 연결된 상태로 유지된다.
State객체가 BuildContext와 연관되어 있기 때문에 State객체가 다른 BuildContext를 통해 직접 엑세스할 수 없다는 것을 의미한다.
Scaffold의 정의와 Scaffold.of를 사용하는 곳이 동일한 build 메소드에 있는 경우는 잘 찾을 수가 없게 된다.
그 이유는 of 메소드가 build를 호출하는 widget으로부터 조상을 찾아가기 때문이다. 그래서 Scaffold는 자식이기 때문에 찾지 못하는 것이다. 따라서 이런 경우는 Builder를 사용해서 찾는 것이 일반적으로 사용된다.
class HelloScrren extends StatelessWidget {
const HelloScrren({ Key? key }) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('test')),
body: Builder(
builder: (BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('snackbar'),
onPressed: () {
Scaffold.of(context).showSnackBar(const SnackBar(
content: Text('안녕!'),
));
},
),
);
}
)
);
}
}
이 포스트를 작성하기 위해 참고한 곳
https://medium.com/flutter-community/widget-state-buildcontext-inheritedwidget-898d671b7956