Skip to content

Instantly share code, notes, and snippets.

@ChangJoo-Park
Last active January 20, 2020 08:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChangJoo-Park/d1b12bf552edd6005b8b81b95aedea97 to your computer and use it in GitHub Desktop.
Save ChangJoo-Park/d1b12bf552edd6005b8b81b95aedea97 to your computer and use it in GitHub Desktop.
Flutter로 당근마켓 만들기
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:market/image_list_tile.dart';
List<Map<String, dynamic>> list = <Map<String, dynamic>>[
{
'image':
'https://dnvefa72aowie.cloudfront.net/origin/article/202001/245bb54195ae001a87e09830c0a3140e30cba0366a275c64b2b23afdf1043c43.webp?q=82&s=300x300&t=crop',
'name': '김치냉장고 무료 나눔합니다',
'place': '서울 성북구 상월곡동',
'uploadAt': '방금',
'price': '10,000원',
'numberOfChat': 40,
'numberOfHeart': 21,
'numberOfComment': 0,
},
{
'image':
'https://dnvefa72aowie.cloudfront.net/origin/article/202001/c84830f43b5b9912b4871673a99cd74bb7e9ccb02273e6ff89a9445cddc08b57.webp?q=82&s=300x300&t=crop',
'name': '이사정리 ( 침대 화장대 통돌이 드럼 세탁기 쇼파 냉장고 팝니다)',
'place': '제주 제주시 조천읍',
'uploadAt': '9시간 전',
'price': '300,000원',
'numberOfChat': 11,
'numberOfHeart': 0,
'numberOfComment': 24,
},
{
'image':
'https://dnvefa72aowie.cloudfront.net/origin/article/202001/737cfa849fd985b80cbe174fe1b79e040dd4efdd72fed3a28911ecf2467948ea.webp?q=82&s=300x300&t=crop',
'name': '제습기',
'place': '대전 서구 둔산동',
'uploadAt': '9시간 전',
'price': '50,000원',
'numberOfChat': 3,
'numberOfHeart': 1,
'numberOfComment': 24,
},
{
'image':
'https://dnvefa72aowie.cloudfront.net/origin/article/202001/d684cfb333962675f8d7b526f7b1b97bea10d0d7c837a97ab0428c63f77ad454.webp?q=82&s=300x300&t=crop',
'name': '전자레인지',
'place': '전북 전주시 덕진구 송천동 2가',
'uploadAt': '9시간 전',
'price': '10,000원',
'numberOfChat': 10,
'numberOfHeart': 1,
'numberOfComment': 27,
},
{
'image':
'https://dnvefa72aowie.cloudfront.net/origin/article/202001/ae156634f7b41d8f8f5655488e03bcf885f4f3e651cde3e22017cd307c483a42.webp?q=82&s=300x300&t=crop',
'name': '무료나눔',
'place': '제주 서귀포시 성산읍',
'uploadAt': '7시간 전',
'price': '무료나눔',
'numberOfChat': 2,
'numberOfHeart': 0,
'numberOfComment': 7,
}
];
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.white,
accentColor: Colors.black,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: choices.length,
child: Scaffold(
appBar: AppBar(
title: Container(
child: GestureDetector(
child: Row(children: [
Text('서초동',
style:
TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold)),
Icon(Icons.expand_more)
]),
),
),
actions: <Widget>[
IconButton(icon: Icon(Icons.search), onPressed: () {}),
IconButton(icon: Icon(Icons.settings), onPressed: () {}),
IconButton(icon: Icon(Icons.notifications_none), onPressed: () {}),
],
bottom: TabBar(
tabs: choices.map((Choice choice) {
return Tab(
text: choice.title,
);
}).toList(),
),
),
body: TabBarView(
children: choices.map((Choice choice) {
return ListView.builder(
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
Map<String, dynamic> item = list[index];
return ImageListTile(
imageWidth: 80,
imageHeight: 80,
image: item['image'],
customChild: Container(
padding: EdgeInsets.only(right: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
item['name'],
style: TextStyle(
fontSize: 14.0, fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
),
Text(
'${item["place"]} · ${item["uploadAt"]}',
style: TextStyle(fontSize: 12.0),
overflow: TextOverflow.ellipsis,
),
Text(
item['price'],
style: TextStyle(fontSize: 12.0),
overflow: TextOverflow.ellipsis,
),
Spacer(flex: 1),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
item['numberOfComment'] > 0
? Row(
children: <Widget>[
Icon(
Icons.comment,
size: 14.0,
color: const Color(0xff8785A4),
),
Text(" ${item['numberOfComment']}",
style: TextStyle(
fontSize: 14.0,
color: const Color(0xff8785A4))),
SizedBox(width: 8.0),
],
)
: SizedBox(width: 0, height: 0),
item['numberOfChat'] > 0
? Row(
children: <Widget>[
Icon(Icons.chat_bubble_outline,
size: 14.0,
color: const Color(0xff8785A4)),
Text(" ${item['numberOfChat']}",
style: TextStyle(
fontSize: 14.0,
color: const Color(0xff8785A4))),
SizedBox(width: 8.0),
],
)
: SizedBox(width: 0, height: 0),
item['numberOfHeart'] > 0
? Row(
children: <Widget>[
Icon(Icons.favorite_border,
size: 14.0,
color: const Color(0xff8785A4)),
Text(" ${item['numberOfHeart']}",
style: TextStyle(
fontSize: 14.0,
color: const Color(0xff8785A4))),
],
)
: SizedBox(width: 0, height: 0)
],
)
],
),
),
);
},
);
}).toList(),
),
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home, color: Colors.black),
title: Text('홈', style: TextStyle(color: Colors.black))),
BottomNavigationBarItem(
icon: Icon(Icons.menu, color: Colors.grey),
title: Text('카테고리', style: TextStyle(color: Colors.grey))),
BottomNavigationBarItem(
icon: Icon(Icons.create, color: Colors.grey),
title: Text('글쓰기', style: TextStyle(color: Colors.grey))),
BottomNavigationBarItem(
icon: Icon(Icons.favorite, color: Colors.grey),
title: Text('채팅', style: TextStyle(color: Colors.grey))),
BottomNavigationBarItem(
icon: Icon(Icons.person, color: Colors.grey),
title: Text('나의당근', style: TextStyle(color: Colors.grey))),
],
type: BottomNavigationBarType.fixed,
currentIndex: 0,
fixedColor: Colors.black,
onTap: (int index) {},
),
),
);
}
}
class Choice {
const Choice({this.title});
final String title;
}
const List<Choice> choices = const <Choice>[
const Choice(title: '중고거래'),
const Choice(title: '동네생활'),
];
int hexToInt(String hex) {
int val = 0;
int len = hex.length;
for (int i = 0; i < len; i++) {
int hexDigit = hex.codeUnitAt(i);
if (hexDigit >= 48 && hexDigit <= 57) {
val += (hexDigit - 48) * (1 << (4 * (len - 1 - i)));
} else if (hexDigit >= 65 && hexDigit <= 70) {
// A..F
val += (hexDigit - 55) * (1 << (4 * (len - 1 - i)));
} else if (hexDigit >= 97 && hexDigit <= 102) {
// a..f
val += (hexDigit - 87) * (1 << (4 * (len - 1 - i)));
} else {
throw new FormatException("Invalid hexadecimal value");
}
}
return val;
}
import 'package:flutter/material.dart';
@immutable
class ImageListTile extends StatelessWidget {
ImageListTile({
@required this.image,
this.imageWidth = 80.0,
this.imageHeight = 80.0,
this.imageBorderRadius = 8.0,
borderRadius,
foregroundImage,
BoxDecoration imageBoxDecoration,
this.customChild,
String title,
String subtitle,
this.onPressed,
this.onLongPressed,
}) {
if ((title != null && subtitle != null) && customChild != null) {
throw Exception('Title, Subtitle cannot using with customChild');
}
this.borderRadius =
borderRadius ?? BorderRadius.circular(imageBorderRadius);
this.foregroundImage = foregroundImage ?? Container();
this.imageBoxDecoration = imageBoxDecoration ??
BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://m.media-amazon.com/images/I/51jrNN1OU1L._AC_UY218_ML3_.jpg'),
fit: BoxFit.contain,
),
);
if (this.customChild == null) {
this.title = title ?? '';
this.subtitle = subtitle ?? '';
this.titleWidget = Text(title, style: titleTextStyle);
this.subtitleWidget = Text(subtitle, style: subtitleTextStyle);
}
}
final double imageWidth;
final double imageHeight;
final double imageBorderRadius;
final String image;
final TextStyle titleTextStyle = TextStyle(fontWeight: FontWeight.bold);
final TextStyle subtitleTextStyle = TextStyle(fontSize: 12.0);
final VoidCallback onPressed;
final VoidCallback onLongPressed;
String title;
String subtitle;
Text titleWidget;
Text subtitleWidget;
Widget customChild;
BoxDecoration imageBoxDecoration;
BorderRadius borderRadius;
Widget foregroundImage;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Column(
children: <Widget>[
Row(children: <Widget>[_buildImage(), _buildBody()]),
],
),
);
}
Expanded _buildBody() {
return Expanded(
flex: 1,
child: Container(
alignment: Alignment.topLeft,
height: imageHeight,
child: customChild ?? _buildSpecificContainer(),
),
);
}
Widget _buildSpecificContainer() {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
titleWidget,
subtitleWidget,
],
),
);
}
Padding _buildImage() {
return Padding(
padding: EdgeInsets.all(imageBorderRadius),
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(imageBorderRadius),
child: Ink(
width: imageWidth,
height: imageHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(imageBorderRadius),
image: DecorationImage(
image: NetworkImage(image),
fit: BoxFit.contain,
),
),
child: foregroundImage,
),
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment