
도전하기
- 카카오톡 친구 탭

import 'package:flutter/material.dart';
import 'package:badges/badges.dart' as badges;
void main() {
runApp(const MyApp());
}
class Friend {
String img;
String name;
String? message;
String? music;
Friend({required this.img, required this.name, this.message, this.music});
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
List<Friend> friends = [
Friend(img: 'http://picsum.photos/48/48', name: '전여친', message: '똥차다음벤츠라더니', music: '똥밟았네'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친', message: '똥차다음벤츠라더니'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친', music: '똥밟았네'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친', message: '똥차다음벤츠라더니', music: '똥밟았네'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친', message: '똥차다음벤츠라더니', music: '똥밟았네'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친', message: '똥차다음벤츠라더니'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친', message: '똥차다음벤츠라더니', music: '똥밟았네'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친', message: '똥차다음벤츠라더니', music: '똥밟았네'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친', message: '똥차다음벤츠라더니', music: '똥밟았네'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친', message: '똥차다음벤츠라더니'),
Friend(img: 'http://picsum.photos/48/48', name: '전여친', message: '똥차다음벤츠라더니', music: '똥밟았네'),
];
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
foregroundColor: Colors.black,
elevation: 0,
centerTitle: false,
title: Text('친구'),
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.search),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.person_add_alt),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.music_note_outlined),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.settings_outlined),
)
],
),
body: ListView(
children: [
SizedBox(
height: 80,
child: PageView(
children: [
Image.asset('assets/images/kakaotalk/event_1.png'),
Image.asset('assets/images/kakaotalk/event_2.png'),
],
),
),
ListTile(
leading: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(17),
),
clipBehavior: Clip.antiAlias,
child: Image.network('http://picsum.photos/50/50'),
),
title: Text('SFAC', style: TextStyle(fontWeight: FontWeight.bold),),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 10, 8, 20),
child: Divider(
height: 2,
),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: Text('친구 ${friends.length}'),
),
Column(
children: List.generate(
friends.length, (index) => ListTile(
leading: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(17),
),
clipBehavior: Clip.antiAlias,
child: Image.network(friends[index].img),
),
title: Text(friends[index].name, style: TextStyle(fontWeight: FontWeight.bold),),
subtitle:
subtitle: friends[index].message != null ? Text(friends[index].message!) : null,
trailing: friends[index].music != null ?
Container(
width: 100,
decoration: BoxDecoration(
border: Border.all(color: Colors.green),
borderRadius: BorderRadius.circular(10)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(friends[index].music!),
Icon(Icons.play_arrow_outlined,color: Colors.green,),
],
),
) : null,
),
)
),
],
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
selectedItemColor: Colors.black,
showSelectedLabels: false,
showUnselectedLabels: false,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.person), label: 'friends'),
BottomNavigationBarItem(
icon: badges.Badge(
badgeContent: Text('99', style: TextStyle(color: Colors.white),),
child: Icon(Icons.chat_bubble_outlined),), label: 'message'),
BottomNavigationBarItem(
icon: Icon(Icons.remove_red_eye_outlined), label: 'view'),
BottomNavigationBarItem(
icon: Icon(Icons.add_business), label: 'shop'),
BottomNavigationBarItem(
icon: Icon(Icons.more_horiz), label: 'more'),
],
),
)
);
}
}

주간평가 (키오스크 앱)
- Output

Requirements
- 음식을 누르면 주문 리스트에 담기는 키오스크앱을 만들어봅니다.
- 음식이미지는 자유이며, 필요한 경우 위에 첨부된 파일을 이용하여도 됩니다.
- 하단에 떠있는 버튼을 누르면 지금까지 주문된 주문 리스트를 초기화합니다.
- 하단에 떠있는 버튼은 정중앙의 하단, 넓게 펴진 형태로 [ 초기화하기 ] 텍스트를 포함합니다.
- 음식이 보여지는 것은 [갤러리] 형태로 보여지게 하며, 검색을 통해 해결합니다.
- 그 외 UI 디자인은 자유입니다.
- MenuTile.dart
import 'package:flutter/material.dart';
class MenuTile extends StatelessWidget {
const MenuTile({Key? key, required this.imgUrl, required this.name}) : super(key: key);
final String imgUrl;
final String name;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Colors.black12,
blurRadius: 4,
spreadRadius: 1,
)
]
),
child: Container(
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 75,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(imgUrl),
fit: BoxFit.cover,
)
),
),
Text(name, style: TextStyle(fontWeight: FontWeight.bold),),
Text('[담기]'),
],
),
),
);
}
}
- Kiosk.dart
- 메뉴를 담을 때 주문 리스트에 중복해서 출력하지 않고, 개수를 카운팅하여 주문 리스트에 메뉴 이름과 개수를 출력하는 형태로 구현했습니다
import 'package:first_app/homework/week2/kiosk/MenuTile.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class Menu {
String imgUrl;
String name;
Menu(this.imgUrl, this.name);
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Menu> menuList = [
Menu('assets/images/kiosk/option_bokki.png', '떡볶이'),
Menu('assets/images/kiosk/option_beer.png', '맥주'),
Menu('assets/images/kiosk/option_kimbap.png', '김밥'),
Menu('assets/images/kiosk/option_omurice.png', '오므라이스'),
Menu('assets/images/kiosk/option_pork_cutlets.png', '돈까스'),
Menu('assets/images/kiosk/option_ramen.png', '라면'),
Menu('assets/images/kiosk/option_udon.png', '우동'),
];
List<String> orderList = [];
Map<String, int> countMenu = {};
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('분식왕 이테디 주문하기',
style: TextStyle(color: Colors.black),),
centerTitle: true,
backgroundColor: Colors.white,
elevation: 0,
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('주문 리스트',
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),),
Text(countMenu.toString(),
style: TextStyle(fontSize: 16),),
Text('음식',
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),),
GridView.builder(
shrinkWrap: true,
itemCount: menuList.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
setState(() {
String tapMenu = menuList[index].name;
orderList.add(tapMenu);
if(countMenu.containsKey(tapMenu)){
countMenu[tapMenu] = countMenu[tapMenu]! + 1;
} else {
countMenu[tapMenu] = 1;
}
});
},
child: MenuTile(
imgUrl: menuList[index].imgUrl,
name: menuList[index].name));
},
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1 / 1,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
),
],
),
)
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
setState(() {
orderList.clear();
countMenu.clear();
});
},
label: Text('초기화하기'),
),
)
);
}
}

