Nick Dev

[Flutter] 05. 페이지 → 페이지 이동하기 본문

Flutter

[Flutter] 05. 페이지 → 페이지 이동하기

Nick99 2023. 7. 25. 18:28
반응형

목차

1. bottomNavigationBar

2. Navigator

3. go_router


1. bottomNavigationBar ( 페이지 간의 이동은 아님 )

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(
    home: HomeWidget(),
  ));
}

class HomeWidget extends StatefulWidget {
  const HomeWidget({super.key});

  @override
  State<HomeWidget> createState() => _HomeWidgetState();
}

class _HomeWidgetState extends State<HomeWidget> {
  late int index;

  @override
  void initState() {
    super.initState();
    index = 1;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('page moveing 1'),
      ),
      body: homeBody(),
      bottomNavigationBar: BottomNavigationBar(
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
          BottomNavigationBarItem(icon: Icon(Icons.person_2), label: 'User'),
        ],
        currentIndex: index,
        onTap: (newIndex) => setState(() => index = newIndex),
      ),
    );
  }

  Widget homeBody() {
    switch (index) {
      case 1:
        return const Center(
          child: Icon(
            Icons.home,
            size: 150,
          ),
        );
      case 2:
        return const Center(
          child: Icon(
            Icons.person_2,
            size: 150,
          ),
        );
      case 0:
      default:
        return const Center(
          child: Icon(
            Icons.search,
            size: 150,
          ),
        );
    }
  }
}

bottomNavigator

  • Scaffold의 bottomNavigationBar 활용
  • 우선 하단 네비게이션 바 클릭할 때마다 상태가 변경되므로 StatefulWidget으로 선언
  • BottomNavigationBar()를 통해 해당 Widget을 생성, 주요 매개변수 3개
    • items: [ ]
      • BottomNavigationBar에 표시될 아이템들의 배열을 정의
      • BottomNavigationBarItem
        • 아이콘과 라벨을 가진 객체를 생성
        • icon: Icon(Icons.xxx) 를 활용해 Bar에 표시될 아이콘을 선택
        • label: Icon 밑에 표시될 글자 
      • BarItem()은 위에서부터 정의한 순서대로 Bar에 좌 → 우로 표시됨
      • 각 BarItem()의 인덱스도 위에서부터 차례대로 0부터 부여
        • Search의 index = 0
        • Home의 index = 1
        • User의 index = 2
    • currentIndex:
      • 현재 선택된 아이템의 인덱스를 설정 
    • onTap: ( newIndex ) => setState( () => index = newIndex )
      • onTap : BarItem()이 클릭될 때 수행될 액션을 정의
      • setState : 해당 item의 인덱스(newIndex)가 index에 저장하고 UI를 업데이트
  • Scaffold의 body
    • HomeWidget 안에서 따로 Widget으로 선언해준다
    •  homeBody Widget
      • 현재 선택된 하단 네비게이션 바에 따라 다른 위젯을 반환하도록 만듦
      • 선택된 BarItem의 index에 따라 해당하는 Icon을 띄워준다

2. Navigator

// main.dart
import 'package:example/screen/new_page.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(
    home: HomeWidget(),
  ));
}

class HomeWidget extends StatelessWidget {
  const HomeWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('flutter 페이지 이동 2'),
      ),
      body: Center(
        child: TextButton(
          child: Text('Go to page'),
          onPressed: () {
            Navigator.push(context, MaterialPageRoute(builder: (context) => NewPage()),);
          },
        ),
      ),
    );
  }
}
// new_page.dart
import 'package:flutter/material.dart';

class NewPage extends StatelessWidget {
  const NewPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('NewPage'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          children: [
            TextButton(onPressed: () => Navigator.pop(context), child: Text('Go to Back'),),
            TextButton(onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => NewPage2())), child: Text('Go to NewPage2'),),
          ],
        ),
      ),
    );
  }
}

