Flutter

[Flutter] 상세페이지 만들기 (Navigator, Routes)

hminor 2023. 8. 10. 16:19

상세페이지 만들기 (Navigator)

  • 버튼 클릭 시 사진을 업로드 할 수 있는 페이지 만들기
    • 현재는 Tab을 활용해서 보여지는 페이지를 다르게 했는데
    • 이번에는 Navigator를 사용해서 보여주는 방법을 배우기!
  • Naviagor는 기존 페이지에 새로운 페이지를 덮어씌워서 페이지를 보여주게 한다.
    • 웹과 다르게 모바일에서는 새로운 페이지를 열 때 기존 페이지에 새로운 페이지를 덮어씌우게 된다.
    • 예시로 카카오톡에서 새로운 링크를 클릭 시 새로운 페이지가 기존 페이지를 덮어씌우는 것과 같다.
  • 그래서 기존 Tab과의 차이점으로는 Stack으로 관리하기에 뒤로가기 버튼이 잘 작동하게 된다.
  • 현재 AppBar에 만들어 뒀던 add_box_outlined 아이콘을 클릭 시 작동하기 위해 onPressed 메서드 안에 코드를 작성하기
    • Navigator.push(context, route)를 작성하는데
    • 이때 주의점으로 context에는 MaterialApp이 들어있는 context를 넣어줘야하기에 확인을 꼭 잘 해줘야 한다.
    • 그리고 route에는 MaterialPageRoute() 위젯을 넣고
      • 해당 위젯의 값으로는 builder: ( ){ } 을 추가하며 인자 값을 하나 넣어줘야한다. 이때 builder로 context를 만들어주기에 필요하면 context를 기입하고 아니면 그냥 c를 넣어주면 된다.
    @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
              title: Text('Instagram'),
              actions: [
                IconButton(
                  onPressed: (){
                    Navigator.push(context,
                      MaterialPageRoute(builder: (c){
                        return Text('새로운 페이지');
                      })
                    );
                  },
                  icon: Icon(Icons.add_box_outlined)
                )
              ],
            ),
    
    • 여기서 Arrow Function을 사용하는 방법을 짚고 넘어가자면
      • return 문이 하나만 있을 경우에 사용하는 것으로 아래와 같이 변경할 수 있다.
      // 변경전
      onPressed: (){Navigator.push(context,
      	              MaterialPageRoute(builder: (c){
      	                return Text('새로운 페이지');
      	              })
      	            );
      	          },
      
      // 변경후
      onPressed: (){Navigator.push(context,
                      MaterialPageRoute(builder: (c) => Text('새로운 페이지')
                      )
                    );
                  },
      
  • 이제 버튼을 클릭 시 다른 페이지로 이동하고 해당 페이지에서 닫기 버튼을 클릭 시 창을 닫도록 하는 코드 작성하기
    • 한번 더 정리하자면 페이지 열게 하는 건
      • Navigator.push()
    • 페이지 닫게 하는 건
      • Navigator.pop()
import 'dart:js_interop';

import 'package:flutter/material.dart';
import './style.dart' as style;
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter/rendering.dart';

void main() {
  runApp(
    MaterialApp(
      theme: style.theme,
      home: MyApp()
    )
  );
}

class MyApp extends StatefulWidget {
  MyApp({super.key});
  
  @override
  State createState() => _MyAppState();
}

class _MyAppState extends State {

  var homeData = [];

  appendData(value){
    setState(() {
      homeData.add(value);
    });
  }
  
  getData() async{
    var result = await http.get(Uri.parse('<https://codingapple1.github.io/app/data.json>'));
    if (result.statusCode == 200) {
      setState(() {
        homeData = jsonDecode(result.body);
      });
    } else {
      print('실패');
    }
  }

  @override
  void initState() {
    super.initState();
    getData();
  }

  // 0: home, 1: shop
  var tab = 0;

  changeTab(tabNumber){
    setState(() {
      tab = tabNumber;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Instagram'),
          actions: [
            IconButton(
              onPressed: (){
                Navigator.push(context,
                  MaterialPageRoute(builder: (c) => Upload()
                  )
                );
              },
              icon: Icon(Icons.add_box_outlined)
            )
          ],
        ),      
    );
  }
}

// Upload
class Upload extends StatelessWidget {
  const Upload({Key? key}) : super(key: key);
  @override

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('이미지업로드화면'),
            IconButton(
                onPressed: (){
                  Navigator.pop(context); 
                },
                icon: Icon(Icons.close)
            ),
          ],
        )
    );

  }
}
  • 그리고 현재는 Tap으로 페이지를 보여주고 했는데 페이지가 너무 많다면 routes를 사용하면 된다.
    • 이렇게 작성하게 되면 React에서 했던 Routing 기능을 적용할 수 있다.
    • 기본 경로를 initialRoute로 기본 경로를 설정 하고 routes로 경로 별 return 할 요소를 전달하기
    void main() {
      runApp(
        MaterialApp(
          theme: style.theme,
          initialRoute: '/',
          routes: {
            '/': (c) => MyApp(),
            '/mypage': (c) => Text('마이 페이지')
          },
        )
      );
    }