본문으로 바로가기

하단 바를 만들고, 아이콘을 탭하면 정해진 화면을 렌더하도록 하자.

 

1. 상태가 바뀌는 것이니 stful 위젯으로 설정

 

2. Scaffold의 bottomNavigationBar 속성으로 BottomNavigationBar을 주고 그 아이템으로 BottomNavigationBarItem을 던져줍니다.

 

3. 페이지가 바뀔 때는 렌더하고 싶은 위젯을 그냥 던져주는 것이 아니라 IndexedStack를 사용합니다. 생성된 위젯을 그냥 던져주면 매번 페이지를 새로 렌더해야 합니다. 리소스 낭비인 거죠.

그러나 IndexedStack를 선택하면, 우선 렌더해야 할 위젯을 stack 쌓아둔 후 필요한 위젯을 최상단으로 가져오고 그 이전에 존재하는 위젯을 다른 곳에 보관하는 방식으로 작동합니다.

 

4. onTap 속성에 주는 함수로 페이지 이동시키면 됩니다. 또, onTap에는 자동으로 아이콘의 index가 주어집니다. 이를 이용하시면 됩니다.

 

 

class MainPage extends StatefulWidget {

  @override
  _MainPageState createState() => _MainPageState();
}

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

  // 화면에 렌더링할 위젯들
  static List<Widget> _widgetOptions = [
    Container(color: Colors.primaries[0],),
    Container(color: Colors.primaries[1],),
    Container(color: Colors.primaries[2],),
    Container(color: Colors.primaries[3],),
    Container(color: Colors.primaries[4],),
  ];

  // 탭 할 때마다 index를 바꿔줍니다.
  void  _onItemTapped(int index) {
    print(index);
    setState(() {
      _selectedIndex = index;
    });
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title : Text("test")),
        body: IndexedStack(
          index: _selectedIndex,
          children: _widgetOptions,
        ),
      bottomNavigationBar: BottomNavigationBar(

        // 선택한 아이템의 레이블 표시할 건가? (왜냐하면 BottomNavigationBarItem의 title이 필수값이라서)
        showSelectedLabels: false,
        // 선택하지 않은 아이템의 레이블 표시할 건가?
        showUnselectedLabels: false,

        // 선택한 아이템의 색
        selectedItemColor: Colors.black,
        // 선택하지 않은 아이템의 색
        unselectedItemColor: Colors.grey[900],

        // animate and labels fade in when they are tapped.
        // 어차피 shifting, fixed 밖에 없습니다.
        type: BottomNavigationBarType.shifting,

        // 하단 바의 배경 색깔
        backgroundColor: Color.fromRGBO(249, 249, 249, 1),

        // 하단 바가 가질 아이템들
        items: [
          _buildBottomNavigationBarItem(activeIconPath: "assets/home_selected.png", iconPath: "assets/home.png"),
          _buildBottomNavigationBarItem(activeIconPath: "assets/search_selected.png", iconPath: "assets/search.png"),
          _buildBottomNavigationBarItem(iconPath: "assets/add.png"),
          _buildBottomNavigationBarItem(activeIconPath: "assets/heart_selected.png", iconPath: "assets/heart.png"),
          _buildBottomNavigationBarItem(activeIconPath: "assets/profile_selected.png", iconPath: "assets/profile.png"),
        ],

        // 선택한 아이템의 index
        currentIndex: _selectedIndex,

        // 아이템을 선택했을 때 할 액션
        onTap: (index) => _onItemTapped(index)
      ),
    );
  }
}

BottomNavigationBarItem _buildBottomNavigationBarItem({String activeIconPath, String iconPath}) {
  return BottomNavigationBarItem(
    // 선택되었을 때 사용할 아이콘
    activeIcon: activeIconPath == null ? null : ImageIcon(AssetImage(activeIconPath)),
    // 선택 안 되었을 때의 아이콘
    icon: ImageIcon(AssetImage(iconPath)),
    // BottomNavigationBarItem은 title 속성이 필수값입니다.
    title: Text(''),
  );
}

 

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체