코딩하는 제리

[Flutter/Project](Instagram Clone) 유저 퍼미션 확인 후 SnackBar 생성 본문

Flutter/Project_InstaClone(완)

[Flutter/Project](Instagram Clone) 유저 퍼미션 확인 후 SnackBar 생성

JerryCho 2021. 1. 27. 10:53

 


ScaffoldState 인스턴스 생성 및 해당 Scaffold에 key 추가


소스코드 및 pubspec.yaml

// home_page.dart

import 'package:flutter/material.dart';
import 'package:flutter_project_IJ/screens/camera_screen.dart';
import 'package:flutter_project_IJ/screens/feed_screen.dart';
import 'package:flutter_project_IJ/screens/profile_screen.dart';
import 'package:permission_handler/permission_handler.dart';

import 'constants/screen_size.dart';

class HomePage extends StatefulWidget {
  HomePage({
    Key key,
  }) : super(key: key);

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

class _HomePageState extends State<HomePage> {
  List<BottomNavigationBarItem> btmNavItems = [
    BottomNavigationBarItem(icon: Icon(Icons.home), label: ""),
    BottomNavigationBarItem(icon: Icon(Icons.search), label: ""),
    BottomNavigationBarItem(icon: Icon(Icons.add), label: ""),
    BottomNavigationBarItem(icon: Icon(Icons.healing), label: ""),
    BottomNavigationBarItem(icon: Icon(Icons.account_circle), label: ""),
  ];

  // 바텀네비게이션 바의 인덱스(위치)
  int _selectedIndex = 0;

  // _selectedIndex 값에 따른 화면 구현

  static List<Widget> _screens = <Widget>[
    FeedScreen(),
    Container(
      color: Colors.blueAccent,
    ),
    Container(
      color: Colors.cyanAccent,
    ),
    Container(
      color: Colors.deepOrangeAccent,
    ),
    ProfileScreen(),
  ];

  // SnackBar 사용을 위한 인스턴스. Scaffold의 상태가 필요하다.
  GlobalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    // 해당 디바이스의 화면 사이즈를 가져옴
    if (size == null) size = MediaQuery.of(context).size;
    return Scaffold(
      key: _key,
      /*
      body: _screen[_selectedIndex],
      IndexedStack과 똑같이 구현되지만
      _screen의 화면이 계속 생성된다. 메모리 관리에 매우 취약
      IndexedStack 사용이 올바르다
      */
      body: IndexedStack(
        index: _selectedIndex,
        children: _screens,
      ),
      bottomNavigationBar: BottomNavigationBar(
        unselectedItemColor: Colors.grey,
        selectedItemColor: Colors.black,
        showSelectedLabels: false /* 레이블 비활성화 */,
        items: btmNavItems /* List<BottomNavigationBarItem> 리스트 타입의 데이터 */,
        currentIndex: _selectedIndex,
        onTap: _onBtmItemClick,
      ),
    );
  }

  void _onBtmItemClick(int index) {
    switch (index) {
      case 2:
        _openCamera();
        break;
      default:
        setState(() {
          // onTap으로 상태가 변경될 때 마다 setState로 상태를 새로 불러온다.
          _selectedIndex = index;
        });
    }
  }

  void _openCamera() async {
    // Future가 도착할 때 까지 기다림
    if (await checkedIfPermissionGranted(context))
      Navigator.of(context)
          .push(MaterialPageRoute(builder: (context) => CameraScreen()));
    else {
      SnackBar snackBar = SnackBar(
        content: Text('카메라, 마이크 접근 허용해야 사용할 수 있습니다.'),
        action: SnackBarAction(
          label: '설정',
          onPressed: () {
            _key.currentState.hideCurrentSnackBar() /*버튼 누르면 스낵바 숨김*/;
            openAppSettings() /* 설정창으로 이동 */;
          },
        ),
      );
      // 스낵바 호출
      _key.currentState.showSnackBar(snackBar);
    }
  }

  // 유저 퍼미션
  Future<bool> checkedIfPermissionGranted(BuildContext context) async {
    Map<Permission, PermissionStatus> statuses =
        await [Permission.camera, Permission.microphone].request();
    bool permitted = true;

    statuses.forEach((permission, permissionStatus) {
      // 하나라도 허락되지 않으면 permitted를 false로 바꿈.
      if (!permissionStatus.isGranted) permitted = false;
    });
    return permitted;
  }
}
Comments