https://github.com/insertvalue2/class_carrot_market
폴더 및 파일 만들기
pubspec.ymal 파일 설정
기본 코드 입력
앱 테마 설정
main.dart 파일 완성
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.6
google_fonts: ^6.2.1
intl: ^0.20.0
font_awesome_flutter: ^10.8.0
1단계
import 'package:carrot_market_ui/screens/main_screens.dart';
import 'package:flutter/material.dart';
void main() {
runApp(CarrotMarketApp());
}
class CarrotMarketApp extends StatelessWidget {
CarrotMarketApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'carrotMarket',
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.orangeAccent)
),
home: MainScreens(),
);
}
}
import 'package:flutter/material.dart';
class MainScreens extends StatefulWidget {
const MainScreens({super.key});
@override
State<MainScreens> createState() => _MainScreensState();
}
class _MainScreensState extends State<MainScreens> {
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
2단계
import 'package:flutter/material.dart';
class MainScreens extends StatefulWidget {
const MainScreens({super.key});
@override
State<MainScreens> createState() => _MainScreensState();
}
class _MainScreensState extends State<MainScreens> {
int _selectedIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _selectedIndex,
children: [
// 0번 인덱스
Container(
child: Text(
'indexedStack0',
style: TextStyle(fontSize: 20, color: Colors.black),
),
),
// 1번 인덱스
Container(
color: Colors.redAccent[100],
child: Text(
'indexedStack1',
style: TextStyle(fontSize: 20, color: Colors.black),
),
),
],
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '홈'
),
BottomNavigationBarItem(
icon: Icon(Icons.chat_bubble),
label: '채팅'
),
],
onTap: (index) {
setState(() {
_selectedIndex = index;
});
},
currentIndex: _selectedIndex,
),
);
}
}
3단계
import 'package:flutter/material.dart';
class ChattingScreen extends StatelessWidget {
const ChattingScreen({super.key});
@override
Widget build(BuildContext context) {
return Text('chattingScreen');
}
}
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Text('HomeScreen');
}
}
홈 화면 만들기
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
children: [
const Text('좌동'),
const SizedBox(width: 4.0),
const Icon(CupertinoIcons.chevron_down),
],
),
actions: [
IconButton(
onPressed: () {},
icon: Icon(CupertinoIcons.search),
),
IconButton(
onPressed: () {},
icon: Icon(CupertinoIcons.list_dash),
),
IconButton(
onPressed: () {},
icon: Icon(CupertinoIcons.bell),
),
],
bottom: PreferredSize(
preferredSize: Size.fromHeight(0.5),
child: Divider(thickness: 0.5, height: 0.5, color: Colors.grey ),
),
),
);
}
}
샘플 데이터 확인
class Product {
String title;
String author;
String address;
String urlToImage;
String publishedAt;
String price;
int heartCount;
int commentsCount;
Product({
required this.title,
required this.author,
required this.address,
required this.urlToImage,
required this.publishedAt,
required this.price,
required this.heartCount,
required this.commentsCount,
});
}
// 샘플 데이터
List<Product> productList = [
Product(
title: '니트 조끼',
author: 'author_1',
urlToImage:
'https://github.com/flutter-coder/ui_images/blob/master/carrot_product_7.jpg?raw=true',
publishedAt: '2시간 전',
heartCount: 8,
price: '35000',
address: '좌동',
commentsCount: 3),
Product(
title: '먼나라 이웃나라 12',
author: 'author_2',
urlToImage:
'https://github.com/flutter-coder/ui_images/blob/master/carrot_product_6.jpg?raw=true',
publishedAt: '3시간 전',
heartCount: 3,
address: '중동',
price: '18000',
commentsCount: 1),
Product(
title: '캐나다구스 패딩조',
author: 'author_3',
address: '우동',
urlToImage:
'https://github.com/flutter-coder/ui_images/blob/master/carrot_product_5.jpg?raw=true',
publishedAt: '1일 전',
heartCount: 0,
price: '15000',
commentsCount: 12,
),
Product(
title: '유럽 여행',
author: 'author_4',
address: '우동',
urlToImage:
'https://github.com/flutter-coder/ui_images/blob/master/carrot_product_4.jpg?raw=true',
publishedAt: '3일 전',
heartCount: 4,
price: '15000',
commentsCount: 11,
),
Product(
title: '가죽 파우치 ',
author: 'author_5',
address: '우동',
urlToImage:
'https://github.com/flutter-coder/ui_images/blob/master/carrot_product_3.jpg?raw=true',
publishedAt: '1주일 전',
heartCount: 7,
price: '95000',
commentsCount: 4,
),
Product(
title: '노트북',
author: 'author_6',
address: '좌동',
urlToImage:
'https://github.com/flutter-coder/ui_images/blob/master/carrot_product_2.jpg?raw=true',
publishedAt: '5일 전',
heartCount: 4,
price: '115000',
commentsCount: 0,
),
Product(
title: '미개봉 아이패드',
author: 'author_7',
address: '좌동',
urlToImage:
'https://github.com/flutter-coder/ui_images/blob/master/carrot_product_1.jpg?raw=true',
publishedAt: '5일 전',
heartCount: 8,
price: '85000',
commentsCount: 3,
),
];
productItem
import 'package:carrot_market_ui/models/product.dart';
import 'package:flutter/material.dart';
class ProductItem extends StatelessWidget {
final Product product;
const ProductItem({required this.product, super.key});
@override
Widget build(BuildContext context) {
return Container(
height: 135.0,
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: Image.network(
product.urlToImage,
width: 115,
height: 115,
fit: BoxFit.cover,
),
)
],
),
);
}
}
임시 코드
import 'package:carrot_market_ui/screens/home/components/product_item.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../models/product.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
children: [
const Text('좌동'),
const SizedBox(width: 4.0),
const Icon(CupertinoIcons.chevron_down),
],
),
actions: [
IconButton(
onPressed: () {},
icon: Icon(CupertinoIcons.search),
),
IconButton(
onPressed: () {},
icon: Icon(CupertinoIcons.list_dash),
),
IconButton(
onPressed: () {},
icon: Icon(CupertinoIcons.bell),
),
],
bottom: PreferredSize(
preferredSize: Size.fromHeight(0.5),
child: Divider(thickness: 0.5, height: 0.5, color: Colors.grey ),
),
),
body: ProductItem(product: productList[0],),
);
}
}
product_detail.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../../models/product.dart';
class ProductDetail extends StatelessWidget {
final Product product;
const ProductDetail({required this.product, super.key});
@override
Widget build(BuildContext context) {
return Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
product.title,
style: TextStyle(fontSize: 16),
),
const SizedBox(height: 4.0),
Text(
' ${product.address} ‧ ${product.publishedAt}',
style: TextStyle(fontSize: 13),
),
const SizedBox(height: 4.0),
Text(
'${numberFormat(product.price)} 원',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Visibility(
visible: product.commentsCount > 0,
child: _buildIcons(
product.commentsCount,
CupertinoIcons.chat_bubble_2,
),
),
const SizedBox(width: 8.0),
Visibility(
visible: product.heartCount > 0,
child: _buildIcons(
product.heartCount,
CupertinoIcons.heart,
),
),
],
)
],
),
);
}
Widget _buildIcons(int count, IconData iconData) {
return Row(
children: [
Icon(iconData, size: 14.0),
const SizedBox(width: 4.0),
Text('${count}')
],
);
}
String numberFormat(String price) {
final formatter = NumberFormat('#,###');
return formatter.format(int.parse(price));
}
}
샘플 데이터
class ChatMessage {
final String sender;
final String profileImage;
final String location;
final String sendDate;
final String message;
final String? imageUri;
ChatMessage({
required this.sender,
required this.profileImage,
required this.location,
required this.sendDate,
required this.message,
this.imageUri,
});
}
// 샘플 데이터
List<ChatMessage> chatMessageList = [
ChatMessage(
sender: '당근이, ',
profileImage: 'https://picsum.photos/id/870/200/100?grayscale',
location: '대부동',
sendDate: '1일전',
message: 'developer 님,근처에 다양한 물품들이 아주 많이있습니다.',
),
ChatMessage(
sender: 'Flutter ',
profileImage: 'https://picsum.photos/id/880/200/100?grayscale',
location: '중동',
sendDate: '2일전',
message: '안녕하세요 지금 다 예약 상태 인가요?',
imageUri: 'https://picsum.photos/id/890/200/100?grayscale')
];
ChattingScreen
import 'package:carrot_market_ui/models/chatMessage.dart';
import 'package:carrot_market_ui/screens/chatting/components/chat_container.dart';
import 'package:flutter/material.dart';
class ChattingScreen extends StatelessWidget {
const ChattingScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('채팅'),
bottom: PreferredSize(
preferredSize: Size.fromHeight(0.5),
child: Divider(thickness: 0.5, height: 0.5, color: Colors.grey),
),
),
body: ListView(
children: List.generate(
chatMessageList.length,
(index) => ChatContainer(chatMessage: chatMessageList[index]),
),
),
);
}
}
chat_container
import 'package:carrot_market_ui/components/image_container.dart';
import 'package:flutter/material.dart';
import '../../../models/chatMessage.dart';
class ChatContainer extends StatelessWidget {
final ChatMessage chatMessage;
const ChatContainer({required this.chatMessage, super.key});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey, width: 0.5))),
height: 100,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Row(
children: [
ImageContainer(
borderRadius: 25,
imageUrl: chatMessage.profileImage,
width: 50,
height: 50,
),
const SizedBox(width: 16.0),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Spacer(),
Text.rich(
TextSpan(
children: [
TextSpan(
text: chatMessage.sender,
style: TextStyle(fontSize: 14),
),
TextSpan(
text: chatMessage.location,
style: TextStyle(fontSize: 12, color: Colors.grey),
),
TextSpan(
text: ' • ${chatMessage.sendDate}',
style: TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
),
Text(
chatMessage.message,
overflow: TextOverflow.ellipsis,
),
const Spacer()
],
),
),
/// 이미지 추가
Visibility(
visible: chatMessage.imageUri != null,
child: ImageContainer(
width: 50,
height: 50,
borderRadius: 8,
imageUrl: chatMessage.imageUri ?? '',
),
)
],
),
),
);
}
}
import 'package:flutter/material.dart';
class ImageContainer extends StatelessWidget {
final double borderRadius;
final String imageUrl;
final double width;
final double height;
const ImageContainer(
{required this.borderRadius,
required this.imageUrl,
required this.width,
required this.height});
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(borderRadius),
child: Image.network(
imageUrl,
width: width,
height: height,
fit: BoxFit.cover,
),
);
}
}
728x90
'Flutter' 카테고리의 다른 글
riverpod 과 MVVM 활용 - 플러터 프로젝트 생성(1) (0) | 2024.11.19 |
---|---|
riverpod 과 MVVM 활용 - riverpod 개념 정리 (1) | 2024.11.19 |
MVVM 패턴과 상태 관리 (0) | 2024.11.15 |
플러터 기본기 다지기 - 4 (Flutter의 위젯과 Element 트리 그리고 Key) (1) | 2024.11.15 |
플러터 기본기 다지기 - 4 (GestureDetector 위젯) (0) | 2024.11.14 |