아직 2편을 안 봤다면? 보러가기👀
반갑습니다 여러분! 코딩백조입니다🦢
오늘 드디어 화면 왔다갔다를 구현할 예정입니다!!
거의 다 왔어요 😉 화이팅!
📍[ 3 / 3 ] 메인 페이지의 버튼 누르면 두 번째 페이지로 이동하기
. . . 두 번째 페이지의 뒤로가기 버튼 누르면 메인 페이지로 이동하기
지난 시간에 Navigator이 페이지를 관리한다는 것까지 말씀드렸어요.
어떻게 관리하냐면요..
바로 Stack 이라는 것을 통해서 입니다!
그래서 Stack이 뭔데? 😡
Stack 은 한국어로 "쌓다" 라는 뜻이 있는데요, 그릇 쌓인거 생각하시면 됩니다.ㅋㅋ
접시를 정리할 때 보통 위로 위로 쌓다가 쓸 땐 또 위에서부터 꺼내 쓰잖아요,
우리에게 보이는 페이지도 그렇게 움직인다는 사실!! 🤩
파란색 통 안에 첫 번째 페이지인 Screen 1 이 있네요.
사용자는 맨 위만 볼 수 있으니 첫 화면을 볼거에요.
이제 버튼을 눌러볼까요?
푸시!! Push 라는 함수를 통해 네비가 Screen 2를 통에 넣어줍니다!
사용자는 맨 위만 볼 수 있기 때문에 이젠 Screen 2만 보이겠죠?
만약 사용자가 뒤로가기를 누른다면?
팝!! Pop 이라는 함수를 통해 네비가 Screen 2를 구멍에서 뺍니다.
그러면 이젠 구멍에 Screen 1 만 있으니까 다시 첫 번째 화면이 보이겠죠!
이런 식으로 Navigator 가 Route 들을 관리한답니다 😎 신기하지 않나요?
우리도 구현하러 가야죠!!
ElevatedButton 을 눌렀을 때 화면을 이동하고 싶은거니까
onPressed 함수에 코드를 작성해볼게요!
아직은 (){} 의 빈 함수지만, 이제 넣어볼게요.
중괄호 내부에다 작성 시작입니다!!
아까 말했듯, 새로운 화면을 넣는 함수는?
Push 💨 해줍니다!
Navigator.push 를 입력해볼까요?
이 두개는 Navigator.push 의 필수 요소입니다. 역시 알아봐야겠죠?
앞으로 정말정말 많이 볼 친구입니다.
지금은 중요한게 아니니, 간단하게는 "주소" 정도라고 해둡시다! 위젯이 여러개가 있는데 그 중 내 위치가 어딘지를 저장해주는 변수입니다.ㅎㅎ
어! 우리가 아는 단어에요!
맞아요, 바로 페이지를 의미합니다. 🏞 어느 페이지를 보여줄거야? 라고 묻는거죠.
여기서 나올 코드는 좀 복잡해서 일단은 따라 써봅시다!
route를 지우고 그 자리에 MaterialPageRoute
를 입력해주세요!
builder
부분에 이제 우리의 페이지를 넣어주면 되는데요, 좀 특이한 형태로 넣어줄 겁니다.
builder: (_) {
return PhotoScreen();
}
아니면
builder: (_) => PhotoScreen()
둘 중 하나를 골라 입력해줍시다!
저 언더바는 뭐고 갑자기 화살표는 뭐고.. 궁금한게 많으시죠?
저도 처음 플러터 배울 때 아무도 설명을 안해줘서 답답했었는데요,
매개변수를 필요로 하는 함수에서
🤨 "근데 나 매개변수 안쓸건데?"
라는 의미로 쓰입니다.
사실 저 builder: 은 context 라는 변수를 매개변수로 받거든요.
builder: (context) {
return PhotoScreen();
}
원래는 이렇게 써야 완벽한 형태가 되는거죠!
근데, 우리는 context 라는 변수 받아봤자.. { 중괄호 } 안에서 안쓰잖아요. 그래서 쓸데없다고 알려주는 표시랍니다.
물론 나중에 context를 써야 하면 꼭 붙여야겠죠!
갑자기 화살표?! 당황하셨을 수도 있는데요,
arrow function, 화살표 함수라는 것도 있습니다.
플러터의 언어인 Dart 에서는 한줄짜리 리턴문을 => 로 대체해서 사용할 수 있어요! 🤭
처음엔 구조가 잘 안보여서 중괄호를 선호했는데.. 이젠 이게 더 편하더라구요 😮
위에 (_) 를 쓰는 이유를 알았으면, 이제 => 로 바꿔볼게요!
builder: (context) => PhotoScreen()
훨씬 깔끔하죠?ㅎㅎ
휴, 엄청 많은 내용이 지나갔어요 😮💨
이제 코드가 거의 다 된거같은데요?
여러분의 버튼 코드가 이렇게 생겼나요?ㅎㅎ
그렇다면 바로 실행해봅시다!!
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => PhotoScreen()),
);
},
child: const Text("cat photo"),
),
안드로이드 스튜디오에서는 에뮬레이터라고 하는 기능이 있어요.
가상 핸드폰을 만들 수 있는거죠!
여기서 자신이 사용하는 폰을 선택해주고,
화면 오른쪽에 핸드폰이 나타나면 저 오른쪽 위에 초록색 삼각형을 눌러 Run ▶️ 해줍니다!
시간이 얼마나 오래 걸리는지는 여러분 컴퓨터의 성능에 따라..😣
전 지금 맥을 써서 10초도 안걸리는데 예전에 3년된 삼성 노트북으로 돌리니까 5분이 넘게 걸리더라구요.....🤬 진짜 화나지만 인내의 시간을 가져봅니다..
..
성공! 이 되어야 됩니다. 호옥시 빌드 실패했다면 에러 코드를 댓글로 남겨주세요!
어떤가요? 앱이 보이나요? 페이지가 잘 넘어가나요?!
아니죠!!! 이상한 에러가 뜹니다!!
혹시 자세한 이유와 자세한 해결방법이 궁금하시다면 여기서 확인해주세요! 👀
이 글에서는 간단하게 해결 방법만 얻고 넘어가겠습니다!!
나중에 앱 다 만들면 한 번 보시는걸 추천해요 😜
해결은 엄청 쉬워요.
main.dart 파일로 넘어가서,
5번째 줄 runApp(const MyApp());
부분을 수정해줄겁니다!
이거 하나만 추가해주면 돼요.
MyApp을 MaterialApp로 감쌀겁니다!
이렇게 입력해주세요.
다시 Run 해볼까요?
두근두근하는 마음으로 버튼을 누르면..
성공!! 전 잘 넘어가네요 🥳 귀여운 고양이가 보입니다!
아직 끝나지 않았어요!!
메인 화면에서 고양이 화면으로 넘어가긴 했는데.. 다시 돌아올 방법이 없어요 😢
그러나! 우린 아까 Navigator 의 존재를 배웠으니 할 수 있어요!!
화면 맨 위에 <- 이렇게 생긴 화살표로 돌아가면 좋을 거 같아요. 이건 얼마 안걸리니까 바로 해봅시다!
파란색 배너 부분을 우리는 AppBar 이라고 부릅니다.
이 AppBar을 자세히 뜯어보면,
여러 속성이 있어요. 우리가 쓰는 title 도 보이네요!
자, 암기입니다. 제목 왼쪽의 공간은 바로
입니다!!
보통은 뒤로가기나, 햄버거 메뉴🍔를 놓는 곳이죠.
여기에 뒤로가기 아이콘을 사용한 버튼을 주고, 사용자가 버튼을 눌렀을 때 현재 페이지를 Stack 에서 빼내면 되겠죠?
바로 들어갑니다!!
photo_screen.dart 에 들어가서 편집 해봐요!
PhotoScreen 위젯의 AppBar 내부에 작성해줄거에요.
title: ~~, 다음에 leading 을 입력해줍니다.
그리고 아이콘 버튼을 넘겨줄 겁니다!
따라치면서 대충 이런게 있군~ 하시면 됩니다. 😜
Elevated Button 이랑 비슷하죠?
child:
대신 icon:
으로 바뀌었을 뿐입니다!
icon에는 icon: Icon(Icons.arrow_back)
라고 Icon() 위젯을 넣어줍니다!
Icons.arrow_back 이라는 모양을 Icon() 위젯에 넘겨준 형태라고 생각하면 됩니다.
이제 onPressed 차례!
지금 우리의 Stack 에는 MyApp 위에 PhotoScreen 이 놓아져 있는 형태일거에요.
다시 MyApp을 보여주려면 어떻게 해야 할까요?
맞아요, 바로 POP! 해줘야 합니다! 😉
이렇게 입력해주세요.
onPressed: (){}
아까처럼 빈 함수를 만들고, 중괄호 부분에 Navigator.pop 을 입력해줍니다.
세미콜론 조심! 👀 이렇게 (){ "여기" } 함수 내부에서는 모든 문장이 ; 로 끝난답니다!
다시 Run▶️ 을 눌러볼까요?
앱이 다시 실행되면 cat photo 버튼을 눌러봅시다!
오! 성공적으로 버튼이 생겼어요!!
뒤로가기 버튼을 누르면 이제 다시 메인 화면으로 가는 것을 볼 수 있습니다. 🤩 🥳
다들 성공하셨나요? 😎
첫 번째 앱 만들기, 끝입니다! 🥳
모두 수고하셨어요 🥰
그럼, 다음에 만나요!
main.dart
import 'package:flutter/material.dart';
import 'package:navigator_example/photo_screen.dart';
void main() {
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text("고양이 사진 보여줘!"),
),
body: Center(
child: Column(
children: [
const SizedBox(
height: 100,
),
const Text("press here to see cat photo"),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const PhotoScreen(),
),
);
},
child: const Text("cat photo"),
),
],
),
),
),
);
}
}
photo_screen.dart
import 'package:flutter/material.dart';
class PhotoScreen extends StatelessWidget {
const PhotoScreen({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text("cat photo"),
leading: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(Icons.arrow_back)),
),
body: const Center(
child: Image(
image: NetworkImage(
"https://images.pexels.com/photos/416160/pexels-photo-416160.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2"),
),
),
),
);
}
}