Flutter Application/기초 사용법

Flutter 화면 이동(BottomNavigationBar) 구현

sdchjjj 2024. 12. 1. 13:45
반응형

안녕하세요.

 

이번 포스팅에서는 하단 navigation bar를 사용해 화면을 이동하는 방식을 간략하게 구현해 보겠습니다.

 

언어: dart

IDE: Android Studio

Framework: Flutter

Test device: Android

 

먼저 Screen으로 사용하기 위한 Widget들을 작성해 줍니다.

main.dart

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: Text(
            'Home Screen',
            style: TextStyle(fontSize: 24)
        )
    );
  }
}

class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: Text(
            'First Screen',
            style: TextStyle(fontSize: 24)
        )
    );
  }
}

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center
      (child: Text(
        'Second Screen',
        style: TextStyle(fontSize: 24)
    )
    );
  }
}

 

그리고 Navigation bar를 위한 StatefulWidget을 생성해 줍니다.

main.dart

class FrameScreen extends StatefulWidget {
  @override
  _FrameScreenState createState() => _FrameScreenState();
}

class _FrameScreenState extends State<FrameScreen> {
  int _selectedIndex = 0;

  // List of screens
  final List<Widget> _screens = [
    HomeScreen(),
    FirstScreen(),
    SecondScreen(),
  ];

  // Update selected index
  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Bottom Navigation Bar'),
      ),
      body: _screens[_selectedIndex], // Show selected screen
      bottomNavigationBar: BottomNavigationBar(
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            label: 'First',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: 'Second',
          ),
        ],
        currentIndex: _selectedIndex, // Highlight selected item
        selectedItemColor: Colors.blue,
        onTap: _onItemTapped, // Handle tap
      ),
    );
  }
}

하단에 navigation bar가 있고, 그 위의 공간은 다른 화면들을 그리기 위한 프레임으로 사용됩니다.

 

전체 코드입니다.

main.dart

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Bottom Navigation Bar',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FrameScreen(),
    );
  }
}

class FrameScreen extends StatefulWidget {
  @override
  _FrameScreenState createState() => _FrameScreenState();
}

class _FrameScreenState extends State<FrameScreen> {
  int _selectedIndex = 0;

  // List of screens
  final List<Widget> _screens = [
    HomeScreen(),
    FirstScreen(),
    SecondScreen(),
  ];

  // Update selected index
  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Bottom Navigation Bar'),
      ),
      body: _screens[_selectedIndex], // Show selected screen
      bottomNavigationBar: BottomNavigationBar(
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            label: 'First',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: 'Second',
          ),
        ],
        currentIndex: _selectedIndex, // Highlight selected item
        selectedItemColor: Colors.blue,
        onTap: _onItemTapped, // Handle tap
      ),
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: Text(
            'Home Screen',
            style: TextStyle(fontSize: 24)
        )
    );
  }
}

class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: Text(
            'First Screen',
            style: TextStyle(fontSize: 24)
        )
    );
  }
}

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center
      (child: Text(
        'Second Screen',
        style: TextStyle(fontSize: 24)
    )
    );
  }
}

간단하게 3개의 스크린으로 구성해 보았습니다. 테스트해 보겠습니다.

 

result

 

정상적으로 동작합니다.

 

여기서 페이지 이동 애니메이션을 추가해 보겠습니다.

 

_onItemTapped에 animateToPage을 아래와 같이 추가해 줍니다.

main.dart/_HomeScreenState

void _onItemTapped(int index) {
  setState(() {
    _selectedIndex = index;
  });
  
  // 이동 시 애니메이션 효과 부여
  _pageController.animateToPage(
    index,
    duration: Duration(milliseconds: 300),
    curve: Curves.easeInOut,
  );
}

 

그리고 PageView 부분도 수정해 줍니다.

main.dart/_HomeScreenState/build

PageView(
  controller: _pageController,
  onPageChanged: (index) {
    setState(() {
      _selectedIndex = index;
    });
  },
  children: _screens,
  physics: NeverScrollableScrollPhysics(),
)

 

아래 코드 유저가 화면 스와이프로 스크린을 넘길 수 없도록 막은 것입니다.

physics: NeverScrollableScrollPhysics(),

이 부분을 지우면 Navigation Bar 터치뿐 아니라 화면을 밀어서도 이동할 수 있게 됩니다.

 

전체 코드입니다.

main.dart

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Bottom Navigation with Slide Animation',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  int _selectedIndex = 0;
  final PageController _pageController = PageController();

  final List<Widget> _screens = [
    Center(child: Text('Home Screen', style: TextStyle(fontSize: 24))),
    Center(child: Text('Search Screen', style: TextStyle(fontSize: 24))),
    Center(child: Text('Profile Screen', style: TextStyle(fontSize: 24))),
  ];

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

    // 이동 시 애니메이션 효과 부여
    _pageController.animateToPage(
      index,
      duration: Duration(milliseconds: 300),
      curve: Curves.easeInOut,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Bottom Navigation with Slide Animation'),
      ),
      body: PageView(
        controller: _pageController,
        onPageChanged: (index) {
          setState(() {
            _selectedIndex = index;
          });
        },
        children: _screens,
        physics: NeverScrollableScrollPhysics(),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            label: 'Search',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.blue,
        onTap: _onItemTapped,
      ),
    );
  }
}

 

화면 전환에 슬라이드 효과를 추가해 주었습니다.

 

확인해 보겠습니다.

result2

 

정상적으로 구현되었습니다.

 

포스팅을 마치겠습니다.

 

감사합니다!

728x90
반응형