BuildContext
위젯 트리 내 위젯의 위치 정보를 가지는 클래스입니다. StatelessWidget.build 또는 State 객체(주로 StatefulWidget과 같이 활용되는)에서 사용가능한 메소드들을 제공합니다.
StatelessWidget.build
아래 코드와 같이 StatelessWidget.build 메소드를 사용였습니다. build 메소드 하위 블록 {} 에서 context 를 이용한 작업 수행이 가능합니다.
import 'package:flutter/material.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
...
}
}
난 context를 선언하지 않았는데?
이 부분 추가로 글 작성하겠습니다.
context.hashcode
이후 다룰 예제에서 두 개 이상의 BuildContext가 서로 다른 BuildContext인지 확인하기 위해 hashcode 속성을 사용하겠습니다.
import 'package:flutter/material.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
...
print(context.hashcode); // 예: 805658925
...
}
}
of(context)
주로 Scaffold 에서 BottomSheet를 통제할 때 사용합니다. 이외, 다양하게 사용 가능합니다.
주의해야 할 점은, of 메소드는 인자로 받은 BuildContext의 가장 가까운 부모 BuildContext부터 탐색합니다. 아래는 ScaffoldState.of(BuildContext context) 메소드 정의 소스코드 일부입니다. findAncestorStateOfType 메소드를 통해 인자로 받은 context기준 부모 ScaffoldState를 반환하도록 설계되어 있습니다.
static ScaffoldState of(BuildContext context) {
final ScaffoldState? result = context.findAncestorStateOfType<ScaffoldState>();
if (result != null) {
return result;
}
...
따라서 아래 예제는 오류를 출력합니다. 예제의 of 메소드는 Scaffold 부모 위젯의 BuildContext부터 탐색합니다.
import 'package:flutter/material.dart';
void main() => runApp(const ShowBottomSheetExampleApp());
class ShowBottomSheetExampleApp extends StatelessWidget {
const ShowBottomSheetExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child : ElevatedButton(
child: const Text('showBottomSheet'),
onPressed: () {
Scaffold.of(context).showBottomSheet<void>(
(BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('BottomSheet'),
ElevatedButton(
child: const Text('Close BottomSheet'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
);
},
);
},)
),
),
);
}
}
══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
The following assertion was thrown while handling a gesture:
Scaffold.of() called with a context that does not contain a Scaffold.
No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). This
usually happens when the context provided is from the same StatefulWidget as that whose build
function actually creates the Scaffold widget being sought.
이 문제를 해결하기 위해 Scaffold 위젯 내 자식 Builder 위젯을 만들어 Builder 위젯의 BuilderContext를 전달하도록 만들어 주세요. of 메소드는 이제 Builder 위젯의 BuildContext의 부모인 Scaffold의 BuildContext부터 탐색합니다.
import 'package:flutter/material.dart';
void main() => runApp(const ShowBottomSheetExampleApp());
class ShowBottomSheetExampleApp extends StatelessWidget {
const ShowBottomSheetExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child : Builder(
builder : (BuildContext context) {
return ElevatedButton(
child: const Text('showBottomSheet'),
onPressed: () {
Scaffold.of(context).showBottomSheet<void>(
(BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('BottomSheet'),
ElevatedButton(
child: const Text('Close BottomSheet'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
);
},
);
},);
})
),
),
);
}
}
그럼 BuildContext들을 서로 구별할 수 있도록 context1 context2 로 바꾸어 출력결과를 보겠습니다. 서로 다른 hashCode를 출력하는 것을 확인할 수 있습니다. 아래 코드에서 Scaffold.of(context2) 를 Scaffold.of(context1)로 바꾸면 에러가 납니다.
import 'package:flutter/material.dart';
void main() => runApp(const ShowBottomSheetExampleApp());
class ShowBottomSheetExampleApp extends StatelessWidget {
const ShowBottomSheetExampleApp({super.key});
@override
Widget build(BuildContext context1) {
return MaterialApp(
home: Scaffold(
body: Center(
child : Builder(
builder : (BuildContext context2) {
return ElevatedButton(
child: const Text('showBottomSheet'),
onPressed: () {
print(context1.hashCode); // 1064410590
print(context2.hashCode); // 931118754
Scaffold.of(context2).showBottomSheet<void>(
(BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
...
참고 자료