강의설명은 정말 쉬운거 같은데, 알고보면 새로운 코드들이 계속 나온다.
외우지 않아도 자연스럽게 알게 되는 경지에 오르려면 얼마나 많이 다뤄야 할지 전혀 감이 오지 않지만, 강의를 듣기 위해 앉아만 있으면 시간은 순삭이다.ㅎㄷㄷ~
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://is1-ssl.mzstatic.com/image/thumb/Music/2e/0d/9e/mzi.oqzdlrnq.jpg/592x592bb.webp',
'title': 'Geek In the Pink',
'artist': 'Jason Mraz',
},
{
'imageUrl':
'https://is2-ssl.mzstatic.com/image/thumb/Music127/v4/fb/c0/fc/fbc0fcac-4867-3530-eb06-c674e4f262c6/cover-.jpg/632x632bb.webp',
'title': 'Luving u',
'artist': '거미',
},
{
'imageUrl':
'https://is2-ssl.mzstatic.com/image/thumb/Music115/v4/3f/3d/d0/3f3dd00d-4bd1-8e71-1300-9387c7a319d3/8809534461859_Cover.jpg/592x592bb.webp',
'title': '첫눈처럼 너에게 가..',
'artist': '에일리',
},
{
'imageUrl':
'https://is3-ssl.mzstatic.com/image/thumb/Music124/v4/0b/fa/7d/0bfa7d8e-6320-663a-a115-e3fa068a2418/825646367580.jpg/632x632bb.webp',
'title': 'La foule',
'artist': 'Édith Piaf',
},
{
'imageUrl':
'https://is5-ssl.mzstatic.com/image/thumb/Music125/v4/59/17/35/591735c0-1939-57a8-2d40-978047695025/8183.jpg/592x592bb.webp',
'title': 'Shape of you',
'artist': '제이플라',
},
{
'imageUrl':
'https://is4-ssl.mzstatic.com/image/thumb/Music114/v4/1d/49/8f/1d498f55-ea5c-2a0f-6c5a-77364494d5e2/swja_serenade_3000.jpg/592x592bb.webp',
'title': '도망가자',
'artist': '선우정아',
},
];
return SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
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,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
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),
child: Row(
children: [
Icon(
Icons.person_rounded,
),
SizedBox(
width: 8,
),
Text(
"아티스트",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
],
),
),
Divider(),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
Icon(Icons.music_note),
SizedBox(
width: 8,
),
Text(
"회원님을 위한 재생목록",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
],
),
),
Divider(),
SizedBox(height: 16),
Text(
"최근 Shazam",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
),
),
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 imageUrl = song['imageUrl']!;
String title = song['title']!;
String artist = song['artist']!;
return Container(
margin: EdgeInsets.all(6),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(8),
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.4),
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(12),
child: Container(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
artist,
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
Spacer(),
Image.network(
"https://www.pngitem.com/pimgs/m/18-189854_listen-on-apple-music-logo-hd-png-download.png",
width: 80,
),
],
),
),
),
)
],
),
);
},
),
),
],
),
),
);
}
}
// 두번째 페이지
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.0, horizontal: 16.0),
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),
),
],
),
),
],
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.1,
),
Text(
"Shazam 하려면 탭하세요.",
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.06,
),
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: 130,
height: 130,
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.12,
),
Container(
width: 50,
height: 50,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.blue[400],
shape: BoxShape.circle,
),
child: Icon(
Icons.search,
color: Colors.white,
size: 30,
),
)
],
),
),
);
}
}
// 세번째 페이지
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': 'Adele',
},
{
'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(fontWeight: FontWeight.bold, fontSize: 18),
),
SizedBox(
height: 16,
),
Expanded(
child: ListView(
children: [
Stack(
alignment: Alignment.center,
children: [
Container(
height: 180,
width: double.infinity,
color: Colors.purple[900],
),
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[400],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Text(
"대한민국 챠트",
style: TextStyle(fontSize: 16),
),
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,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
Text(artist),
],
),
);
}).toList(),
),
Container(
width: double.infinity,
height: 8,
color: Colors.grey[400],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Text(
"글로벌 챠트",
style: TextStyle(fontSize: 16),
),
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,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
Text(artist),
],
),
);
}).toList(),
),
Container(
width: double.infinity,
height: 8,
color: Colors.grey[400],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Text(
"뉴욕 챠트",
style: TextStyle(fontSize: 16),
),
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,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
Text(artist),
],
),
);
}).toList(),
),
],
),
)
],
));
}
}