1)
2) component
/card_title.dart
import 'package:flutter/material.dart';
class CardTitle extends StatelessWidget {
final String title;
final Color backgroundColor;
const CardTitle({
Key? key,
required this.title,
required this.backgroundColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
title,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.center,
),
),
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0),
),
),
);
}
}
/main_app_bar.dart
import 'package:dusty_dust/model/stat_model.dart';
import 'package:dusty_dust/model/status_model.dart';
import 'package:flutter/material.dart';
import 'package:dusty_dust/utils/data_utils.dart';
class MainAppBar extends StatelessWidget {
final StatModel stat;
final StatusModel status;
final String region;
final bool isExpanded;
const MainAppBar({
Key? key,
required this.stat,
required this.status,
required this.region,
required this.isExpanded,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final ts = TextStyle(
color: Colors.white,
fontSize: 30.0,
);
return SliverAppBar(
pinned: true,
title: isExpanded
? null
: Text(
'$region ${DataUtils.getTimeFromDateTime(dateTime: stat.dataTime)}'),
centerTitle: true,
expandedHeight: 500.0,
backgroundColor: status.primaryColor,
flexibleSpace: FlexibleSpaceBar(
background: SafeArea(
child: Container(
margin: EdgeInsets.only(
top: kToolbarHeight,
),
child: Column(
children: [
Text(
region,
style: ts.copyWith(
fontSize: 40.0,
fontWeight: FontWeight.w700,
),
),
Text(
DataUtils.getTimeFromDateTime(dateTime: stat.dataTime),
style: ts.copyWith(
fontSize: 20.0,
),
),
const SizedBox(height: 20.0),
Image.asset(
status.imagePath,
width: MediaQuery.of(context).size.width / 2,
),
const SizedBox(height: 20.0),
Text(
status.label,
style: ts.copyWith(
fontSize: 40.0,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 8.0),
Text(
status.comment,
style: ts.copyWith(
fontSize: 20.0,
fontWeight: FontWeight.w700,
),
),
],
),
),
),
),
);
}
}
/main_card.dart
import 'package:flutter/material.dart';
class MainCard extends StatelessWidget {
final Widget child;
final Color backgroundColor;
const MainCard({
Key? key,
required this.child,
required this.backgroundColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.symmetric(horizontal: 8.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(16.0),
),
),
color: backgroundColor,
child: child,
);
}
}
/main_drawer.dart
import 'package:flutter/material.dart';
import 'package:dusty_dust/const/regions.dart';
typedef OnRegionTap = void Function(String region);
class MainDrawer extends StatelessWidget {
final OnRegionTap onRegionTap;
final String region;
final Color lightColor;
final Color darkColor;
const MainDrawer({
Key? key,
required this.region,
required this.onRegionTap,
required this.lightColor,
required this.darkColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Drawer(
backgroundColor: darkColor,
child: ListView(
children: [
DrawerHeader(
child: Text(
'지역 선택',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
...regions
.map(
(e) => ListTile(
tileColor: Colors.white,
selectedColor: Colors.black,
selectedTileColor: lightColor,
selected: e == region,
onTap: () {
onRegionTap(e);
},
title: Text(
e,
),
),
)
.toList()
],
),
);
}
}
/main_stat.dart
import 'package:flutter/material.dart';
class MainStat extends StatelessWidget {
// 미세먼지 / 초미세먼지 등
final String category;
// 아이콘 위치 (경로)
final String imgPath;
// 오염 정도
final String level;
// 오염 수치
final String stat;
// 너비
final double width;
const MainStat({
Key? key,
required this.category,
required this.imgPath,
required this.level,
required this.stat,
required this.width,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final ts = TextStyle(
color: Colors.black,
);
return SizedBox(
width: width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
category,
style: ts,
),
SizedBox(height: 8.0),
Image.asset(
imgPath,
width: 50.0,
),
SizedBox(height: 8.0),
Text(
level,
style: ts,
),
Text(
stat,
style: ts,
),
],
),
);
}
}
3) container
/category_card.dart
import 'package:dusty_dust/component/card_title.dart';
import 'package:dusty_dust/component/main_card.dart';
import 'package:dusty_dust/utils/data_utils.dart';
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:dusty_dust/component/main_stat.dart';
import 'package:dusty_dust/model/stat_model.dart';
class CategoryCard extends StatelessWidget {
final String region;
final Color lightColor;
final Color darkColor;
const CategoryCard({
Key? key,
required this.region,
required this.lightColor,
required this.darkColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: 160.0,
child: MainCard(
backgroundColor: lightColor,
child: LayoutBuilder(builder: (context, constraint) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
CardTitle(
title: '종류별 통계',
backgroundColor: darkColor,
),
Expanded(
child: ListView(
scrollDirection: Axis.horizontal,
physics: PageScrollPhysics(),
children: ItemCode.values.map(
(ItemCode itemCode) {
return ValueListenableBuilder<Box>(
valueListenable:
Hive.box<StatModel>(itemCode.name).listenable(),
builder: (context, box, widget) {
final stat =
(box.values.toList().last as StatModel);
final status =
DataUtils.getStatusFromItemCodeAndValue(
value: stat.getLevelFromRegion(region),
itemCode: itemCode,
);
return MainStat(
category: DataUtils.getItemCodeKrString(
itemCode: itemCode),
imgPath: status.imagePath,
level: status.label,
stat: '${stat.getLevelFromRegion(
region,
)}${DataUtils.getUnitFromItemCode(
itemCode: itemCode,
)}',
width: constraint.maxWidth / 3,
);
},
);
},
).toList()),
)
],
);
}),
),
);
}
}
/hourly_card.dart
import 'package:dusty_dust/model/stat_model.dart';
import 'package:dusty_dust/utils/data_utils.dart';
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:dusty_dust/component/card_title.dart';
import 'package:dusty_dust/component/main_card.dart';
class HourlyCard extends StatelessWidget {
final Color darkColor;
final Color lightColor;
final String region;
final ItemCode itemCode;
const HourlyCard({
Key? key,
required this.darkColor,
required this.lightColor,
required this.region,
required this.itemCode,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return MainCard(
backgroundColor: lightColor,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
CardTitle(
title: '시간별 ${DataUtils.getItemCodeKrString(itemCode: itemCode)}',
backgroundColor: darkColor,
),
ValueListenableBuilder<Box>(
valueListenable: Hive.box<StatModel>(itemCode.name).listenable(),
builder: (context, box, widget) => Column(
children: box.values
.toList()
.reversed
.map(
(stat) => renderRow(stat: stat),
)
.toList(),
),
),
],
),
);
}
Widget renderRow({required StatModel stat}) {
final status = DataUtils.getStatusFromItemCodeAndValue(
value: stat.getLevelFromRegion(region),
itemCode: stat.itemCode,
);
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 4.0,
),
child: Row(
children: [
Expanded(
child: Text(
'${stat.dataTime.hour}시',
),
),
Expanded(
child: Image.asset(
status.imagePath,
height: 20.0,
),
),
Expanded(
child: Text(
status.label,
textAlign: TextAlign.right,
),
),
],
),
);
}
}
'개발이 좋아서 > Flutter가 좋아서' 카테고리의 다른 글
[flutter] 미세먼지 앱_마무리_repository, screen, utils, main (0) | 2023.02.07 |
---|---|
[flutter] 미세먼지 앱_마무리_const, model (0) | 2023.02.07 |
[flutter] 미세먼지 앱_Hive_연습 (0) | 2023.02.06 |
[flutter] 미세먼지 앱_데이터 모델링 (0) | 2023.01.31 |
[flutter] 미세먼지 앱_UI구현 (0) | 2023.01.31 |