Dialog가 뭐냐면 님들 앱쓸 때 뜨는 팝업/모달창 같은 겁니다.
이거 만드는 법을 알아봅시다. 나중에 연락처 추가할 수 있는 UI로 활용할 수도 있겠군요.
MaterialApp 디자인 쓰는 앱은 showDialog() 라는 기본 함수가 있습니다.
여기다가 파라미터 몇개 집어넣어주면 쉽게 다이얼로그가 화면에 생성됩니다.
근데 그냥 대충 쓰면 안되고 요구 조건이 몇개 있습니다.
그걸 알아봅시다.
버튼하나 아무데나 만들기
MaterialApp(
home: Scaffold(
floatingActionButton: FloatingActionButton(
child: Text('버튼'),
onPressed: (){},
),
(생략)
누르면 팝업 띄울 버튼이 필요합니다. 아무데나 버튼 하나 만드십시오.
저는 간지나게 FAB으로 만들었습니다.
showDialog() 함수
괄호 붙으면 다 위젯같아보이지만
소문자로 시작하는 것들은 함수입니다.
Flutter가 제공하는 기본 함수인 showDialog()는 쓰는 순간 Dialog가 하나가 뿅 뜹니다.
버튼의 onPressed: 안에 넣어봅시다.
근데 정해진 쓰는 법이 있습니다. 엔터 잘 치면 자동완성될걸요 아마
FloatingActionButton(
child: Text('버튼'),
onPressed: () {
showDialog(
context: context,
builder: (context){
return Dialog(
child: Text('AlertDialog Title'),
);
},
);
},
),
showDialog()에 들어갈 첫 파라미터는 context입니다. 저렇게 자동완성되는거 냅둡시다.
둘째 파라미터는 builder: 인데 여기에는 위젯을 return으로 퉤 뱉는 함수넣으시면 됩니다.
Dialog() 위젯은 모달창같은 배경 시커먼 하얀박스 만들어주는 기본 위젯입니다.
이제 버튼 누르면
Q. 사기치네 안나오는데요
A. 왜 안나오는지 궁금하다면 콘솔창을 한번 확인해보면 됩니다. 뭔가 에러같은게 뜰 수도 있습니다.
▲ 이렇게 친절하게 알려줍니다.
MaterialLocalizations 라는 변수가 조상중에 존재해야한다고 에러를 내주는데
실은 이 위젯은 MaterialApp() 에 몰래 들어있습니다. (에러메세지 잘 읽어보면 그럼)
어 근데 우리 MaterialApp() 썼는데 왜 저따구로 에러내주는 겁니까?
답부터 알려드리자면
void main() {
runApp(
MaterialApp(
home : MyApp()
)
);
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return Scaffold( 안쪽 생략 );
더 쉽게 하려면 MaterialApp() 부분을 밖으로 빼십시오
그럼 문제해결 이제 잘 동작함
답부터 알려드리자면
void main() {
runApp(
MaterialApp(
home : MyApp()
)
);
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return Scaffold( 안쪽 생략 );
더 쉽게 하려면 MaterialApp() 부분을 밖으로 빼십시오
그럼 문제해결 이제 잘 동작함
안궁금해하겠지만 이유설명
사용법만 쓱 외워가도 되겠지만
뭐든 원리를 알아야 혼자서도 코드잘 짜는 사람이 됩니다.
우선 context라는 파라미터가 뭔지 알아봅시다.
1. context는 쉽게 비유하자면 족보입니다.
class 위젯명 extends StatelessWidget {
@override
build (context) {
어쩌구 생략
▲ 커스텀 위젯 만들 때 보면 build() 함수를 쓰도록 되어있습니다.
근데 build() 함수안에 첫 파라미터 넣으시면 그건 무조건 현재 위젯의 부모들이 누군지 담겨있습니다.
그냥 쉽게 비유하자면 족보입니다.
context도 내 아빠 위젯, 할배 위젯, 증조할배 위젯이 누구인가 알려주는 족보입니다.
(주의) 형제, 자식 정보는 없고 무조건 조상 위젯이 누군지만 들어있는 족보입니다.
족보를 간지나는 영어로 context라고 합니다.
그래서 build(context) 이렇게 파라미터를 작명하는데
그냥 build(jokbo)로 작명하는게 어떨까요 이해쉽게
2. 족보 퀴즈
예를 들어서 이런 레이아웃을 만들었다고 칩시다.
코드로 표현하자면 이렇겠군요
class MyApp extends StatelessWidget {
(생략)
build (context) {
return MaterialApp(
home : Scaffold(
body : 커스텀위젯()
)
);
}
}
class 커스텀위젯 extends StatelessWidget {
(생략)
build (context) {
return Text('안녕');
}
}
근데 여기서 커스텀위젯 안에 build(context) 라는거 보이시죠?
커스텀위젯의 모든 조상들의 정보를 담고있으니
MaterialApp
Scaffold
이런 것들이 담겨있습니다.
MyApp 위젯의 모든 조상들에 대한 정보를 담고 있는 변수입니다.
이런 부모가 없군요
그래서 암것도 든게 없음
3. Flutter에는 특별한 함수들이 몇개 있습니다.
showDialog()
Navigator()
Theme.of()
Scaffold.of()
이런 함수들은 context를 (족보를) 소괄호 안에 집어넣어야 잘 작동하는 함수입니다.
4. 이 중에 showDialog() 함수는
족보를 넣는데 족보 중에 MaterialApp이 들어있어야 제대로 작동합니다.
showDialog( context : MaterialApp이부모로들어있는족보 )
이렇게 써야합니다.
그게 싫으면 플러터 만든사람에게 따져야합니다.
그럼 showDialog() 이렇게 쓰면 잘 동작할까요?
build (context) {
return MaterialApp(
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: (){
showDialog(
context: context,
builder: (context){ return Dialog( child: Text('안녕'), ); },
);
},
),
지금 context라는 파라미터는 위에 build(context) 여기서 만들어졌는데
이 context는 MaterialApp()의 부모와 조상에 대한 정보를 담고 있을겁니다.
MaterialApp()의 부모 위젯이 누구죠?
없는데요 부모가 없군요
그래서 이 context는 showDialog() 안에 넣으면 작동안하는 것입니다.
5. 그럼 어떻게 하면 에러를 해결할 수 있을까요
당연히 MaterialApp이 부모로 들어있는 context를 하나 만들어주면 됩니다.
해결책 1은 MaterialApp을 바깥으로, 그니까 부모로 보내버리면
자연스럽게 아까 그 context에 MaterialApp이 부모로 기록되겠죠?
그럼 문제 해결입니다.
6. 해결책 2는 족보를 하나 만드십시오
Build() 이런 특별한 위젯이 있는데
그거쓰면 족보를 중간에 생성해줍니다.
build (context) {
return MaterialApp(
home: Scaffold(
floatingActionButton: Builder(
builder: (jokbo1) {
return FloatingActionButton(
onPressed: (){
showDialog( context: jokbo1,
builder: (context){ return Dialog( child: Text('AlertDialog Title'), ); },
);
},
);
}
),
저러면 context가 중간에 하나 생성됩니다. 저는 jokbo1 이라고 이름지었습니다.
그럼 jokbo1은 Scaffold, MaterialApp이 들어있는 족보가 되기 때문에 아까의 문제 해결입니다.
이런건 직접 짜는게 아니라
원하는 위젯 하나에 커서찍고 왼쪽 전구누르시면 Builder로 감싸기 그런거 쉽게 됩니다.
해결책 2는 치우고 해결책 1 쓰십시오
Builder() 이건 복잡해지니 귀찮습니다. 응급상황에 쓰셈
다시 쉽게 정리 하자면 context 즉
저 빌드 하는 부분에 context를 사용 하는거라 저기에 MaterialApp 있어야함 하지만 지금
내부에 MaterialApp 이 있으니까 저 context에는 아무 것도 없어서 오류가 나는 것임
+ 추가적으로 모달창 없애는 코드
class DialogUI extends StatelessWidget {
DialogUI({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Dialog(
child: Container(
width: 300,
height: 300,
child: Column(
children: [
TextField(),
TextButton( child: Text('완료'), onPressed:(){} ),
TextButton(
child: Text('취소'),
onPressed:(){ Navigator.pop(context); })
],
),
),
);
}
}
취소버튼 누를 때 모달창이 꺼지는 것은
Navigator.pop(context);
이런 코드 실행하면 모달창 없어집니다.
Navigator.pop() 이건 실은 페이지 나눌 때 "현재 페이지 닫기~" 이런 기능을 해주는 코드입니다.
Navigator.pop() 안에는 context 넣어야하는데 아마 MaterialApp 아니면 Scaffold 이게 있는 context 넣으면 될겁니다.
'APP > Flutter' 카테고리의 다른 글
플러터 자식 위젯이 부모 위젯의 state를 변경하고 싶으면 4-step (0) | 2022.08.07 |
---|---|
플러터 state를 자식 위젯에서 쓰고 싶다면 3 step 이용 (0) | 2022.08.07 |
플러터 재렌더링이란?, state란? , StatefulWidget (0) | 2022.08.05 |
플러터 스크롤바 만들어주는 ListView 위젯 (0) | 2022.08.05 |
코드가 길어지면 커스텀 위젯만들기 (0) | 2022.08.05 |