Flutter/기본

UI만들기 - 상단부분 (BottomNavigationBar)

꽃피는봄날 2021. 6. 20. 00:56

BottomNavigationBar

 

 

AppBar 오른쪽에 메뉴 추가하기

 

 

 

화면이 3개인 UI 만들기

 

 

화면구성(페이지)을 크게 세부분으로 나누기

 

 

한 줄에 메뉴 4개 만들기

  // 상단
  Widget _buildTop(){
    return Row(

      // ↱가로를 꽉 채우면서 적당한 각격을 유지하도록 정렬
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        Column(
          children: <Widget>[
            Icon(
              Icons.local_taxi,
              size: 40,
            ),
            Text('택시'),
          ],
        ),
        Column(
          children: <Widget>[
            Icon(
              Icons.local_taxi,
              size: 40,
            ),
            Text('승용차'),
          ],
        ),
        Column(
          children: <Widget>[
            Icon(
              Icons.local_taxi,
              size: 40,
            ),
            Text('우버택시'),
          ],
        ),
        Column(
          children: <Widget>[
            Icon(
              Icons.local_taxi,
              size: 40,
            ),
            Text('테슬라'),
          ],
        ),
      ],
    );
  }

 

메뉴를 2줄로 만들기,   그리고 8개의 메뉴를 7개로 변경하기

  • Row 위젯을 -> 다시 Column 위젯으로 감싸고 -> Row전체를 복사해서 Column안에 붙여 넣어주기
더보기
  // 상단
  Widget _buildTop(){

    return Column(
      children: [
        Row(
          // ↱가로를 꽉 채우면서 적당한 각격을 유지하도록 정렬
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            Column(
              children: <Widget>[
                Icon(
                  Icons.local_taxi,
                  size: 40,
                ),
                Text('택시'),
              ],
            ),
            Column(
              children: <Widget>[
                Icon(
                  Icons.local_taxi,
                  size: 40,
                ),
                Text('승용차'),
              ],
            ),
            Column(
              children: <Widget>[
                Icon(
                  Icons.local_taxi,
                  size: 40,
                ),
                Text('우버택시'),
              ],
            ),
            Column(
              children: <Widget>[
                Icon(
                  Icons.local_taxi,
                  size: 40,
                ),
                Text('테슬라'),
              ],
            ),
          ],
        ),

        // 여백 주기
        SizedBox(
          height: 20,
        ),

        Row(
          // ↱가로를 꽉 채우면서 적당한 각격을 유지하도록 정렬
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            Column(
              children: <Widget>[
                Icon(
                  Icons.local_taxi,
                  size: 40,
                ),
                Text('포르쉐'),
              ],
            ),
            Column(
              children: <Widget>[
                Icon(
                  Icons.local_taxi,
                  size: 40,
                ),
                Text('마세라티'),
              ],
            ),
            Column(
              children: <Widget>[
                Icon(
                  Icons.local_taxi,
                  size: 40,
                ),
                Text('서울택시'),
              ],
            ),
            Opacity(
              opacity: 0.0, // 투명하게 설정
              child: Column(
                children: <Widget>[
                  Icon(
                    Icons.local_taxi,
                    size: 40,
                  ),
                  Text('테슬라'),
                ],
              ),
            ),
          ],
        ),

      ],
    );
  }

 

  • 마지막 메뉴 코드를 삭제할 경우 정렬이 흐트러짐 -> Opacity를 사용하여 안 보이게 해야 함

 

 

 

클릭 가능하게 하고 전체 여백주기

  • 클릭가능하게 하기 : Column을 -> GestureDetector ( 또는 InkWell )로 감싼다.

 

  • 전체 여백주기 : 최상단 Column을 padding으로 감싸기

 

 

전체코드⬇︎ 

더보기
import 'dart:math';

import 'package:first_app/main_backUp.dart';
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';


