Vintage appMaker의 Tech Blog

[Flutter] BottomNavitaionBar에서 backkey처리( WillPopScope ) 본문

Source code or Tip/Flutter & Dart

[Flutter] BottomNavitaionBar에서 backkey처리( WillPopScope )

VintageappMaker 2022. 7. 21. 21:55

 

 

1.

다른 플랫폼과 달리 Android에서는 하단메뉴가 존재하는 UI에서는 back 키를 눌렀을 때, 이전화면으로 가는 UX가 요구될 때가 있다. 그럴 경우, Android에서는 onBackPressed() 메소드를 오버라이드한다. 이와 비슷하게 Flutter에서는

WillPopScope의 onWillPop: 파라메터에 bool 값을 리턴하는 함수를 구현한다. false일 경우는 back key를 무력화하고 true일 경우는 back key를 앱에서 처리한다. 

WillPopScope(
  onWillPop: () async {
    //return false; 원하는 기능을 한다.
    //return true;  시스템의 backey를 처리하게 한다(화면종료)
        
  }
  child: ...
}

2.

화면 메뉴 클릭 및 화면이동에 대한 히스토리 관리를 위한 List를 선언하고 하단메뉴를 선택했을 때와 다른 방식으로 이동했을 때를 달리하여 히스토리를 관리한다. 

 

  • 1

메인화면 Widget을 관리(_items) 및 히스토리 관리(_historyItems)

  • 2

메뉴 클릭시 화면 이동 및 history 관리

  • 3

onWillPop에서 async 방식의 함수를 구현하여 back key에 대한 로직을 구현

  • 4

menu에 보이는 Widget과 안보이는 Widget의 index를 지정하고 관리할 수 있다. 그렇게하면 메뉴이동없이 화면을 변경하더라도 history 관리가 된다.

[전체소스]

import "package:flutter/material.dart";
import "package:flutter/widgets.dart";

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter 예제',
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() {
    return _MyHomePageState();
  }
}

class _MyHomePageState extends State<MyHomePage> {
  double fontSize = 15;
  late List<Widget> _items;

  // Widget History
  final List<int> _historyItems = [];

  // Menu count
  final int MENU_SIZE = 3;
  // Widget Item 설정
  int _nItemsIndex = 0;

  void setNoMenuContent(int n) {
    setState(() {
      _historyItems.add(n);
      _nItemsIndex = n;
    });
  }

  @override
  void initState() {
    _items = [
      GestureDetector(
        child: Text(
          "1 - click me",
          style: TextStyle(fontSize: 30),
        ),
        onTap: () {
          setNoMenuContent(3);
        },
      ),
      GestureDetector(
        child: Text(
          "2 - click me",
          style: TextStyle(fontSize: 30),
        ),
        onTap: () {
          setNoMenuContent(3);
        },
      ),
      GestureDetector(
        child: Text(
          "3 - click me",
          style: TextStyle(fontSize: 30),
        ),
        onTap: () {
          setNoMenuContent(3);
        },
      ),
      // menu에 없는 화면(Widget)
      Image.network(
          "https://play-lh.googleusercontent.com/l3vW1Dmmkai50VaheZhg1idph0X1n6epEsN24z9bQecCIuTulg6vqxim9bRXycnmQ9w=w327-h184-rw")
    ];

    // 최초보이는 화면 (index와 selecterdIndex의 기준값이 다르다.)
    _historyItems.add(0);
  }

  int _selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        if (_historyItems.isEmpty) return true;

        setState(() {
          _historyItems.removeLast();

          print("${_historyItems.toString()}");
          var n = _historyItems.last;
          _nItemsIndex = n;
          if (n < MENU_SIZE) _selectedIndex = n;
        });
        return false;
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text("Flutter Example"),
        ),
        body: Center(child: _items[_nItemsIndex]),
        bottomNavigationBar: _showBottomNav(),
      ),
    );
  }

  Widget _showBottomNav() {
    return BottomNavigationBar(
      items: [
        BottomNavigationBarItem(
          icon: Icon(Icons.abc),
          label: '1',
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.numbers_rounded),
          label: '2',
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.pages),
          label: '3',
        ),
      ],
      currentIndex: _selectedIndex,
      selectedItemColor: Colors.green,
      unselectedItemColor: Colors.grey,
      onTap: _onTap,
    );
  }

  // menu onTap
  void _onTap(int index) {
    _historyItems.add(index);

    print("${index}");
    print("${_historyItems.toString()}");

    // 화면갱신
    setState(() {
      _nItemsIndex = index;
      _selectedIndex = index;
    });
  }
}
Comments