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),
),
);
}
}