// 이미지 주소목록
final dummyItem =[
  'https://img1.daumcdn.net/thumb/R720x0.q80/?scode=mtistory2&fname=http%3A%2F%2Fcfile28.uf.tistory.com%2Fimage%2F99BDD14D5BB078DA146127',
  'https://img1.daumcdn.net/thumb/R720x0.q80/?scode=mtistory2&fname=http%3A%2F%2Fcfile3.uf.tistory.com%2Fimage%2F9966A24D5BB078E406D14B',
  'https://t1.daumcdn.net/blogfile/fs3/29_blog_2007_07_27_21_08_46a9e00365158?x-content-disposition=inline&filename=coilmimi_24.jpg',
];


// 앱 시작 부분
void main() {
  runApp(MyApp());
}


// 시작 클랙스, 머티리얼 디자인 앱 생성!
class MyApp extends StatelessWidget {

  // StatelessWidget 클래스는 상태를 가지지 않는 위젯을 구성하는 기본 클래스.
  // (상태를 가지지 않는 다는 것은-> 한 번 그려진 후 다시 그리지 않는 경우이며,
  // 프로퍼티로 변수를 가지지 않는다 다만 상수는 가질 수 있다.)

  // StatelessWidget 은 build() 메서드를 가지고 있고 이 메서드는 위젯을 생성할 때 호출 되면서 화면에 그릴 위젯을
  // 반환한다.

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // title, theme, home 인수를 설정한다. (위젯의 속성을 표현)
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,

        // ↱ 전체 테마를 변경하는 방법.
        // primaryColor: Colors.white,

      ),

      // ↱실행될 때 보여지는 것을 설정 (첫 페이지 설정)
      home: MyHomePage(),


    );
  }
}

// 시작 클래스가 실제로 표시하는 클래스
// 첫 번째 페이지
class MyHomePage extends StatefulWidget {
  const MyHomePage({Key key}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> {

  var _index = 0; // 페이지 인덱스

  // 각각의 페이지를 리스트로 구성
  var _pages =[
    Page1(),
    Page2(),
    Page3(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        title: Text('복잡한 UI',
          style: TextStyle(color: Colors.black),
        ),

        centerTitle: true,  // 제목을 가운데로!

        // actions을 이용해 어떠한 위젯도 리스트로 배치가능
       actions: <Widget>[
          IconButton(  // AppBar 메뉴를 작성
              icon: Icon(
                Icons.add,
                color: Colors.blue,
              ),
              onPressed: (){

              })
        ],
      ),

      // 화면이 갱신될 때마다 _index를 활용하여 -> 해당 페이지를 찾게해줌
      body: _pages[_index],


      bottomNavigationBar: BottomNavigationBar(
        onTap: (index11){
          setState(() {
            _index = index11;  // 선택된 탭의 인덱스로 인덱스를 변경
          });
        },

        currentIndex: _index,   // 선택된 인덱스

        // ↱ items에 BottomNavigationBarItem의 위젯 리스트를 정의
        items: <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            label: '홈',
            icon: Icon(Icons.home)
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.assignment),
            label: '이용서비스',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.account_circle),
            label: '내 정보',
          ),
        ],
      ),
    );
  }
}