class NewPage2 extends StatelessWidget {
  const NewPage2({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('NewPage2'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          children: [
            TextButton(onPressed: () => Navigator.pop(context), child: Text('Go to Back'),),
            TextButton(onPressed: () => Navigator.popUntil(context, (route) => route.isFirst), child: Text('Go to Home'),),
          ],
        ),
      ),
    );
  }
}
  • 총 3 page로 구성
    • home page
    • NewPage
    • NewPage2
  • 모두 TextButton의 onPressed 활용해 페이지 간 이동
  • home page
    • Navigator.push(context, MaterialPageRoute(builder: (context) => NewPage()),);
      • Navigator Widget을 활용해 'NewPage'로 이동하는 코드
      • Navigator.push
        • push 메서드는 Navigator 스택에 새로운 경로(Route)를 추가
        • 이 메서드가 호출되면, 현재 화면 위에 새로운 화면이 표시
      • context : 현재 Widget Tree의 위치를 나타내는 BuildContext 객체
      • MaterialPageRoute(builder: (context) => NewPage()),);
        • 새로 표시할 화면을 생성하는 Route를 생성 
        • NewPage() 는 새로 표시할 화면의 위젯
    • 'Go to page' 를 클릭하면 'NewPage'로 이동
  • NewPage() Widget
    • 2개의 버튼을 통해 이전 페이지로 돌아가거나 라우팅된 페이지로 넘어가기
    • Navigator.pop(context)
      • '뒤로 가기' 기능
      • context는 WidgetTree에서 현재 위치를 나타내는 객체임
      • .pop(context)
        • 현재 화면 위에 표시된 화면(즉, 스택의 맨 위에 있는 화면)이 제거 → 그 아래 있던 화면이 다시 보임
      • 즉, 해당 버튼이 눌리면 현재 화면이 닫히고 이전 화면으로 돌아가게 된다
    • Navigator.push( ... )
      • 현재 page에서 새로운 페이지 'NewPage2'로 이동하는 코드
      • 이 버튼 누르면 'NewPage2'로 이동
  • NewPage2() Widget
    • Navigator.pop( context )로 ' 뒤로 가기 ' 구현
    • Naviagtor.popUntil (context, (route) => route.isFirst)
      • '홈으로 돌아가기' 
      • home 화면 위에 있는 화면들이 home 화면 나올 때까지 순서대로 제거된다
      • 즉, 이 버튼을 누르면 앱의 첫 번째 화면으로 돌아가게 된다

3. go_router (외부 라이브러리 활용)

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:part2/screen/new_page.dart';

const assetImagePath = 'assets/images';
const myFaceImage = '$assetImagePath/myFace.jpg';

void main() {
  runApp(
    MaterialApp.router(
      routerConfig: GoRouter(initialLocation: '/', routes: [
        GoRoute(
          path: '/',
          name: 'home',
          builder: (context, _) => const HomeWidget(),
        ),
        GoRoute(
          path: '/new',
          name: 'new1',
          builder: (context, _) => const NewPage(),
          // route 안에 route를 만들 수 있다 -> app의 path를 효과적으로 만들 수 있다
          routes: [

          ]
        ),
        GoRoute(
          path: '/new1',
          name: 'new2',
          builder: (context, _) => const NewPage2(),
        ),
      ]),
    ),
  );
}

class HomeWidget extends StatelessWidget {
  const HomeWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter에서 화면 이동하기 3'),
        centerTitle: true,
      ),
      body: Center(
        child: TextButton(
          child: Text('Go to Page'),
          onPressed: () {
            context.pushNamed('new1');
          },
        ),
      ),
    );
  }
}

// new_page.dart
class NewPage extends StatelessWidget {
  const NewPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Welcome New Page'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextButton(
              child: const Text('Go to Back'),
              onPressed: () => context.pop(),
            ),
            TextButton(
              child: const Text('Go to New Page2'),
              onPressed: () => context.pushNamed('new2'),
            ),
          ],
        ),
      ),
    );
  }
}

class NewPage2 extends StatelessWidget {
  const NewPage2({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Welcome to New Page 2'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          children: [
            TextButton(
              onPressed: () => context.pop(),
              child: const Text('Go to Back'),
            ),
            TextButton(
              onPressed: () => context.goNamed('home'),
              child: const Text('Go to Home'),
            ),
          ],
        ),
      ),
    );
  }
}
  • pub.dev에서 가져온 외부 라이브러리 활용
    • 매우 많이 사용되는 외부 라이브러리라고 함
  • 총 3 page로 구성
    • HomeWidget()
    • NewPage()
    • NewPage2()
  • Navigator 보다 훨씬 단순하고 편함
    • Routing 할 때 'name'을 통해서 보기쉽게 표현 가능
  • MaterialApp.router
    • MaterialApp Widget에 .router 메서드를 사용해 사용자 정의 라우터를 설정
    • routerConfig
      • GoRouter( ... ) 객체를 생성
      • initialLocation: '/' 
        • 앱이 처음 시작될 때 표시되는 경로를 설정
    • GoRouter
      •  routes : GoRoute 객체들의 리스트, 각 페이지에 대한 경로를 정의
      • GoRoute : 해당 페이지에 대한 경로 정의 
        • path : GoRoute의 경로를 정의
          • '/' → home page 를 의미
        • name : 해당 GoRoute의 이름을 설정 나중에 push할 때 이 이름으로 push 가능
        • builder : GoRoute가 이동할 위젯을 생성하는 함수를 정의 → 여기선 'HomeWidget()' 생성
  • HomeWidget() Widget
    • onPressed: () { context.pushNamed('new1'); },
      • 이 코드를 통해 'GoRoute'에서 정의한 'name'인 'new1'을 활용해 해당 라우트로 이동하도록함
      • 즉, 버튼 클릭 시 'new1' 라우트의 화면이 현재 화면 위에 표시됨 
  • NewPage() Widget
    • onPressed: ( ) { context.pop( ); }
      • .pop을 통해 간단하게 '뒤로 가기' 구현
  • NewPage2() Widget
    • onPressed: ( ) { context.goNamed('home'); }
      • 이 코드를 통해 간단하게 '홈으로 돌아가기' 구현
반응형