@override
Widget build(BuildContext context) {
return Scaffold(
)
}
위젯을 만들 때 마다 항상 등장하는 BuildContext가 속해 있는 코드이다.
자세히 살펴보면, "Widget 타입의 build 메서드가 BuildContext라는 타입의 context를 인자로 받아 Scaffold 위젯을 리턴하는" 형태임을 알 수 있다.
즉, context는 BuildContext 클래스의 인스턴스다.
ex)
class Person{
String name;
int age;
}
void main () {
Person p1 = Person();
}
여기서 BuildContext는 위젯이 화면에 어디에 있는지에 대한 위치 정보를 담고 있다.
build 함수는 Scaffold 위젯을 리턴하는데 이때 위젯트리 상에서 부모 위젯이 어디에 위치하는가에 대한 정보를 담은 context를 넣어 Scaffold 위젯을 리턴하는 것이다. 따라서 BuildContext란, 위젯의 위치 정보를 담고 있다고 보면 된다.
그리고 모든 위젯은 BuildContext를 가지고 있는데, 이때 BuildContext는 build 메서드에 의해서 리턴된 위젯의 부모가 된다.
아래 코드를 다시 살펴보자.
class MyHomePage extends StatelessWidget {
const MyHomePage({ Key? key }) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
)
}
}
MyHomePage라는 커스텀 위젯은 자신만의 context를 가지고 있다. build 메서드를 통해 Scaffold 위젯이 리턴되었고 Scaffold는 부모인 MyHomePage의 context를 그대로 물려받는다. 모든 위젯은 BuildContext를 가지고 있고, BuildContext는 리턴된 위젯의 부모가 되기 때문이다.
그럼 Scaffold의 위치가 필요하여 Scaffold의 context를 확인하려면 어떻게 해야할까?
Scaffold가 부모의 컨텍스트를 그대로 물려 받은 것 처럼, 빌드 메서드로 Scaffold 하단에서 무언가를 리턴해서 Scaffold 위젯의 진짜 context를 물려받으면 될 것이다!
많이 활용되는 스낵바 예시로 살펴보자!
Scaffold.of(context).showSnackBar()
스낵바를 실행하기 위해 필요한 위의 코드를 살펴보면,
"of(context)를 통해 Scaffold의 위치를 참조한 후, showSnackBar 메소드를 통해 구현해야한다"는 의미다.
스낵바는 Scaffold의 위에 그려져야 하기 때문에 Scaffold의 정확한 context를 참조해서 그곳에 스낵바를 그릴 수 있도록 해야 한다는 것이다.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Appbar',
theme: ThemeData(primarySwatch: Colors.red),
home: MyPage(),
);
}
}
class MyPage extends StatelessWidget {
const MyPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Snack Bar'),
centerTitle: true,
),
body: Center(
child: FlatButton(
child: Text(
'Snack Bar Test',
style: TextStyle(
color: Colors.white
),
),
color: Colors.red,
onPressed: () {
Scaffold.of(context).showSnackBar(SnackBar(content: Text('Hello World'),));
},
),
),
);
}
}
그런데 위처럼 코드를 작성하면 에러가 나게 된다.
context는 리턴되는 위젯의 것이 아닌 부모인 BuildContext의 것 즉, MyPage이다. 왜냐하면 부모 위젯의 컨텍스트를 그대로 물려받게 되기 때문이다.
Scaffold를 찾으러 위로 갔으나 MyPage의 스캐폴드를 찾게 되고, 계속 올라가면서 찾지만 결국 리턴하는 위젯의 Scaffold를 찾지 못하게 되서 오류 메시지가 나오게 된다. Scaffold를 찾을 수 있게 하려면 Scaffold 보다 밑에 있는 위젯의 context를 사용할 수 있게 하면 된다.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Appbar',
theme: ThemeData(primarySwatch: Colors.red),
home: MyPage(),
);
}
}
class MyPage extends StatelessWidget {
const MyPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Snack Bar'),
centerTitle: true,
),
body: Builder( // 빌더 위젯추가!
builder: (BuildContext ctx) {
return Center(
child: FlatButton(
child: Text(
'Show me',
style: TextStyle(color: Colors.white),
),
color: Colors.red,
onPressed: () {
Scaffold.of(ctx).showSnackBar(SnackBar(
content: Text('Hello'),
));
},
),
);
},
));
}
}
빌더 위젯을 통해 새로운 context가 생겼고 이제 Builder Widget 위에서 찾아 올라가며 Scaffold 위젯을 찾을 수 있게 되면서 정상적으로 스낵바가 생성된다.