주요 사용 위젯
- BottomNavigationBar : 하단 탭 구성
- AppBar : 상단 제목줄 구성
- Row, Column : 가로, 세로 레이아웃 구성
- GestureDetector : 클릭 이벤트 만들기 위한 위젯
- Opacity : 투명도
- CarouselSlider : 좌우 슬라이드하는 UI 작성을 위한 라이브러리
- Listview : ListTile과 함께 사용하여 스크롤 가능한 리스트를 만드는 위젯
* ListView 안에 ListView 를 넣어야 하는 경우 physics / shrinkWrap 프로퍼티를 지정해줘야 함
Step
1. 전체 틀 잡기
2. BottomNavigationBar를 이용해 하단 탭 만들기 + AppBar 수정해서 상단부 만들기
3. 메인 화면(HomePage) 상/중/하단 만들기
1. 전체 틀 잡기 : 기본 코드에서 쓸데없는 것들 다 날리자.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(''),
),
body: Center(
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
2. BottomNavigationBar를 이용해 하단 탭 만들기 + AppBar 속성 변경해서 노란 테마로 바꾸기
class _MyHomePageState extends State<MyHomePage> {
var _pageIndex = 0; // 페이지 정보
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Complicated UI App'),
centerTitle: true, // 중앙 정렬 여부
elevation: 6, // 상단바 그림자 강도
actions: <Widget>[
IconButton(
icon: Icon(
Icons.add_circle,
color: Colors.black87,
),
onPressed: () {},
),
IconButton(
icon: Icon(
Icons.drafts,
color: Colors.black87,
),
onPressed: () {},
),
],
),
body: Center(
child: Text('$_pageIndex 페이지', style: TextStyle(fontSize: 50)),
),
bottomNavigationBar: BottomNavigationBar(
onTap: (value) { // 하단 네비게이션 바를 눌러 페이지 이동
setState(() {
_pageIndex = value;
});
},
currentIndex: _pageIndex, // 현재 페이지
selectedItemColor: Colors.amber, // 선택된 NavigationBar의 색상
unselectedItemColor: Colors.black26, // 선택안된 NavigationBar의 색상
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.add_a_photo),
title: Text('photo'),
),
BottomNavigationBarItem(
icon: Icon(Icons.more_horiz),
title: Text('more'),
),
]
),// ng comma makes auto-formatting nicer for build methods.
);
}
}
3. 메인 화면(HomePage) 상/중/하단 만들기
- 크게 세 부분으로 나누기 (각 부분은 위젯 리턴형 메소드로 분리)
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
_pageOfTop(), // 상단
_pageOfMiddle(), // 중단
_pageOfBottom(), // 하단
],
);
}
}
Widget _pageOfTop() {
return Text('pageOfTop');
}
Widget _pageOfMiddle() {
return Text('pageOfMiddle');
}
Widget _pageOfBottom() {
return Text('pageOfBottom');
}
- 상단부분 만들기
- 클릭할 아이콘과 텍스트 만들기
Widget _pageOfTop() {
return Column(
children: <Widget>[
Icon(
Icons.directions_bike,
size: 40,
),
Text(
'자전거'
),
],
);
}
- 위 메뉴를 한 줄에 3개씩 만들기 (tip : mainAxisAlignment 프로퍼티 설정으로 위젯간 공간 동일하게 만들기)
: Column을 Row위젯으로 감싸고 해당 Column위젯을 복사해서 3개로 만들자
Widget _pageOfTop() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 위젯 사이 공간 동일하게 만들기
children: <Widget>[
Column(
children: <Widget>[
Icon(
Icons.directions_bike,
size: 40,
),
Text(
'자전거'
),
],
),
Column(
children: <Widget>[
Icon(
Icons.directions_run,
size: 40,
),
Text(
'뛰기'
),
],
),
Column(
children: <Widget>[
Icon(
Icons.directions_bus,
size: 40,
),
Text(
'버스'
),
],
),
],
);
}
- 총 두 줄로 만들기 (tip : Row와 Row 사이에 SizedBox 위치시켜서 여백 넣기)
: Row위젯을 Column위젯으로 다시 감싸고 Row위젯을 복사시켜서 2줄을 만들자
Widget _pageOfTop() {
return Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Column(
children: <Widget>[
Icon(
Icons.directions_bike,
size: 40,
),
Text(
'자전거'
),
],
),
Column(
children: <Widget>[
Icon(
Icons.directions_run,
size: 40,
),
Text(
'달리기'
),
],
),
Column(
children: <Widget>[
Icon(
Icons.directions_bus,
size: 40,
),
Text(
'버스'
),
],
),
],
),
SizedBox(height: 30,), // Row와 Row사이에 위치시켜서 여백 넣기
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Column(
children: <Widget>[
Icon(
Icons.directions_car,
size: 40,
),
Text(
'자동차'
),
],
),
Column(
children: <Widget>[
Icon(
Icons.directions_subway,
size: 40,
),
Text(
'지하철'
),
],
),
Column(
children: <Widget>[
Icon(
Icons.directions_boat,
size: 40,
),
Text(
'보트'
),
],
),
],
)
],
);
}
- 총 메뉴 개수 5개로 만들기
: 아래줄의 Column을 2개로 줄이면 윗줄 3개의 간격과 달라 보기에 좋지 않다.
지우고 싶은 Column에 Opacity위젯으로 감싸고 프로퍼티를 변경해 보이지 않게 바꾸자
Opacity( // 안보이게 하고 싶은 위젯을 감싸기
opacity: 0.0, // 완전 투명
child: Column(
children: <Widget>[
Icon(
Icons.directions_boat,
size: 40,
),
Text(
'보트'
),
],
),
),
- 메뉴를 클릭할 수 있게 만들고 전체 여백 주기
: Column을 GestureDetector 위젯으로 감싸고 onTap 프로퍼티를 통해 클릭이벤트를 만들자
* InkWell 위젯으로 감싸면 클릭시 효과가 보여서 마음에 드는 것으로 선택하면 된다.
Widget _pageOfTop() {
return Padding( // 여백을 위해 위젯 추가
padding: const EdgeInsets.only(top: 30.0), 위쪽 여백만 30 주기
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
GestureDetector( // 클릭이벤트를 위한 위젯 추가
onTap: () { // 클릭시 실행
print('자전거 아이콘 클릭');
},
child: Column(
children: <Widget>[
Icon(
Icons.directions_bike,
size: 40,
),
Text(
'자전거'
),
],
),
),
Column(
children: <Widget>[
Icon(
Icons.directions_run,
size: 40,
...
}
- 중단부분 만들기
- carousel_slider 추가하기 : https://pub.dev/packages/carousel_slider
- 슬라이더 위젯 활용하기 : https://pub.dev/packages/carousel_slider
> 상단 페이지의 How to use 부분 복사해오자.
Widget _pageOfMiddle() {
return CarouselSlider(
options: CarouselOptions(height: 400.0), // 슬라이더 높이 설정
items: [1,2,3,4,5].map((i) { //
return Builder(
builder: (BuildContext context) { // context 사용할 경우 활용 가능
return Container(
width: MediaQuery.of(context).size.width, // 기기 가로사이즈 받아오기
margin: EdgeInsets.symmetric(horizontal: 5.0), // 좌우여백 설정
decoration: BoxDecoration(
color: Colors.amber
),
child: Text('text $i', style: TextStyle(fontSize: 16.0),)
);
},
);
}).toList(),
);
}
- 슬라이더에 사진을 넣고 입맛에 맞게 변경
- pubspec.yaml 파일에 assets폴더 추가 후 사진 assets 폴더로 옮기기
- 리스트로 이미지 리스트 추가
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';
final pictureLists = [
'assets/buildings-5070537__480.jpg',
'assets/landscape-5137147__480.jpg',
'assets/spring-5093894__480.jpg',
'assets/temple-5142557__480.jpg',
];
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
...
- 슬라이더 부분 수정
Widget _pageOfMiddle() {
return CarouselSlider(
options: CarouselOptions(
height: 200,
autoPlay: true, // 자동 슬라이더 설정
), // 슬라이더 높이 설정
items: pictureLists.map((url) { // 리스트의 url 넘기기
return Builder(
builder: (BuildContext context) { // context 사용할 경우 활용 가능
return Container(
width: MediaQuery.of(context).size.width, // 기기 가로사이즈 받아오기
margin: EdgeInsets.symmetric(horizontal: 5.0), // 좌우여백 설정
child: ClipRRect( // 이미지 슬라이더에 활용할 위젯
borderRadius: BorderRadius.circular(10.0),
child: Image.asset(
url, // 해당 url 값을 이미지로
fit: BoxFit.cover // 이미지 채우기
),
),
);
},
);
}).toList(),
);
}
- HomePage의 return 위젯을 Column에서 ListView로 변경해 전체가 스크롤 되도록 변경
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView( // Column에서 변경
children: <Widget>[
_pageOfTop(),
_pageOfMiddle(),
_pageOfBottom(),
],
);
}
}
- 하단 만들기
- ListView / ListTile 이용해 구현하기
> ListView위젯(HomePage) 안에 ListView위젯(_pageOfBottom)을 감싸고 있는 경우 shrinkWrap 프로퍼티를 true로
설정해줘야 하며 위젯에서 스크롤이 되려면 physics 프로퍼티의 NeverScrollableScrollPhysics 를 설정해줘야 한다.
Widget _pageOfBottom() {
final items = List.generate(15, (i) {
var num = i + 1;
return ListTile(
leading: Icon(Icons.notifications),
title: Text('$num번째 ListTile'),
);
});
return ListView(
physics: NeverScrollableScrollPhysics(), // 해당 리스트의 스크롤 금지
shrinkWrap: true, // 상위 리스트 위젯이 별도로 있다면 true 로 설정해야 스크롤이 가능
children: items,
);
}
댓글