목표
기능은 제외하고 주어진 화면 만들어 보기
이미지
작동 영상
사전 준비
주어진 코드
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Shazam',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: 1,
length: 3,
child: Builder(builder: (context) {
DefaultTabController.of(context)?.addListener(() {
setState(() {});
});
return Scaffold(
body: Stack(
children: [
TabBarView(
children: [
FirstTab(),
SecondTab(),
ThirdTab(),
],
),
SafeArea(
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 16),
child: Column(
children: [
Container(
alignment: Alignment.topCenter,
child: TabPageSelector(
color: DefaultTabController.of(context)?.index == 1
? Colors.blue[300]
: Colors.grey[400],
selectedColor:
DefaultTabController.of(context)?.index == 1
? Colors.white
: Colors.blue,
indicatorSize: 8,
),
),
],
),
),
),
],
),
);
}),
);
}
}
// 첫번째 페이지
class FirstTab extends StatelessWidget {
const FirstTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
const songs = [
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
];
return Center(child: Text('첫번째 페이지'));
}
}
// 두번째 페이지
class SecondTab extends StatelessWidget {
const SecondTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(child: Text('두번째 페이지'));
}
}
// 세번째 페이지
class ThirdTab extends StatelessWidget {
const ThirdTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
const chartData = {
'korea': [
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
],
'global': [
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
],
'newyork': [
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
],
};
return Center(child: Text('세번째 페이지'));
}
}
완성 코드
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Shazam',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: 1,
length: 3,
child: Builder(builder: (context) {
DefaultTabController.of(context)?.addListener(() {
setState(() {});
});
return Scaffold(
body: Stack(
children: [
TabBarView(
children: [
FirstTab(),
SecondTab(),
ThirdTab(),
],
),
SafeArea(
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 16),
child: Column(
children: [
Container(
alignment: Alignment.topCenter,
child: TabPageSelector(
color: DefaultTabController.of(context)?.index == 1
? Colors.blue[300]
: Colors.grey[400],
selectedColor:
DefaultTabController.of(context)?.index == 1
? Colors.white
: Colors.blue,
indicatorSize: 8,
),
),
],
),
),
),
],
),
);
}),
);
}
}
// 첫번째 페이지
class FirstTab extends StatelessWidget {
const FirstTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
const songs = [
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
{
'imageUrl': 'https://i.ytimg.com/vi/jAO0KXRdz_4/hqdefault.jpg',
'title': '가을밤에 든 생각',
'artist': '잔나비',
},
];
return SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Icon(Icons.settings),
),
Text(
"라이브러리",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Icon(null),
],
),
SizedBox(
height: 8,
),
//Shazam
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
children: [
ImageIcon(
NetworkImage("https://i.ibb.co/hxNbZ8p/shazam.png"),
size: 18,
),
SizedBox(
width: 12,
),
Text(
"Shazam",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
),
],
),
),
Divider(),
//아티스트
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
children: [
Icon(Icons.person_rounded),
SizedBox(
width: 12,
),
Text(
"아티스트",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
),
],
),
),
Divider(),
//회원님을 위한 재생 목록
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
children: [
Icon(Icons.music_note),
SizedBox(
width: 12,
),
Text(
"회원님을 위한 재생 목록",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
),
],
),
),
Divider(),
SizedBox(height: 16),
Text("최근 Shazam",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
)),
SizedBox(height: 16),
Expanded(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3 / 5,
),
itemCount: songs.length,
itemBuilder: (context, index) {
var song = songs[index];
String title = song['title']!;
String artist = song['artist']!;
String imageUrl = song['imageUrl']!;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(8),
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
blurRadius: 1,
spreadRadius: 1,
)
]),
child: Column(children: [
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
child: Image.network(
imageUrl,
fit: BoxFit.cover,
height: MediaQuery.of(context).size.width *
0.5 *
(5 / 3) *
0.55,
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
)),
Text(artist,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.grey,
)),
Spacer(),
Image.network(
"https://i.ibb.co/KG9m5QS/applemusic.png",
width: 60,
)
],
),
),
),
),
]),
),
);
},
),
)
],
),
));
}
}
// 두번째 페이지
class SecondTab extends StatelessWidget {
const SecondTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.blue[300]!, Colors.blue[900]!],
),
),
child: SafeArea(
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Row(
children: [
GestureDetector(
onTap: () {
DefaultTabController.of(context)!.animateTo(0);
},
child: Column(
children: [
Icon(
Icons.person,
color: Colors.white,
),
Text(
"라이브러리",
style: TextStyle(color: Colors.white),
)
],
),
),
Spacer(),
GestureDetector(
onTap: () {
DefaultTabController.of(context)!.animateTo(2);
},
child: Column(
children: [
Icon(
Icons.show_chart,
color: Colors.white,
),
Text(
"차트",
style: TextStyle(color: Colors.white),
)
],
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 60),
child: Text(
"Shazam하려면 탭하세요",
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 80),
child: Container(
alignment: Alignment.center,
width: 200,
height: 200,
decoration: BoxDecoration(
color: Colors.blue[300],
shape: BoxShape.circle,
),
child: Image.network(
"https://i.ibb.co/hxNbZ8p/shazam.png",
color: Colors.white,
width: 150,
height: 150,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 90),
child: Container(
alignment: Alignment.center,
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.blue[400],
shape: BoxShape.circle,
),
child: Icon(
Icons.search,
color: Colors.white,
),
),
),
],
),
),
);
}
}
// 세번째 페이지
class ThirdTab extends StatelessWidget {
const ThirdTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
const chartData = {
'korea': [
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
],
'global': [
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
],
'newyork': [
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
{
'imageUrl': 'https://i.ibb.co/xf2HpfG/dynamite.jpg',
'name': 'Dynamite',
'artist': 'BTS',
},
],
};
return SafeArea(
child: Column(
children: [
Text(
"차트",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(height: 18),
Expanded(
child: ListView(
children: [
Stack(
alignment: Alignment.center,
children: [
Container(
color: Colors.purple[900],
width: double.infinity,
height: 180,
),
Column(
children: [
Container(
width: MediaQuery.of(context).size.width * 0.8,
child: ElevatedButton(
onPressed: () {},
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.white)),
child: Text(
"국가 및 도시별 차트",
style: TextStyle(
color: Colors.purple[900],
fontWeight: FontWeight.bold),
),
),
),
SizedBox(
height: 8,
),
Text(
"전 세계",
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
)
],
),
],
),
//대한민국
Container(
width: double.infinity,
height: 8,
color: Colors.grey,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Text("대한민국 차트"),
Spacer(),
Text(
"모두 보기",
style: TextStyle(color: Colors.blue),
),
],
),
),
Row(
children: chartData['korea']!.map((element) {
String imageUrl = element['imageUrl']!;
String name = element['name']!;
String artist = element['artist']!;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
imageUrl,
width: MediaQuery.of(context).size.width * 0.29,
),
Text(name),
Text(artist),
],
),
);
}).toList(),
),
//글로벌
Container(
width: double.infinity,
height: 8,
color: Colors.grey,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Text("글로벌 차트"),
Spacer(),
Text(
"모두 보기",
style: TextStyle(color: Colors.blue),
),
],
),
),
Row(
children: chartData['global']!.map((element) {
String imageUrl = element['imageUrl']!;
String name = element['name']!;
String artist = element['artist']!;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
imageUrl,
width: MediaQuery.of(context).size.width * 0.29,
),
Text(name),
Text(artist),
],
),
);
}).toList(),
),
// 뉴욕 차트
Container(
width: double.infinity,
height: 8,
color: Colors.grey,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Text("뉴욕 차트"),
Spacer(),
Text(
"모두 보기",
style: TextStyle(color: Colors.blue),
),
],
),
),
Row(
children: chartData['newyork']!.map((element) {
String imageUrl = element['imageUrl']!;
String name = element['name']!;
String artist = element['artist']!;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
imageUrl,
width: MediaQuery.of(context).size.width * 0.29,
),
Text(name),
Text(artist),
],
),
);
}).toList(),
)
],
),
)
],
));
}
}
2주차
- Row
가로로 요소를 삽입할때 쓰임 - leadingWidth: 100
오버플로우 나지않게 해주는 역할을 해줌 - 화면 구성 방법
column과 row와 stack을 이용하여 화면 구성 - overflow: TextOverflow.ellipsis
오버플로우를 막아줘야하지만 최종적으로 Expanded로 감싸줘야한다 이는 Refactor -> widget으로 만든뒤 이름을 변경하자 - Alignment 방법
Flutter 가로 세로 정렬 - SizedBox(width: 12)
패딩처럼 공간 띄우기 - Spacer()
공간 최대한 차지하고 나머지 위젯 밀어내는 역할 - GestureDetector
위젯을 버튼처럼 - floatingActionButton: FloatingActionButton
눌리는 아이콘 만듥;
- 간단한 조건문 만들기
isFavorite
? CupertinoIcons.heart_fill
: CupertinoIcons.heart,
color: isFavorite ? Colors.pink : Colors.black,
?뒤는 참일때
:뒤는 거짓일때
- padding 방법
padding: const EdgeInsets.symmetric(horizontal: 16),
symmetric 대칭형으로
horizontal 가로방향만
- statefullwidget
사용할때는 2개의 클래스를 사용하는데 위의 클래스 변수를 아래 클래스에서 사용하고 싶을떄는 widget.imageUrl 처럼 widget을 붙이면 된다.
사진의 required this.imageUrl은 imageUrl인자를 꼭 받겠다는 문장이다.
- final의 의미
final도 const와 마찬가지로 처음 선언한 값을 변경할 수 없다.
하지만 다른점은 const의경우 선언부에서 무조건 값을 부여해주어야하지만 final은 선언 시 값을 부여하지 않고 이후 최초 1번 값을 부여해줄 수 있다.
그래서 선언부의 코드만으로는 컴파일러가 해당 변수의 값을 알 수 없기 때문에 const처럼 앱 실행 시 메모리에 넣어 관리할 수 없다.
- Scaffold 사용
Scaffold는 appbar 와 body를 사용할떄 사용하는것이므로 appbar를 안쓸거면 scaffold를 사용안해도 된다
- 그라데이션 넣는 방법
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.blue[300]!, Colors.blue[900]!],
),
),
blue[300]! 뒤에 !오는 이유는 널값이 들어갈수도있어서 오류 방지를 위해 넣는다.
- mainAxisAlignment: MainAxisAlignment.spaceBetween
아이콘을 양쪽으로 붙게 하는 기능
→ 두 아이콘 사이에 Spacer(), 함수를 넣어도 가능
- SafeArea
너무 처음부터 붙지않게 약간의 공간을 만들어 준다.(아이폰의위와 아래 부분에 가리지 않게 해줌)
- IconButton사용시 아이콘하고 text의 공간이 생기는데 이를 해결하는 방법
GestureDetector(
onTap: () {
DefaultTabController.of(context)!.animateTo(0);
},
IconButton 대신 GestureDetector로 column을 묶어줘서 클릭 이벤트로 만들면 된다.
- GestureDetector의 사용법
InkWell과 매우 비슷합니다. 둘다 클릭시 동작하게 만들어줌
InkWell과의 차이점은 사용자의 동작을 감지 시 별도의 애니메이션 효과가 없습니다.
- 패딩 세부사항 조절
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16)
padding: const EdgeInsets.only(top: 100),
- 공간 여백을 퍼센트로 주는 방법
SizedBox(height: MediaQuery.of(context).size.height * 0.1),
10퍼센트만큼 차지하게 만들기.
- 그림 뒤에 여백 주기
stack사용 뿐만이 라니라 container 자체에 색을 넣어주는것도 가능
Container(
alignment: Alignment.center,
width: 200,
height: 200,
decoration: BoxDecoration(
color: Colors.blue[300],
shape: BoxShape.circle,
),
child: Image.network(
"<https://i.ibb.co/hxNbZ8p/shazam.png>",
color: Colors.white,
width: 150,
height: 150,
),
+참고로
alignment: Alignment.center, 정렬을 해줘야 크기가 적용됨 그이유는 어떤 걸 기준으로 크기를 조절해야할지 모르기 때문에 정렬을 해줘야 적용이 되는것
비포 에프터
- ListView 오류
크기를 정해주지 않아서 오류가 나는데 이는 ListView를 Expanded로 refacture 해주면 된다 감싸주면 된다.
- color: Colors.purple[900],
색 뒤에 [900] 해줌으로 색을 조절할수있다 높을수록 찐하게
- 크기 설정
width: double.infinity,
끝까지 채우는 것
- 버튼의 색을 바꾸는 방법
+파란 줄 오류가 뜨는 이유는 child는 맨 뒤에 있어야한다고 해서 style 뒤로 옮기면 해결 된다.
- 버튼의 가로 넓이 조절
Container(
width: MediaQuery.of(context).size.width * 0.8,
child: ElevatedButton(
버튼을 container로 묶어준뒤 넓이 설정
- list요소 나타내기
위처럼
요소들을 나타내고 싶을때
row로 묶은뒤 chartData['korea']로 접근을 하는데
이를 .map으로 나타낼수있다.
chartData['korea'].map((element) {
return Text("he");
})
이때 return하는것 자체를 list로 만들어야하는데 이는 .list를 붙여서
chartData['korea'].map((element) {
return Text("he");
}).toList(),
이렇게 만들어야하는데
row에는 children: []로 이미 list가 있으므로
Row(
children: chartData['korea'].map((element) {
return Text("he");
}).toList(),
)
이런식으로 []를 벗겨준다
이때
이처럼 map에 오류가 뜨는데 이는 chartData['korea']에 null값이 올수 있으니까 오류가 뜨는건데
children: chartData['korea']!.map((element) {
return Text("he");
}).toList(),
이런식으로 null값이 아니라는
chartData['korea']!.map((element) !를 붙여주면 해결된다.
+추가 활용
Row(
children: chartData['newyork']!.map((element) {
String imageUrl = element['imageUrl']!;
String name = element['name']!;
String artist = element['artist']!;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
imageUrl,
width: MediaQuery.of(context).size.width * 0.29,
),
Text(name),
Text(artist),
],
),
);
}).toList(),
)
요소를 변수로 지정해주고 지정해줄때는 !와 ; 를 잘 넣어야한다
- 3가지 요소 및 2가지 요소 정렬
Icon(null)값과 mainAxisAlignment: MainAxisAlignment.spaceBetween으로 정렬을 하는 방법도 있음
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.settings),
Text(
"라이브러리",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Icon(null),
],
)
여기서 아이콘만 살짝 밑으로 내리려 할때 주로 padding을 주는데 이때 라이브러리란 텍스트도 같이 내려오게 된다
이러한 이유는 기본 정렬이 center이므로 같이 정렬이 되는건데 이를
crossAxisAlignment: CrossAxisAlignment.start, 로 맞춰주면 해결이 된다.
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Icon(Icons.settings),
),
Text(
"라이브러리",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Icon(null),
],
)
- 이미지 아이콘화
ImageIcon(
NetworkImage("<https://i.ibb.co/hxNbZ8p/shazam.png>"),
size: 18,
),
- 폰트 bold 세세한 설정
fontWeight: FontWeight.w600
- GridView.builder 사용
사용할때 공간지정오류를 위해 expanded로 묶어줘야한다.
Expanded(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3 / 5,
),
itemCount: songs.length,
itemBuilder: (context, index) {
return Text("D");
},
),
)
기본적인 요소들이며 분석해보면
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount는 스타일을 정하는것이며
crossAxisCount는 가로로 몇개를 표시할지
childAspectRatio: 3 / 5,는 세로로 길이를 조절
itemCount: songs.length,
itemBuilder: (context, index) {
return Text("D");
},
밑은 요소를 나타내는데 사용된다.
return Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.all(
Radius.circular(8),
)),
);
여기서
borderRadius: BorderRadius.all(
Radius.circular(8),
)
이부분은 테두리를 둥글게 만드는 옵션이다.
+이미지를 넣을때 이미지도 같이 둥글게 만들려면
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
child: Image.network(imageUrl),
),
cliprrect을 사용해서 한번더 해준다.
그림자
Boxdecoration안에
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
blurRadius: 1,
spreadRadius: 1,
)
]
이렇게 넣어주는데
이렇게 그림자로 정해준 회색이 밑에도 차지해버리므로 컨테이너 자체 색을 흰색으로 정해줘야한다.
'Flutter 앱 개발일지' 카테고리의 다른 글
Flutter 프로젝트 준비(Flutter 프로젝트 생성하기,VSCode Dart 세팅,Android Studio 설치,Android Studio 에뮬레이터 설치,VSCode에뮬레이터 실행하기) (1) | 2023.01.02 |
---|---|
Movie Reviews 만들기 (0) | 2022.12.31 |
Flutter? (1) | 2022.12.27 |