본문 바로가기
공부기록/Flutter

[Flutter] AppBar, BottomNavigator 구현(상단,하단은 고정 & body만 바뀌도록)

by 책읽는 개발자 ami 2023. 7. 5.
728x90
반응형

 

Flutter에서 상단 바, 하단 네비게이션 구현하기

main.dart

MainPage 위젯을 통해 구성된 애플리케이션이다. 애플리케이션의 전체적인 테마와 페이지 구성을 설정하고, 페이지 간 이동을 관리한다.

  • MyApp: MaterialApp을 생성하여 애플리케이션 전체의 테마와 기본 설정을 지정. title은 애플리케이션의 제목을 설정하고, theme은 전체적인 테마 설정을 담고 있음.
  • MainPage: StatefulWidget를 상속하여 페이지 이동과 BottomNavigationBar를 관리하는 위젯
    _currentIndex 변수를 사용하여 현재 선택된 페이지 인덱스를 관리하며, _onItemTapped 함수는 탭 이벤트를 처리하여 _currentIndex를 업데이트
    _pages 리스트에는 홈페이지와 세 개의 탭 페이지 위젯이 포함
  • build: Scaffold를 구성하여 앱의 기본 레이아웃을 정의
    - AppBar는 뒤로가기 버튼을 추가한 상단 앱 바를 표시
    - body는 현재 선택된 페이지에 해당하는 위젯을 표시
    - bottomNavigationBar는 네비게이션 바로, 사용자가 선택한 탭에 따라 현재 페이지를 업데이트

HomePage, Tab1Page, Tab2Page, Tab3Page라는 각각의 페이지 위젯을 생성하고 _pages 리스트에 추가하여 페이지 간 이동을 처리.
BottomNavigationBar를 통해 사용자가 원하는 페이지로 이동할 수 있다.

import 'package:flutter/material.dart';
import 'package:musicalapp/home.dart';
import 'package:musicalapp/tab1.dart';
import 'package:musicalapp/tab2.dart';
import 'package:musicalapp/tab3.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My Mobile App',
      theme: ThemeData(
          primarySwatch: Colors.blue,
          appBarTheme: AppBarTheme(
            backgroundColor: Colors.white, // 기본 색상
          )),
      home: MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int _currentIndex = 0;

  final List<Widget> _pages = [HomePage(), Tab1Page(), Tab2Page(), Tab3Page()];

  void _onItemTapped(int index) {
    setState(() {
      _currentIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        //title: Text('My Mobile App'),
        leading: IconButton(
          icon: Icon(Icons.arrow_back),
          color: Colors.grey,
          onPressed: () {
            // 뒤로가기 버튼 동작
          },
        ),
      ),
      body: _pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: '홈',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.event),
            label: '탭1',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.tiktok),
            label: '탭2',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: 'MY',
          ),
        ],
        currentIndex: _currentIndex,
        selectedItemColor: Color.fromARGB(255, 197, 142, 233),
        unselectedItemColor: Colors.grey,
        onTap: _onItemTapped,
      ),
    );
  }
}

home.dart에 대한 설명은 아래 링크 참조!
2023.07.04 - [공부기록/Flutter] - [Flutter] 반응형 모바일 배너 만들기(슬라이더)

home.dart

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<HomePage> {
  final PageController _pageController = PageController();
  int _currentPage = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            Expanded(
              flex: 1,
              child: Stack(
                children: [
                  PageView(
                    controller: _pageController,
                    onPageChanged: (int page) {
                      setState(() {
                        _currentPage = page;
                      });
                    },
                    children: [
                      buildBanner('Banner 1', 0),
                      buildBanner('Banner 2', 1),
                    ],
                  ),
                  Align(
                    alignment: Alignment.bottomCenter,
                    child: Container(
                      margin: EdgeInsets.symmetric(vertical: 8.0),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          for (int i = 0; i < 2; i++)
                            Container(
                              margin: EdgeInsets.all(4.0),
                              width: 12.0,
                              height: 12.0,
                              decoration: BoxDecoration(
                                shape: BoxShape.circle,
                                color: _currentPage == i
                                    ? Colors.grey
                                    : Colors.grey.withOpacity(0.5),
                              ),
                            ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Expanded(
              flex: 4,
              child: Column(
                children: [
                  Expanded(
                    child: Container(
                      margin: EdgeInsets.symmetric(vertical: 8.0),
                      padding: EdgeInsets.all(8.0),
                      alignment: Alignment.center,
                      decoration: BoxDecoration(
                        borderRadius:
                            BorderRadius.circular(10.0), // 원하는 둥근 정도를 설정합니다.
                        color: Colors.white,
                        boxShadow: [
                          BoxShadow(
                            color: Colors.grey.withOpacity(0.5),
                            spreadRadius: 2,
                            blurRadius: 4,
                            offset: Offset(0, 2),
                          ),
                        ],
                      ),
                      child: Text('2'),
                    ),
                  ),
                  Expanded(
                    child: Container(
                      margin: EdgeInsets.symmetric(vertical: 8.0),
                      padding: EdgeInsets.all(8.0),
                      alignment: Alignment.center,
                      decoration: BoxDecoration(
                        borderRadius:
                            BorderRadius.circular(10.0), // 원하는 둥근 정도를 설정합니다.
                        color: Colors.white,
                        boxShadow: [
                          BoxShadow(
                            color: Colors.grey.withOpacity(0.5),
                            spreadRadius: 2,
                            blurRadius: 4,
                            offset: Offset(0, 2),
                          ),
                        ],
                      ),
                      child: Text('2'),
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget buildBanner(String text, int index) {
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(10.0), // 원하는 둥근 정도를 설정합니다.
        color: Colors.blueGrey,
      ),
      child: Center(child: Text(text)),
    );
  }
}

tab1.dart

tab1.dart는 첫 번째 탭 페이지로, 간단한 리스트를 보여주는 페이지
페이지 상단에는 "탭1 리스트"라는 제목이 표시되고, 아래에는 아이템들의 목록이
ListView.builder를 통해 동적으로 생성된다.
각 아이템은 번호와 해당 아이템에 대한 세부 정보로 구성되어 표시된다.

tab1.dart, tab2.dart, tab3.dart

import 'package:flutter/material.dart';

class Tab1Page extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding: EdgeInsets.all(16.0),
            child: Text(
              '탭1 리스트',
              style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold),
            ),
          ),
          Expanded(
            child: ListView.builder(
              itemCount: 20,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text('Item ${index + 1}'),
                  subtitle: Text('Details about Items ${index + 1}'),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

 

위와 같은 방법으로 AppBar와 BottomNavigator는 고정하고 body만 변경되는 식으로 앱을 구현할 수 있다.

(정식으로 공부를 해서 작성하는 코드가 아니므로 더 좋은 방법이 있을 수 도 있습니다. 더 효율적인 방법이 있다면 댓글로 알려주시면 감사드리겠습니다!)

728x90
반응형