class Page1 extends StatelessWidget {
  const Page1({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //      컬럼을 이용해 메서드를 세 영역으로 배치
    return ListView(
      children: <Widget> [
        _buildTop(),
        _buildMiddle(),
        _buildBottom(),
      ],
    );
  }


  // 메서드를 이용해 상단, 중단, 하단을 나눔
  // 상단
  Widget _buildTop(){

    return GestureDetector(
      onTap: (){
        print('클릭!~');
      },
      child: Padding(
        padding: const EdgeInsets.only(top: 20, bottom: 20),

        child: Column(
          children: [
            Row(
              // ↱가로를 꽉 채우면서 적당한 각격을 유지하도록 정렬
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                Column(
                  children: <Widget>[
                    Icon(
                      Icons.local_taxi,
                      size: 40,
                    ),
                    Text('택시'),
                  ],
                ),
                Column(
                  children: <Widget>[
                    Icon(
                      Icons.local_taxi,
                      size: 40,
                    ),
                    Text('승용차'),
                  ],
                ),
                Column(
                  children: <Widget>[
                    Icon(
                      Icons.local_taxi,
                      size: 40,
                    ),
                    Text('우버택시'),
                  ],
                ),
                Column(
                  children: <Widget>[
                    Icon(
                      Icons.local_taxi,
                      size: 40,
                    ),
                    Text('테슬라'),
                  ],
                ),
              ],
            ),

            // 여백 주기
            SizedBox(
              height: 20,
            ),

            Row(
              // ↱가로를 꽉 채우면서 적당한 각격을 유지하도록 정렬
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                Column(
                  children: <Widget>[
                    Icon(
                      Icons.local_taxi,
                      size: 40,
                    ),
                    Text('포르쉐'),
                  ],
                ),
                Column(
                  children: <Widget>[
                    Icon(
                      Icons.local_taxi,
                      size: 40,
                    ),
                    Text('마세라티'),
                  ],
                ),
                Column(
                  children: <Widget>[
                    Icon(
                      Icons.local_taxi,
                      size: 40,
                    ),
                    Text('서울택시'),
                  ],
                ),
                Opacity(
                  opacity: 0.0, // 투명하게 설정
                  child: Column(
                    children: <Widget>[
                      Icon(
                        Icons.local_taxi,
                        size: 40,
                      ),
                      Text('테슬라'),
                    ],
                  ),
                ),
              ],
            ),

          ],
        ),
      ),
    );
  }

  // 중단
  Widget _buildMiddle(){
    //      ↱ pub.dev의 Readme의 예제 붙여 넣기
    return CarouselSlider(
      options: CarouselOptions(
        height: 159.0,
        autoPlay: true,  // 슬라이드가 자동으로 넘어감
      ),
      //       ↱ 5페이지로 만듦  (map을 이용해 리스트의 숫자를 다른 요소로 변경)
      items: dummyItem.map((url) {
        return Builder(
          builder: (BuildContext context){
            return Container(
              width: MediaQuery.of(context).size.width,
              margin: EdgeInsets.symmetric(horizontal: 5.0),
              child: ClipRRect( // child를 사각형의 모서리를 둥글게 만듦
                borderRadius: BorderRadius.circular(8.0),
                child: Image.network(
                  url,
                  fit: BoxFit.cover, // 화면에 여백이 남지 않도록 함
                ),
              ),
            );
          },
        );
      }).toList(),
    );
  }

  // 하단
  Widget _buildBottom(){
    final items = List.generate(10, (i) {
      // i 값을 받아서 ListTile 위젯 형태로 변환하여 -> 리스트 형태로 줌... 총  9개가 만들어 지겠지?
      return ListTile(
        leading: Icon(Icons.notifications_none),
        title: Text('$i [이벤트~] 이것은 공지사항임'),
      );
    });
    return ListView(
      physics: NeverScrollableScrollPhysics(),  // 이게 없으면 하단부분이 스크롤이 안 됨 ->
                                                // 스크롤안에 스크롤이 있는 경우 이므로 안 쪽 스크롤을 막아서 작동하도록 함
      shrinkWrap: true, // 이 리스트가 다른 스크롤 객체 안에 있을 경우 true로 설정 (ListView안에 ListView가 있는 경우임)
      children: items,
    );
  }

}

class Page2 extends StatelessWidget {
  const Page2({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        '사용서비스~',
        style: TextStyle(fontSize: 40),
      ),
    );
  }
}

class Page3 extends StatelessWidget {
  const Page3({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        '내정보',
        style: TextStyle(fontSize: 40),
      ),
    );
  }
}