ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Flutter - 코딩마스터하기|새로운 시작! instagram V2.0
    개발/Flutter 2021. 10. 21. 01:14
    반응형

    기초부터 다시 시작

    프로젝트부터 생성을 해보자. 생성을 한 후, avd manager에서 에뮬레이터를 생성 한 후 처음 상태로 실행해보자.

    여기까진 다른 글들을 찾아가면서 하면 금방 할 수 있다. 다른 디버깅 방법으로는 핸드폰을 직접 연결해서 하는 방법인데, 지금은 선없이 연결하려고 해본다. 우선 핸드폰에 플레이 스토어에서 ip address를 검색한 후  ip tools 라는 어플을 다운 받는다. 다른 ip를 볼 수 있는 앱이면 괜찮다. 실행 후 Internal IP를 찾는다. 그리고 adb가 없으면 설치 한후 cmd 창에서 스마트폰을 연결한 상태로 adb tcpip 5555를 해주고 adb connect Internal IP:5555를 해주면 열린다. 이렇게 같은 와이파이안에있으면 작동을 하게된다.(그러나 나는 안됨...왜 안되는지 모르겠음...)

     

    MaterialApp 으로 기초 부분 만들기

    main.dart에서 void main() 부분을 제외하고 아래를 다 지워준후 StatelessWidget를 만들어 주고 MyApp으로 클래스명을 지정해준 뒤, return에 MaterialApp에 home에 Scaffold, 그 안에 appbar에 AppBar를 하고 title로 Text에 아무 글자를 넣어준 뒤 에뮬레이터에 실행을 하면 된다.


    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('cool app'),
            ),
            body: Container(color: Colors.amber,),
          ),
        );
      }
    }

    코드나누기(위젯추출)

    Scaffold 부분을 드래그 한뒤, refactor에 method로 해주면 따로 분리된다. 밑에 분리된 코드를 잘라내기 한 후, lib에 home_page.dart라는 새 파일을 만들어 준후 붙여넣어주면 된다. 그리고 빨간 밑줄 부분을 import 해준뒤 실행하면 정상 작동 한다.

     

    bottom navigationbar 생성

    Scaffold 안에 bottomNavigationBar 옵션에 BattomNavigationBar를 넣어준다. 그리고 그안에 items안에 넣어주면 된다. items는 List로써 BattomNavigationBarItem을 가진 여러개의 아이템을 받는다. 그래서 상단에 List<BottomNavigationBarItem>을 생성해준다. 그리고 그 안에 BottomNavigationBarItem을 만들고 icon과 label을 넣어준후 icon에는 Icon(Icons.**)로 모양을 다르게 5개를 만들어 준다. label은 원래 주로 title가 쓰였으나 바뀌고 추천되는 부분이다. 그 밑에는 int로 현재 선택된 index의 번호를 지정해주는 것을 만들어준다. 처음 시작하는 부분을 적는데, 우선은 0으로 해둔다. 나중에 5개중 가운데서 시작하고싶으면 2를 넣으면 된다. 그 후 items에는 btmNavItems를 넣어주고 BattomNavigationBar에 unselectedItemColor와 selectedItemColor에 색을 집어 넣어준다. 안넣어주면 바만 보이고 아이콘들은 보이지 않는다.  currentIndex에 위에서 만든 현재 Index를 넣는 부분을 넣어준다. 그리고 현재 StatelessWidget인데 이상태에서 화면이 변하지 않으므로 StatefulWidget로 변경해준다. StatelessWidget에서 Alt + Enter해서 Convert 해주면 상태를 변화시키는 부분도 자동으로 생성된다. 그리고 ontap에서 index를 변화 시켜준다. 변수들의 값의 상태를 변화시키는것은 setState(){}에서 변화시키면 된다. 메소드로 만들고 int index를 받아온다. bottomNavigationBar 에서 자동으로 index를 알려주므로 _selectedIndex = index로 해주면 변하는 것을 알 수 있다. 실행시켜보면 버튼을 누르면 변하는 것을 알 수 있다. 이때 아이콘이 위로 올라오는데 이부분은 선택되었을때 레이블이 보이게 되는데 이때 옵션을 꺼두면 된다. showSelectedLabels, showUnselectedLabels 를 모두 false 해주면 된다.


    Widget build(BuildContext context) {
        return Scaffold(
          body: Container(
            color: Colors.cyan,
          )
          bottomNavigationBar: BottomNavigationBar(
            showSelectedLabels: false,
            showUnselectedLabels: false,
            items: btmNavItems,
            unselectedItemColor: Colors.grey,
            selectedItemColor: Colors.black87,
            currentIndex: _selectedIndex,
            onTap: _onBtnItemClick,
          ),
        );

    화면을 indexed stack로 바꾸기

    body에 여러가지를 넣어서 네비게이션 버튼마다 다르게 해줄것임. 우선을 List<Widget> _screens 라는것을 생성해줌. 그 안에 Container를 색만 다르게 버튼 갯수만큼 생성 해줌. List이기 때문에 _screens[선택된 인덱스]로 해주면 원하는 창이 뜸. body에 그렇게 넣어주면 되는데 이렇게 할 때는 Container 대신 속에 든게 많은 레이아웃이면 힘들어지므로 body에 바로 _screen[index]를 쓰기 보다는 IndexedStack를 사용하면 된다. 두개의 동작이 다른데 그냥 쓰게 되면 레이아웃이 바뀌는 형태이고 IndexedStack는 모든 레이아웃이 쌓아져있고 그 인덱스 부분이 선택되면 가장 위로 올라오는 형태이다. Indexedstack에 index에 _selectedIndex를 넣고 children에 _screens를 넣어주면 된다.


        List<BottomNavigationBarItem> btmNavItems = [
        const BottomNavigationBarItem(
          icon: Icon(Icons.home),
          label: "",
        ),
        const BottomNavigationBarItem(
          icon: Icon(Icons.search),
          label: "",
        ),
        const BottomNavigationBarItem(
          icon: Icon(Icons.add),
          label: "",
        ),
        const BottomNavigationBarItem(
          icon: Icon(Icons.healing),
          label: "",
        ),
        const BottomNavigationBarItem(
          icon: Icon(Icons.account_circle),
          label: "",
        ),
      ];
    
      int _selectedIndex = 0;
    
      final List<Widget> _screens = [ //노란줄일때 final을 추천함. 강의에서는 static인데 그냥 final쓰면 될듯
        Container(color: Colors.amberAccent,),
        Container(color: Colors.blueAccent,),
        Container(color: Colors.greenAccent,),
        Container(color: Colors.deepPurpleAccent,),
        Container(color: Colors.cyanAccent,),
      ];
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          //body: _screens[_selectedIndex], //이렇게 할대 문제점은 위에 각각의 스크린에다가 복잡하게 위젯을 하면 힘들어짐 그래서 다른것으로 써야함
          body: IndexedStack( //이렇게 하면 화면이 스택으로 쌓여있고 선택된 index가 맨위로 올라오는 형태임 각각의 창들도 관리하기 쉬워짐
            index: _selectedIndex,
            children: _screens,
          ),
          bottomNavigationBar: BottomNavigationBar(
            showSelectedLabels: false,
            showUnselectedLabels: false,
            items: btmNavItems,
            unselectedItemColor: Colors.grey,
            selectedItemColor: Colors.black87,
            currentIndex: _selectedIndex,
            onTap: _onBtnItemClick,
          ),
        );
      }
        void _onBtnItemClick(int index) {
        setState(() {// 이 안에서만 상태가 바뀜 이 클래스 안에서만 사용가능
          _selectedIndex = index;
        });
      }

    Feed Screen 만들기

    lib 폴더에 feed_screen.dart를 만들고 StatelessWidget로 FeedScreen을 만들어 준다. 그 뒤 home_page의 _screens의 가장 위의 Container을 FeedScreen()으로 바꿔준다.


    class FeedScreen extends StatelessWidget {
    
      @override
      Widget build(BuildContext context) {
        return Container();
      }
    }

    그리고 피드페이지를 위해 Container을 Scaffold로 바꿔준후 appbar에 AppBar를 넣어주고 title을 Text로 instagram을 넣어준다. 글씨체를 커스텀해서 쓸것인데 우선 원하는 글씨체를 받은 후, pubspec.yaml으로 이동한다. 하단에 fonts라고 되어 있는 부분이 있는데 fonts - family - fonts - assets 까지 주석을 제거해준다.(이때 버그인지 모르겠지만 주석 푼 부분을 한칸씩 더 들여써줘야 한다.) 그리고 family를 VeganStyle로 변경해준다. 프로젝트 가장 상위에서 폴더로 assets를 만들어 준다. 그리고 그 안에 fonts 폴더를 하나 더 만들어 준다. 다운 받은 폰트를 fonts에 집어 넣어준 후, pubspec.yaml에서 fonts - assets에 경로를 assets/fonts/다운받은폰트명.ttf로 해주면 된다. 그 후 실행을 해보면 폰트가 바뀐 instgram을 앱바에서 확인할 수 있다.(하지만 강의와는 다르게 똑같이 해도 중앙정렬이 아님. 그래서 Center로 묶음)


    class FeedScreen extends StatelessWidget {
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text(
              'instagram',
              style: TextStyle(
                fontFamily: 'VeganStyle',
              ),
            ),
          ),
        );
      }
    }

    이어서 앱바의 색을 하얗게 하고 글씨를 까맣게 해보자. instagram글씨 부분의 TextStyle에서 color을 black87로 준다. 흰색은 feed_screen의 Scaffold에 주면 그 페이지만 하얀색이므로 mina.dart에서 MaterialApp안에 theme 옵션이 있다. 거기에 ThemeData를 주고 primarySwatch옵션에 color을 주면된다. 그러나 Colors.white는 Color인데 primarySwatch는 MaterialColor로 줘야 하기 때문에 이 부분을 하얀색으로 주기 위해서는 직접 만들어 주면 된다. lib에 material_white.dart를 만들어 주고 Colors.red에 red부분에 Ctrl + 클릭으로 이동하는 부분에서 복사한 값을 붙여넣어준다. 가장 상단의 부분은 0xFFFFFFFF로 해주고 50부터 차례대로 가장 앞쪽의 F를 0~9로 해주면 된다. 이 부분이 투명도 이다. 변수명도 white로 바꿔준다.


    const MaterialColor white = MaterialColor(
      0xFFFFFFFF,
      <int, Color>{
        50: Color(0x0FFFFFFF),
        100: Color(0x1FFFFFFF),
        200: Color(0x2FFFFFFF),
        300: Color(0x3FFFFFFF),
        400: Color(0x4FFFFFFF),
        500: Color(0x5FFFFFFF),
        600: Color(0x6FFFFFFF),
        700: Color(0x7FFFFFFF),
        800: Color(0x8FFFFFFF),
        900: Color(0x9FFFFFFF),
      }
    );

    그리고 이제 색을 넣어주는 부분을 그냥 white로 해주고, import를 해주면 된다.

    반응형

    댓글

Designed by Tistory.