방명록
- [Flutter] "Do it! 플러터 앱 프로그래밍" - 내비게이션 활용하기 | 내비게이션 이해하기, 할 일을 기록하는 앱 만들기2022년 02월 15일 01시 07분 28초에 업로드 된 글입니다.작성자: DandyNow728x90반응형
"조준수. (2021). Do it! 플러터 앱 프로그래밍. 이지스퍼블리싱", 8장을 실습하였다. 내비게이터와 라우트를 이용한 페이지 이동을 실습한 후 할 일 기록하는 앱을 만들어 보았다. 완성된 앱을 테스트하던 중 발생한 에러에 대해 예외 처리를 추가로 해주었다.
내비게이션 이해하기
페이지 이동하기
Navigitor는 스택을 이용해 페이지를 관리하는 클래스이다. 페이지의 이동은 push와 pop으로 이루어진다.
// main.dart import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'SubPage Example', theme: ThemeData( primarySwatch: Colors.blue, ), home: FirstPage(), ); } } class FirstPage extends StatefulWidget { @override State<StatefulWidget> createState() => _FirstPage(); } class _FirstPage extends State<FirstPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Sub Page Main'), ), body: Container( child: Center( child: Text('첫 번째 페이지'), ), ), floatingActionButton: FloatingActionButton( onPressed: () { // Navigator는 스택을 이용해 페이지를 관리할 때 사용하는 클래스. of 함수는 현재 페이지를 나타내고, push 함수는 스택에 페이지를 쌓는 역할을 한다. Navigator.of(context) // MaterialPageRoute 스타일로 페이지를 이동하게 한다. .push(MaterialPageRoute( builder: (context) => SecondPage())); // SecondPage를 쌓는다. }, child: Icon(Icons.add), ), ); } } class SecondPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Second Page'), ), body: Container( child: Center( child: ElevatedButton( onPressed: () { // 이 페이지가 보인다는 것은 현재 스택 메모리 맨 위에 있다는 의미이다. Navigator.of(context).pop(); // 현재 페이지 pop하여 종료 }, child: Text('돌아가기'), ), ), ), ); } }
라우트로 페이지 이동하기
라우트는 경로를 의미하는 용어이다. 이 기능을 이용하면 페이지 이동 기능을 더 편하게 구현할 수 있다.
// main.dart import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'SubPage Example', theme: ThemeData( primarySwatch: Colors.blue, ), // home: FirstPage(), // 라이트 설정 initialRoute: '/', // 앱을 처음 시작했을 때 보여 줄 경로 routes: { '/': (context) => FirstPage(), '/second': (context) => SecondPage() }, ); } } class FirstPage extends StatefulWidget { @override State<StatefulWidget> createState() => _FirstPage(); } class _FirstPage extends State<FirstPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Sub Page Main'), ), body: Container( child: Center( child: Text('첫 번째 페이지'), ), ), floatingActionButton: FloatingActionButton( onPressed: () { // Navigator는 스택을 이용해 페이지를 관리할 때 사용하는 클래스. of 함수는 현재 페이지를 나타내고, push 함수는 스택에 페이지를 쌓는 역할을 한다. Navigator.of(context).pushNamed('/second'); // 라우터 연결 // MaterialPageRoute 스타일로 페이지를 이동하게 한다. // .push(MaterialPageRoute( // builder: (context) => SecondPage())); // SecondPage를 쌓는다. }, child: Icon(Icons.add), ), ); } } class SecondPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Second Page'), ), body: Container( child: Center( child: ElevatedButton( onPressed: () { // 이 페이지가 보인다는 것은 현재 스택 메모리 맨 위에 있다는 의미이다. Navigator.of(context).pop(); // 현재 페이지 pop하여 종료 }, child: Text('돌아가기'), ), ), ), ); } }
할 일을 기록하는 앱 만들기
페이지 이동하기
세 개의 페이지를 이동하는 기능을 실습했다.
// main.dart import 'package:flutter/material.dart'; import 'subDetail.dart'; import 'secondDetail.dart'; import 'thirdPage.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { static const String _title = 'Widget Example'; @override Widget build(BuildContext context) { return MaterialApp( title: _title, initialRoute: '/', // 경로 설정 routes: { '/': (context) => SubDetail(), '/second': (context) => SecondDetail(), '/third': (context) => ThirdDetail(), }, ); } }
// subDetail.dart import 'package:flutter/material.dart'; class SubDetail extends StatefulWidget { @override State<StatefulWidget> createState() => _SubDetail(); } class _SubDetail extends State<SubDetail> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Sub Detail Example'), ), body: Container( child: Center( child: ElevatedButton( onPressed: () { // Navigator.of(context).pushReplacementNamed('/second'); // pushReplacementNamed 함수는 스택에 자료를 추가하지 않고 기존 자료를 교체한다. Navigator.of(context) .pushNamed('/second'); // pushNamed 함수는 새로운 자료를 추가한다. }, child: Text('두 번째 페이지로 이동하기'), ), ), ), ); } }
// secondDetail.dart import 'package:flutter/material.dart'; class SecondDetail extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Second Page'), ), body: Container( child: Center( child: ElevatedButton( onPressed: () { Navigator.of(context) .pushReplacementNamed('/third'); // pushReplacementNamed 함수를 호출해 이 페이지를 세 번째 페이지로 교체 }, child: Text('세 번째 페이지로 돌아가기'), ), ), ), ); } }
// thirdPage.dart import 'package:flutter/material.dart'; class ThirdDetail extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Third Page'), ), body: Container( child: Center( child: ElevatedButton( onPressed: () { Navigator.of(context).pop(); }, child: Text('첫 번째 페이지로 이동하기'), ), ), ), ); } }
할 일 보기 기능 만들기
페이지에 데이터를 전달하는 방법을 실습했다.
// subDetail.dart import 'package:flutter/material.dart'; class SubDetail extends StatefulWidget { @override State<StatefulWidget> createState() => _SubDetail(); } class _SubDetail extends State<SubDetail> { List<String> todoList = new List.empty(growable: true); @override void initState() { super.initState(); todoList.add('플러터 공부'); todoList.add('자바스크립트 공부'); todoList.add('플러터 토이 프로젝트'); todoList.add('자바스크립트 토이 프로젝트'); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Sub Detail Example'), ), body: ListView.builder( itemBuilder: (context, index) { return Card( // InkWell 위젯은 탭, 더블탭, 롱탭 등 다양한 이벤트 처리를 할 수 있다. child: InkWell( child: Text( todoList[index], style: TextStyle(fontSize: 30), ), onTap: () { Navigator.of(context).pushNamed('/third', arguments: todoList[ index]); // 첫 번째 인자로 지정한 경로로 두 번째 인자로 지정한 데이터를 전달한다 }, ), ); }, itemCount: todoList.length, ), floatingActionButton: FloatingActionButton( onPressed: () {}, child: Icon(Icons.add), ), ); } }
// thirdPage.dart import 'package:flutter/material.dart'; class ThirdDetail extends StatelessWidget { @override Widget build(BuildContext context) { // 라우터로 전달받은 데이터인 arguments 값이 어떤 자료형인지 알 수 없으므로 String으로 형변환한 다음 args에 넣는다. final String args = ModalRoute.of(context)!.settings.arguments.toString(); return Scaffold( appBar: AppBar( title: Text('Third Page'), ), body: Container( child: Center( child: Text( args, style: TextStyle(fontSize: 30), ), ), ), ); } }
할 일 추가 기능 만들기
할 일 추가 기능을 적용한 후 테스트하던 중 Second Page의 텍스트 필드에 입력 값이 없는 상태에서 뒤로 가기 버튼을 터치하니 [그림 5]와 같은 에러가 발생했다. 그래서 try catch문으로 예외처리를 해주었다.
// subDetail.dart import 'package:flutter/material.dart'; class SubDetail extends StatefulWidget { @override State<StatefulWidget> createState() => _SubDetail(); } class _SubDetail extends State<SubDetail> { List<String> todoList = new List.empty(growable: true); @override void initState() { super.initState(); todoList.add('플러터 공부'); todoList.add('자바스크립트 공부'); todoList.add('플러터 토이 프로젝트'); todoList.add('자바스크립트 토이 프로젝트'); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Sub Detail Example'), ), body: ListView.builder( itemBuilder: (context, index) { return Card( // InkWell 위젯은 탭, 더블탭, 롱탭 등 다양한 이벤트 처리를 할 수 있다. child: InkWell( child: Text( todoList[index], style: TextStyle(fontSize: 30), ), onTap: () { Navigator.of(context).pushNamed('/third', arguments: todoList[ index]); // 첫 번째 인자로 지정한 경로로 두 번째 인자로 지정한 데이터를 전달한다 }, ), ); }, itemCount: todoList.length, ), floatingActionButton: FloatingActionButton( onPressed: () { _addNavigation(context); // 할 일 추가 기능 함수 호출 }, child: Icon(Icons.add), ), ); } // 할 일 추가 기능 만들기 void _addNavigation(BuildContext context) async { final result = await Navigator.of(context).pushNamed('/second'); setState(() { try { // result를 String 형변환하여 todoList에 add. todoList.add(result as String); } catch (e) {} // 할 일 추가하지 않고 뒤로 가기 처리. try catch 없으면 뒤로 가기 버튼 터치 시 [그림 5]와 같은 에러 발생 }); } }
// secondDetail.dart import 'package:flutter/material.dart'; class SecondDetail extends StatelessWidget { @override Widget build(BuildContext context) { TextEditingController controller = new TextEditingController(); // 할 일을 입력할 TextField용 변수 return Scaffold( appBar: AppBar( title: Text('Second Page'), ), body: Container( child: Column( children: <Widget>[ TextField( controller: controller, keyboardType: TextInputType.text, ), // TextField에 할 일을 입력하고 저장하기 버튼을 누르면 데이터를 전달한 후 현재 화면을 종료한다. ElevatedButton( onPressed: () { Navigator.of(context).pop(controller.value.text); }, child: Text('저장하기'), ), ], ), ), ); } }
728x90반응형'언어·프레임워크 > Flutter' 카테고리의 다른 글
다음글이 없습니다.이전글이 없습니다.댓글