ðFlutterã§åããŠã®ã¢ããª
èŠä»¶ã®ç¢ºèª
ä»åäœãã¢ããªã«ã€ããŠ
æ¥åžžã®ã¿ã¹ã¯ç®¡çã«äœ¿ããTODOã¢ããªãäœæããŸãã
TODOã¢ããªãšã¯ããããããšãªã¹ããã管çããã¢ããªã®ããšã§ããäŸãã°ïŒ
ãã¬ããŒããæžãã
ãè²·ãç©ã«è¡ãã
ãåéã«ã¡ãŒã«ãéãã
ãã®ãããªæ¥ã
ã®ã¿ã¹ã¯ãç»é²ããŠãå®äºããããã§ãã¯ãä»ããããšã§ãããã¹ãããšãæŽçã§ããŸãã
ã¢ããªã§ã§ããããš
äœæããTODOã¢ããªã§ã¯ã以äžã®ããšãã§ããŸãïŒ
ð ã¿ã¹ã¯ã®ç®¡ç
ã¿ã¹ã¯ã®äžèŠ§è¡šç€º: ç»é²ããã¿ã¹ã¯ããªã¹ã圢åŒã§ç¢ºèª
æ°ããã¿ã¹ã¯ã®è¿œå : æ°ãããããããšããã¢ããªã«ç»é²
å®äºã»æªå®äºã®åãæ¿ã: ã¿ã¹ã¯ãçµãã£ãããã§ãã¯ããŒã¯ãä»ãã
äžèŠãªã¿ã¹ã¯ã®åé€: å¿
èŠãªããªã£ãã¿ã¹ã¯ãåé€
ð¡ 䜿çšäŸ
æã®æºå
ãæã飯ãé£ã¹ããâ å®äºâ
ãæ¯ç£šãããããâ å®äºâ
ã倧åŠã®æºåããããâ æªå®äºâ
ãã®ããã«ãèŠèŠçã«ããããšãæŽçãããã®ã§ãå¿ãç©ã ããå¿ããé²ãããšãã§ããŸãã
ã¢ããªã®ç»é¢æ§æ
TODOã¢ããªã¯ãäž»ã«2ã€ã®ç»é¢ã§æ§æãããŸãïŒ
ð ã¡ã€ã³ç»é¢ïŒã¿ã¹ã¯äžèЧç»é¢ïŒ
ã¢ããªãéããæã«æåã«è¡šç€ºãããç»é¢ã§ãã
ç»é²ãããŠããã¿ã¹ã¯ã®äžèЧã衚瀺ããã
åã¿ã¹ã¯ã®å®äºã»æªå®äºãåãæ¿ãããã¿ã³
äžèŠã«ãªã£ãã¿ã¹ã¯ãåé€ãããã¿ã³
æ°ããã¿ã¹ã¯ã远å ããããã®ãïŒããã¿ã³
â ã¿ã¹ã¯è¿œå ç»é¢
æ°ããã¿ã¹ã¯ãå
¥åããç»é¢ã§ãã
ã¿ã¹ã¯ã®å
容ãå
¥åããããã¹ãããã¯ã¹
ãä¿åããã¿ã³ïŒå
¥åããã¿ã¹ã¯ãç»é²ïŒ
ããã£ã³ã»ã«ããã¿ã³ïŒå
¥åãåãæ¶ããŠã¡ã€ã³ç»é¢ã«æ»ãïŒ
ãã®2ã€ã®ç»é¢ãè¡ãæ¥ããããšã§ãã¿ã¹ã¯ã®ç®¡çãè¡ããŸãã
ã¿ã¹ã¯ã®æ å ±ã«ã€ããŠ
ã¢ããªã§ç®¡çããåã¿ã¹ã¯ã¯ã以äžã®3ã€ã®æ å ±ãæã¡ãŸãïŒ
ð èå¥çªå·ïŒIDïŒ
ã³ã³ãã¥ãŒã¿ãŒãã¿ã¹ã¯ãåºå¥ããããã®çªå·ã§ãã åãå
容ã®ã¿ã¹ã¯ãè€æ°ãã£ãŠãããã®çªå·ã§èŠåããããšãã§ããŸãã ïŒãŠãŒã¶ãŒã«ã¯è¡šç€ºãããŸããããã¢ããªã®å
éšã§éèŠãªåœ¹å²ãæãããŸãïŒ
ð ã¿ã¹ã¯ã®å
容ïŒã¿ã€ãã«ïŒ
å®éã«ããããšã®å
容ã§ããäŸïŒãã¬ããŒããæžãããè²·ãç©ã«è¡ãã
â
å®äºç¶æ
ãã®ã¿ã¹ã¯ãå®äºããŠãããã©ããã®æ
å ±ã§ãã
å®äºïŒâ
ïŒãã§ãã¯ããŒã¯ïŒ
æªå®äºïŒâïŒæªãã§ãã¯ïŒ
ãããã®æ
å ±ãçµã¿åãããããšã§ãå¹ççãªã¿ã¹ã¯ç®¡çãå¯èœã«ãªããŸãã
å®è£ ã®æŠèŠ
ã¢ããªã®ãã¡ã€ã«æ§æã«ã€ããŠ
ã¢ããªãäœãéã¯ãã³ãŒããæŽçæŽé ããããã«ã圹å²ããšã«ãã¡ã€ã«ãåããŠç®¡çããŸãã
ð ãã©ã«ããšãã¡ã€ã«ã®æ§æ
lib/ ïŒã¢ããªã®æ žãšãªããã©ã«ãïŒ
âââ main.dart ïŒã¢ããªã®éå§å°ç¹ïŒ
âââ models/ ïŒããŒã¿ã®èšèšå³ãã©ã«ãïŒ
â âââ todo.dart ïŒã¿ã¹ã¯ã®èšèšå³ïŒ
âââ screens/ ïŒç»é¢ãã©ã«ãïŒ
â âââ home_screen.dart ïŒã¡ã€ã³ç»é¢ïŒ
â âââ add_todo_screen.dart ïŒã¿ã¹ã¯è¿œå ç»é¢ïŒ
âââ widgets/ ïŒåå©çšã§ããéšåãã©ã«ãïŒ
â âââ todo_list.dart ïŒã¿ã¹ã¯ãªã¹ãéšåïŒ
â âââ todo_card.dart ïŒåå¥ã¿ã¹ã¯éšåïŒ
âââ services/ ïŒããŒã¿ç®¡çãã©ã«ãïŒ
âââ todo_service.dart ïŒããŒã¿ã®ä¿åã»èªã¿èŸŒã¿ïŒ
ð åãã¡ã€ã«ã®åœ¹å²
main.dart: ã¢ããªãæåã«å®è¡ããããã¡ã€ã«ïŒã¢ããªã®ãå
¥ãå£ãïŒ
screens/: ãŠãŒã¶ãŒãå®éã«èŠãç»é¢ã®ãã¡ã€ã«
models/: ããŒã¿ã®æ§é ãå®çŸ©ãããã¡ã€ã«ïŒã¿ã¹ã¯ãæã€æ
å ±ã®æ±ºãŸãïŒ
widgets/: ç»é¢ã®äžã§äœ¿ãåããéšåã®ãã¡ã€ã«
services/: ããŒã¿ã®ä¿åãèªã¿èŸŒã¿ãæ
åœãããã¡ã€ã«
éçºã®é²ãæ¹
ã¢ããªéçºã¯ãå®¶ã建ãŠãã®ãšäŒŒãŠããŸããåºç€ããé çªã«äœã£ãŠããå¿ èŠããããŸãã
ðïž æ®µéçãªéçºæé
- ãããžã§ã¯ãã®æ°èŠäœæ
åå°ã®æŽåïŒéçºç°å¢ã®æºåïŒ
åºæ¬çãªèšèšå³ã®æºå
2. TodoããŒãã®å®è£
建æã®æºåïŒåå©çšã§ããéšåã®äœæïŒ
ã¿ã¹ã¯ã衚瀺ããããã®åºæ¬çãªéšåäœã
3. ããŒã¿ã¢ãã«ã®å®è£
èšèšå³ã®è©³çްåïŒã¿ã¹ã¯ã®è©³çŽ°ãªæ§é ãæ±ºå®ïŒ
ããŒã¿ã®ä¿åæ¹æ³ã®æ±ºå®
4. Todoãªã¹ãç»é¢ã®å®è£
1ééšåã®å»ºèšïŒã¡ã€ã³ç»é¢ã®äœæïŒ
ã¿ã¹ã¯äžèЧã衚瀺ããç»é¢
5. Todo远å ç»é¢ã®å®è£
2ééšåã®å»ºèšïŒè¿œå ç»é¢ã®äœæïŒ
æ°ããã¿ã¹ã¯ãå
¥åããç»é¢
6. ç¶æ
管çã®å®è£
黿°ã»æ°Žéå·¥äºïŒç»é¢éã®é£æºïŒ
ããŒã¿ã®æŽæ°ãšãªã¢ã«ã¿ã€ã åæ
ãã®é åºã§é²ããããšã§ã確å®ã«ã¢ããªã宿ãããããšãã§ããŸãã
éçºã§å€§åãªãã€ã³ã
ã¢ããªéçºã§ã¯ã以äžã®3ã€ã®ãã€ã³ããç¹ã«éèŠã§ãïŒ
ðš ç»é¢ã®äœãæ¹ïŒUIå®è£
ïŒ
ãŠãŒã¶ãŒãå®éã«èŠãŠæäœããéšåãäœããŸãã
éšåå: åãæ©èœãäœåºŠã䜿ãåããããã«ãéšåãšããŠäœæ
ç»é¢æ§æ: åç»é¢ã®ã¬ã€ã¢ãŠããšèŠãç®ãèšèš
ç»é¢ç§»å: ãã¿ã³ãæŒããæã®ç»é¢ã®åãæ¿ã
äŸ: ãã¿ã¹ã¯ã衚瀺ããã«ãŒããã1ã€äœãã°ããããäœåã§ã䞊ã¹ãŠãªã¹ãã«ã§ããŸã
ð ããŒã¿ã®ç®¡çïŒç¶æ
管çïŒ
ã¢ããªãåçã«å€åããéšåã管çããŸãã
ãªã¢ã«ã¿ã€ã æŽæ°: ã¿ã¹ã¯ã远å ãããããã«ç»é¢ã«åæ
æ
å ±ã®å
±æ: éãç»é¢éã§ããŒã¿ãå
±æ
倿Žã®æ€ç¥: ããŒã¿ãå€ãã£ãæã«ç»é¢ãèªåæŽæ°
äŸ: æ°ããã¿ã¹ã¯ã远å ããããã¡ã€ã³ç»é¢ã®ãªã¹ãã«ãå³åº§ã«è¡šç€ºããã
ðŸ ããŒã¿ã®ä¿åïŒããŒã¿æ°žç¶åïŒ
ã¢ããªãéããŠãæ
å ±ãæ®ãããã«ããŸãã
èªåä¿å: ã¿ã¹ã¯ã远å ã»å€æŽãããèªåçã«ä¿å
埩å
: ã¢ããªãåèµ·åããæã«ååã®ããŒã¿ãèªã¿èŸŒã¿
äŸ: ã¢ããªãéããŠå床éããŠããååäœã£ãã¿ã¹ã¯ãã¡ãããšæ®ã£ãŠãã
éçºç°å¢æºåãšãããžã§ã¯ãäœæ
åã®ã¹ãããã§éçºã®å šäœåã«ã€ããŠçè§£ããŠããã ããã§ããããïŒ
ãã®ç« ã§ã¯ãå®éã«ã¢ããªéçºãå§ããããã®æºåãè¡ããŸããæ°ããäœæ¥å ŽãæŽããŠãTODOã¢ããªã®åºç€ãšãªããã¡ã€ã«ãäœæããã³ã³ãã¥ãŒã¿ãŒäžã§ã¢ããªãåäœããããšã確èªããŠãããŸãã
ð¯ ãã®ç« ã®ãŽãŒã«
TODOã¢ããªå°çšã®æ°ãããã©ã«ããšãã¡ã€ã«ãäœæãã
ä»®æ³ã®ã¹ããŒããã©ã³ïŒãšãã¥ã¬ãŒã¿ãŒïŒãèµ·åãã
åºæ¬çãªã¢ããªãã¹ããŒããã©ã³ã§åãããšã確èªãã
ð äœæ¥æé
1. æ°ããã¢ããªã®ãã©ã«ããäœæ
ãŸããä»åã®TODOã¢ããªå°çšã®ãã©ã«ããšãã¡ã€ã«ãäœæããŸãã ããã¯ãæ°ãããããžã§ã¯ããå§ããæã«ããŒããšææ¿å ·ãçšæãããããªãã®ã§ãã
ããã€ãäœææ¹æ³ãããã®ã§å¥œããªãã®ã§äœæããŠãã ãããäœæãããã©ã«ãã®å Žæã¯ä»»æã§ãã
ð» 1. ã³ãã³ãã®å®è¡
Android StudioãŸãã¯VSCodeã® ã³ãã³ãããã³ããïŒãŸãã¯ã¿ãŒããã«ïŒ ã§ä»¥äžãå ¥åããŠãã ããïŒ
flutter create todo_app
cd todo_app
ð ã³ãã³ãã®èª¬æ
flutter create todo_app: ãtodo_appããšããååã®æ°ããã¢ããªãäœæ
cd todo_app: äœæããããã©ã«ãã®äžã«ç§»å
ð» 2. VSCodeã®å Žåãã³ãã³ããã¬ããããäœæ
CommandïŒShiftïŒPãæŒããŠã³ãã³ããã¬ãããéã
ã³ãã³ããã¬ãããããFlutter: New Projectããéžæ
ãããžã§ã¯ãåãå
¥åïŒããã§ã¯ãtodo_appããšããŸãïŒ
ãããžã§ã¯ããäœæ
ð» 3. AndroidStudioã®å Žåãã¡ãã¥ãŒããäœæ
äžéšã®ããããŒã¡ãã¥ãŒãããFileãâãNewãâãNew Flutter Projectããéžæ
ãããžã§ã¯ãåãå
¥åïŒããã§ã¯ãtodo_appããšããŸãïŒ
ãããžã§ã¯ããäœæ
æåãããšããtodo_appããšãããã©ã«ããã§ãããã®äžã«ã¢ããªéçºã«å¿
èŠãªãã¡ã€ã«ãèªåçã«äœãããŸãã
2. äžèŠãªã³ãŒããåé€ããŠç©ºã®ç»é¢ãäœã
æ°ããçæããã Flutter ãããžã§ã¯ã㯠ã«ãŠã³ã¿ãŒã¢ããªã®ãµã³ãã«ã«ãªã£ãŠããŸãããã®ãŸãŸã§ã¯ Todo ã¢ããªãšã¯é¢ä¿ã®ãªããã¿ã³ãããžãã¯ãå«ãŸããŠãããããæå°æ§æãžãªã»ããããŸãããã
ãšãã£ã¿ãŒã§ lib/main.dart ãéããŸãã
æ¢åã® CounterApp ã MyHomePage ãªã© ã«ãŠã³ã¿ãŒé¢é£ã®ãŠã£ãžã§ããããã¹ãŠåé€ ããæ¬¡ã®ã³ãŒãã«çœ®ãæããŸãã
lib/main.dart (æå°æ§æ)
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Todo App',
home: Scaffold(
appBar: AppBar(title: const Text('Todo App')),
body: const Center(child: Text('ãããã Todo App ãž')),
),
);
}
}
ããã§ ã¢ããªãèµ·åããŠã空ã®ç»é¢ãšã¿ã€ãã«ããŒã ãã衚瀺ãããç¶æ ã«ãªããŸãã以éã®ã¹ãããã§å¿ èŠãªãŠã£ãžã§ãããå°ããã€è¿œå ããŠãããŸãã
3. ä»®æ³ã¹ããŒããã©ã³ã®æºå
æå°æ§æã«ãªã£ãã¢ããªãåäœããããšã確èªããŸãããã å®éã®ã¹ããŒããã©ã³ããªããŠããã³ã³ãã¥ãŒã¿ãŒäžã§ä»®æ³çãªã¹ããŒããã©ã³ãåããããšãã§ããŸãã ããããšãã¥ã¬ãŒã¿ãŒãšåŒã³ãŸãã
ð± å©çšå¯èœãªãšãã¥ã¬ãŒã¿ãŒã®ç¢ºèª
ãŸããã©ã®ãããªãšãã¥ã¬ãŒã¿ãŒã䜿ãããã確èªããŸãããïŒ
flutter emulators
ãã®ã³ãã³ãã§ã䜿çšå¯èœãªãšãã¥ã¬ãŒã¿ãŒã®äžèЧã衚瀺ãããŸãã
ð ãšãã¥ã¬ãŒã¿ãŒã®èµ·å
äžèЧããé©åãªãšãã¥ã¬ãŒã¿ãŒãéžãã§èµ·åããŸãïŒ
flutter emulators --launch <ãšãã¥ã¬ãŒã¿ãŒå>
äŸ:
flutter emulators --launch Pixel_7_API_34
VSCodeãAndroid Studioã®åã¡ãã¥ãŒãããšãã¥ã¬ãŒã¿ãŒãèµ·åããããšãå¯èœã§ãã
ãŸããã¢ããªå®è¡æã«ãšãã¥ã¬ãŒã¿ãŒãèµ·åããŠããªãå Žåã¯ããã®éçšã§ãšãã¥ã¬ãŒã¿ãŒãèµ·åããããšãã§ããŸãã
äžéšã®ããããŒã¡ãã¥ãŒãããRunãâãRun Without Debuggingããéžæ
ãšãã¥ã¬ãŒã¿ãŒã®éžæ
ã¢ããªãèµ·å
4. ãšãã¥ã¬ãŒã¿ãŒã®åäœç¢ºèª
ãšãã¥ã¬ãŒã¿ãŒãèµ·åãããã以äžã®ç¹ã確èªããŠãã ããïŒ
â
確èªãã€ã³ã
ç»é¢è¡šç€º: ã¹ããŒããã©ã³ã®ãããªç»é¢ã衚瀺ãããŠãã
ç»é¢ã®åã: 瞊åãã§è¡šç€ºãããŠãã
æäœæ§: ããŠã¹ã§ã¿ããæäœãã§ãã
ð§ ãšãã¥ã¬ãŒã¿ãŒã®èšå®å€æŽ
ãšãã¥ã¬ãŒã¿ãŒã®çš®é¡ã倿Žãããå Žåã¯ãAndroid Studioã®AVD Managerãã倿Žã§ããŸã
ç»é¢ãµã€ãºãæ§èœãªã©ã調æŽå¯èœã§ã
5. ã¢ããªã®å®è¡ãã¹ã
ãšãã¥ã¬ãŒã¿ãŒãæ£åžžã«åäœããŠããããšã確èªã§ããããå®éã«ã¢ããªãå®è¡ããŠã¿ãŸãããïŒ
flutter run
â±ïž å®è¡æéã«ã€ããŠ
ååå®è¡æã¯ãå¿
èŠãªãã¡ã€ã«ã®ããŠã³ããŒããšæºåã®ããã5ã10åçšåºŠãããå ŽåããããŸãã ã³ãŒããŒã§ã飲ã¿ãªãããæ°é·ã«ãåŸ
ã¡ãã ããâïž
6. åäœç¢ºèªãšãã¹ã
ã¢ããªãç¡äºã«èµ·åãããã以äžã確èªããŠã¿ãŸãããïŒ
ð± åºæ¬åäœã®ç¢ºèª
ã¢ããªã®èµ·å: ã¢ããªãæ£åžžã«è¡šç€ºããã
ç»é¢è¡šç€º: æåããã¿ã³ãèªãã倧ããã§è¡šç€ºããã
ã¢ããªèµ·ååŸã®ã€ã¡ãŒãž
説ææ
ð ïž ãã©ãã«ã·ã¥ãŒãã£ã³ã°
â ããããåé¡ãšè§£æ±ºæ¹æ³
åé¡: ãšãã¥ã¬ãŒã¿ãŒãèµ·åããªã
解決ç: Android Studioãåèµ·åããŠãAVD Managerããæåã§ãšãã¥ã¬ãŒã¿ãŒãèµ·å
åé¡: ã¢ããªã®å®è¡ã倱æãã
解決ç: flutter doctorã³ãã³ããã¿ãŒããã«ã§å®è¡ããéçºç°å¢ã«åé¡ããªãã確èª
åé¡: å®è¡ãéåžžã«é
ã
解決ç: ãšãã¥ã¬ãŒã¿ãŒã®èšå®ã§RAMãšCPUã®å²ãåœãŠãå¢ãã
pubspec.yaml ã®èšå®
Flutter ãããžã§ã¯ãã§ã¯ pubspec.yaml ãã¡ã€ã«ãã¢ããªã®ãèšèšå³ & ä»å ¥ããªã¹ããã®åœ¹å²ãæ ããŸããããã«ã¢ããªã§å©çšããããã±ãŒãžãã¢ã»ããïŒç»åããã©ã³ããªã©ïŒãããŒãžã§ã³æ å ±ãèšè¿°ããŠããããšã§ãããŒã å šå¡ãåãç°å¢ã§ãã«ãã§ããŸãã
ð¯ ãã®ç« ã®ãŽãŒã«
pubspec.yaml ã®åºæ¬æ§é ãçè§£ãã
Todo ã¢ããªã§å¿
èŠãšãªãäŸåããã±ãŒãžã远å ãã
ã³ãã³ãã§äŸåé¢ä¿ãã€ã³ã¹ããŒã«ãããšã©ãŒãçºçããªãããšã確èªãã
ããã±ãŒãžãšã¯ïŒ
Flutterã«ããããããã±ãŒãžããšã¯ãåå©çšå¯èœãªã³ãŒãã®ã²ãšãŸãšãŸããæããŸããDart ã§ã¯ pub.dev ãšããå ¬åŒãµã€ãã«å ¬éãããŠããã以äžã®èŠçŽ ãå«ãããšãã§ããŸãã
Dart ãœãŒã¹ã³ãŒãïŒã¯ã©ã¹ã颿°ããŠã£ãžã§ãããªã©ïŒ
ããã¥ã¡ã³ãããµã³ãã«ã³ãŒã
pubspec.yaml ã«ããã±ãŒãžåãšããŒãžã§ã³ãèšè¿°ãããšãflutter pub get ã³ãã³ãã§èªåçã«ããŠã³ããŒãã»çµã¿èŸŒã¿ãè¡ããããããžã§ã¯ãå
ã§ã€ã³ããŒãããŠå©çšã§ããããã«ãªããŸãã
ããã±ãŒãžã掻çšããçç±
Flutterã«éãããã¹ããã¢ããªéçºã§ã¯ãUI ã³ã³ããŒãã³ããç¶æ 管çãããŒã¿ããŒã¹ãèªèšŒãªã©ãããããçšéã«å¯Ÿå¿ããæ°åãã®ããã±ãŒãžãå ¬éãããŠããŸããæ¢åã®ããã±ãŒãžã掻çšããããšã§è€éãªæ©èœãäžããå®è£ ããæéãçããæ¬æ¥æ³šåãã¹ãéçºã«æéãå²ããŸãã
pubspec.yaml ã®äžèº«
ã¢ããªã®ãããžã§ã¯ããã©ã«ãã®çŽäžã«ãã pubspec.yaml ãéããŸãã
ãŸãã¯çæçŽåŸã® pubspec.yaml ããã£ãšçºããŠã¿ãŸãããã
pubspec.yaml (æç²)
name: todo_app
# ... çç¥ ...
environment:
sdk: '>=3.2.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
#dev_dependencies ã flutter éšåãç¶ã
dependencies: ã®äžã«ã¢ããªã䜿çšããå€éšããã±ãŒãžãåæããŠãããŸãã
Todo ã¢ããªã§è¿œå ããäŸåããã±ãŒãž
ããã±ãŒãž | çšé | åè |
---|---|---|
uuid | äžæãªIDãçæ | ããŒã¿ã¢ãã«ã§äœ¿çš |
shared_preferences | 端æ«ããŒã«ã«ã«ããŒã¿ãä¿å | ãã°ã€ã³æ å ±ãç°¡æèšå®ã®ä¿åã«äŸ¿å© |
intl | æ¥ä»ãã©ãŒããã | DateFormat ã§æ¥æ¬èªè¡šèš |
ããã§ã¯æ¬¡ã®ããã« pubspec.yaml ãžããã±ãŒãžã远å ããŠã¿ãŸãããã ã€ã³ãã³ãã®äœçœ®ã«ã¯ã泚æããŠãã ããã
pubspec.yaml (dependencies 远å åŸ)
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
# --- ãããã远å å ---
uuid: ^4.5.1
shared_preferences: ^2.5.3
intl: ^0.20.2
ðš ããŒãžã§ã³ã¯å·çæç¹ïŒ2025-06ïŒã§ã®äŸã§ããå®éã«ã¯ pub.dev ã§ææ°ããŒãžã§ã³ã確èªããŠãã ããã
ããã±ãŒãžãã€ã³ã¹ããŒã«ãã
ã¿ãŒããã«ã§ãããžã§ã¯ãçŽäžã«ç§»åããæ¬¡ã®ã³ãã³ããå®è¡ããŸãããã
flutter pub get
exit code 0 ãè¿ã£ãŠããŠãšã©ãŒãåºãªããã°æåã§ãã
ãããããšã©ãŒãšå¯ŸåŠæ³
ãšã©ãŒ | åå | 解決ç |
---|---|---|
"Because X depends on Y >=1.0.0 which requires SDK versionâŠ" | Dart / Flutter SDK ãå€ã | flutter upgrade ã§ã¢ããã°ã¬ãŒã |
"ProcessException: No such file or directory" | flutter ã³ãã³ããéã£ãŠãªã | PATH ã確èªãã¿ãŒããã«ãåèµ·å |
TodoããŒãã®å®è£
åã®ã¹ãããã§éçºç°å¢ã®æºåãšãããžã§ã¯ãäœæãå®äºããŸããã
ãã®ç« ã§ã¯ãå®è£ ã®æŠèŠã§èª¬æãã2çªç®ã®ã¹ããããTodoããŒãã®å®è£ ããè¡ããŸããTODOã¢ããªã§ç¹°ãè¿ã䜿çšããåºæ¬çãªéšåïŒã³ã³ããŒãã³ãïŒãäœæããŠãããŸãã
ð¯ ãã®ç« ã®ãŽãŒã«
åå©çšå¯èœãªéšåã®æŠå¿µãçè§£ãã
TODOããŒã¿ã®èšèšå³ãäœæãã
TODOã衚瀺ããããã®ã«ãŒãéšåãäœæãã
å¹ççãªéçºææ³ã身ã«ã€ãã
宿ã³ã³ããŒãã³ãã®ã€ã¡ãŒãž
説ææ
ð§© ãã³ã³ããŒãã³ããã£ãŠãªã«ïŒ
ã¢ããªéçºã«ããããã³ã³ããŒãã³ãããšã¯ãäœåºŠã䜿ãåããéšåã®ããšã§ãã
ðŠ æ¥åžžç掻ã§ã®äŸ
ã¬ãŽãããã¯ãæãæµ®ãã¹ãŠãã ããïŒ
åºæ¬ãããã¯: åã圢ã®éšåãäœåãçµã¿åãããŠå€§ããªäœåãäœã
åå©çš: äžåºŠäœã£ãéšåã¯ãå¥ã®å Žæã§ã䜿ãåãã
å¹çæ§: æ¯åãŒãããäœããããæ¢åã®éšåãæŽ»çšããæ¹ãæ©ã
ã¢ããªéçºã§ãåãã§ãããã¿ã¹ã¯ã衚瀺ããã«ãŒããã1ã€äœãã°ããããäœåã䞊ã¹ãŠãªã¹ãã«ã§ããŸãã
ð ããŒãåã®ã¡ãªãã
äœæ¥å¹ç: äžåºŠäœãã°äœåºŠã§ã䜿ãã
çµ±äžæ§: èŠãç®ãã¹ã¿ã€ã«ãçµ±äžããã
ä¿å®æ§: ä¿®æ£ãå¿
èŠãªæã¯1ç®æãå€ããã ãã§å
šäœã«åæ
ð äœæ¥æé
1. TODOããŒã¿ã®èšèšå³ãäœæ
ð ãã©ã«ããšãã¡ã€ã«ãæºå
ãŸãã¯ã³ãŒããé
眮ããããã®ãã©ã«ããšãã¡ã€ã«ãäœæããŸããæçµçãªæ§æã€ã¡ãŒãžã¯ä»¥äžã®ãšããã§ãã
ãããžã§ã¯ãå
ã®ãã£ã¬ã¯ããªæ§æ
lib/ ã¢ããªã®æ žãšãªããã©ã«ã
âââ main.dart ã¢ããªã®éå§å°ç¹
âââ models/ ããŒã¿ã®èšèšå³ã眮ããã©ã«ã
â âââ todo.dart ã¿ã¹ã¯ã®èšèšå³ãã¡ã€ã«ïŒãã®ç« ã§å®è£
ïŒ
ãã©ã«ãããã¡ã€ã«ã®äœæã¯ãVSCodeãAndroid Studioã®åã¡ãã¥ãŒããè¡ããŸãã
CreateNew
ããã§ todo.dart ã« Todo ã¯ã©ã¹ãæžããæºåãæŽããŸããã
ðïž Todoã¯ã©ã¹ã®äœæ
class Todo {
final String title; // ã¿ã¹ã¯ã®ã¿ã€ãã«ïŒäŸïŒãã¬ããŒããæžããïŒ
final String detail; // ã¿ã¹ã¯ã®è©³çްïŒäŸïŒãå¿çåŠã®ã¬ããŒãã2000åãïŒ
final DateTime dueDate; // ææ¥ïŒäŸïŒDateTime(2025, 4, 1)ïŒ
final bool isCompleted; // ãã§ãã¯æžã¿ãã©ããïŒtrue: å®äº, false: æªå®äºïŒ
// ã³ã³ã¹ãã©ã¯ã¿ïŒTODOãäœæããæã®æ±ºãŸãïŒ
Todo({
required this.title, // ã¿ã€ãã«ã¯å¿
é
required this.detail, // 詳现ãå¿
é
required this.dueDate, // ææ¥ãå¿
é
this.isCompleted = false, // ããã©ã«ãã¯ãæªå®äºã
});
}
ð ã³ãŒãã®èª¬æ
class Todo: ãTodoããšããæ°ããããŒã¿åãå®çŸ©
final String title: ã¿ã€ãã«æååïŒå€æŽäžå¯ïŒ
final String detail: 詳现æååïŒå€æŽäžå¯ïŒ
final DateTime dueDate: ææ¥ïŒDateTimeåã倿Žäžå¯ïŒ
final bool isCompleted: ãã§ãã¯ããã¯ã¹ã®ç¶æ
ïŒå®äºãªãtrueïŒ
required: å¿
ãæå®ããå¿
èŠãããé
ç®ïŒisCompletedã¯ããã©ã«ãã§falseãªã®ã§ä»»æïŒ
2. TODOã«ãŒãéšåã®äœæ
次ã«ãTODOããŒã¿ãç»é¢ã«è¡šç€ºããããã®ãã«ãŒããéšåãäœæããŸãã
宿ã³ã³ããŒãã³ãã®ã€ã¡ãŒãž
説ææ
ð todo_card.dartãã¡ã€ã«ãæºå
todo.dartãã¡ã€ã«ãšåãããã«ãwidgetsãã©ã«ãã«todo_card.dartãã¡ã€ã«ãäœæããŸãã
ãããžã§ã¯ãå
ã®ãã£ã¬ã¯ããªæ§æ
lib/ ã¢ããªã®æ žãšãªããã©ã«ã
âââ main.dart ã¢ããªã®éå§å°ç¹
âââ widgets/
â âââ todo_card.dart
ããã§ todo_card.dart ã« TodoCard ã¯ã©ã¹ãæžããæºåãæŽããŸããã
ðŽ TodoCardãŠã£ãžã§ããã®äœæ
import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; // æ¥ä»ãã©ãŒãããçšããã±ãŒãž
class TodoCard extends StatelessWidget {
final Todo todo; // 衚瀺ãã Todo ããŒã¿
final VoidCallback? onToggle; // å®äºãã°ã«çšã³ãŒã«ããã¯ïŒä»»æïŒ
const TodoCard({
super.key,
required this.todo,
this.onToggle,
});
@override
Widget build(BuildContext context) {
return Card(
color: Colors.blue,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
elevation: 8,
child: SizedBox(
width: double.infinity,
height: 150,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// ââ 巊端ïŒãã§ãã¯ã¢ã€ã³ã³ïŒã¿ããã§ãã°ã«ïŒ
IconButton(
iconSize: 32,
icon: Icon(
todo.isCompleted
? Icons.check_circle // ãã§ãã¯æžã¿
: Icons.radio_button_unchecked, // æªãã§ãã¯
color: Colors.white,
),
onPressed: onToggle,
),
const SizedBox(width: 8),
// ââ ããã¹ã矀
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
todo.title,
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
Text(
todo.detail,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.white70,
fontSize: 16,
),
),
Text(
DateFormat('Mædæ¥(E)').format(todo.dueDate),
style: TextStyle(
color: Colors.white70,
fontSize: 16,
),
),
],
),
),
],
),
),
);
}
}
ð ã³ãŒãã®èª¬æ
StatelessWidget â ç¶æ
ãæããªãåå©çšå¯èœãªãŠã£ãžã§ããã
Card â è§äžžãšåœ±ãåããã«ãŒãåã®ã³ã³ããã
IconButton â ã¢ã€ã³ã³ãã¿ããå¯èœãªãã¿ã³ã«ãããŠã£ãžã§ãããããã§ã¯ãã§ãã¯ç¶æ
ã®åãæ¿ãã«äœ¿çšã
Icons.check_circle / Icons.radio_button_unchecked â Flutter å
¬åŒã®ã¢ã€ã³ã³ãå®äºïŒæªå®äºã§ã¢ã€ã³ã³ãåãæ¿ããã
Column + Expanded â ããã¹ãã瞊æ¹åã«ç©ã¿ãäœã£ãå¹
ãå æãããã¬ã€ã¢ãŠãã
Text â ã¿ã€ãã«ã»èª¬æã»ææ¥ã衚瀺ãããããè²ããµã€ãºã調æŽããŠèŠèªæ§ãé«ããŠããã
todo ãããã㣠â Todo ã¢ãã«ãåãåããã«ãŒãå
éšã®æèšãåçã«çæã
Column + Expanded â ããã¹ãã瞊æ¹åã«ç©ã¿ãäœã£ãå¹
ãå æãããã¬ã€ã¢ãŠãã
Text â todo.title / todo.detail / todo.dueDate ã衚瀺ããå
容ã«å¿ããŠèªååæ ã
intl ããã±ãŒãžïŒDateFormatïŒ â todo.dueDate ãã12æ30æ¥(æ)ãã®ãããªè¡šèšã«å€æã
3. å®éã®äœ¿çšäŸ
äœæããããŒãã¯ä»¥äžã®ããã«äœ¿çšã§ããŸãïŒ
// TODOããŒã¿ãäœæ
Todo myTodo = Todo(
title: "è±èªã®å®¿é¡",
detail: "æç§æžã®p.50-60ãèªãã§èŠçŽãã",
dueDate: DateTime(2025, 12, 30),
isCompleted: false, // ãŸã å®äºããŠããªã
);
// ã«ãŒãéšåã§TODOã衚瀺
TodoCard(todo: myTodo)
4. TodoCard ãã¢ããªã«è¡šç€ºããŠã¿ãã
æåŸã«ãäœæãã TodoCard ãå®éã®ã¢ããªç»é¢ã«è¡šç€ºãããã確èªããŸãã
ð main.dart ã«ãŠã£ãžã§ãããèªã¿èŸŒã
1.lib/main.dart ãéããŸãã
2.MaterialApp ã® home ã« TodoCard ãé
眮ããŸãããã
â»æ¬æ¥ã¯è€æ°ã® TodoCard ããªã¹ãã§è¡šç€ºããŸãããããã§ã¯TodoCardãæ£ãã衚瀺ãããã確èªããããã«1ã€ã®ã«ãŒãã衚瀺ããŸãã
lib/main.dart
import 'package:flutter/material.dart';
import 'widgets/todo_card.dart'; // 远å : TodoCard ãã€ã³ããŒã
import 'models/todo.dart'; // Todo ã¢ãã«ãã€ã³ããŒã
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Todo App',
home: Scaffold(
appBar: AppBar(title: const Text('Todo App')),
body: Center(
child: TodoCard(
todo: Todo(
title: 'ãã¹ãã¿ã€ãã«',
detail: '説ææ',
dueDate: DateTime.now(),
),
onToggle: () {},
),
),
),
);
}
}
ã¿ãŒããã«ã§æ¬¡ã®ã³ãã³ããå®è¡ãããšãã¥ã¬ãŒã¿ãŒäžã«ã«ãŒãã衚瀺ãããããšã確èªããŠãã ããã
flutter run
â éãã«ãŒããšæªå®äºã®ãã§ãã¯ã¢ã€ã³ã³ãã¿ã¹ã¯ã®ã¿ã€ãã«ãªã©ã衚瀺ãããã°æåã§ãïŒ
ã«ãŒãã®è¡šç€º
ð¡ å®è£
ã®ãã€ã³ã
ð·ïž åãããããååãã€ãã
ã»Good: Todo, TodoCard, title, detail
ã»Bad: Data, Widget1, str1, str2
ååãèŠãã ãã§ãäœã®ããã®ãã®ããåããããã«ããŸãããã
ð§ requiredïŒå¿
é ïŒã®æŽ»çš
requiredããŒã¯ãŒãã䜿ãããšã§ãéèŠãªæ
å ±ã®å
¥åãå¿ããé²ããŸãã ããã¯ãã¢ã³ã±ãŒãã®ãå¿
é é
ç®ããšåãä»çµã¿ã§ãã
ðš çµ±äžããããã¶ã€ã³
CardãListTileã䜿ãããšã§ãAndroidã»iOSã®æšæºçãªãã¶ã€ã³ãé©çšããããŠãŒã¶ãŒã«ãšã£ãŠäœ¿ããããUIã«ãªããŸãã
ããŒã¿ã¢ãã«ã®å®è£
åã®ã¹ãããã§TodoããŒãïŒéšåïŒã®åºæ¬çãªå®è£ ãå®äºããŸããã
ãã®ç« ã§ã¯ãå®è£ ã®æŠèŠã§èª¬æãã3çªç®ã®ã¹ããããããŒã¿ã¢ãã«ã®å®è£ ããè¡ããŸããååäœã£ãåºæ¬çãªèšèšå³ãããã«çºå±ãããŠãããæ¬æ ŒçãªããŒã¿ç®¡çã®ä»çµã¿ãäœã£ãŠãããŸãã
ð¯ ãã®ç« ã®ãŽãŒã«
æ¬æ ŒçãªTodoã¢ãã«ãäœæããå®çšçãªããŒã¿æ§é ãå®çŸ©ãã
ããŒã¿ç®¡çãµãŒãã¹ãå®è£
ããããŒã¿ã®ä¿åã»èªã¿èŸŒã¿ãå¯èœã«ãã
éåæåŠçã®æŠå¿µãçè§£ããå®è£
ãã
ðïž ããŒã¿ã¢ãã«ã£ãŠäœïŒ
ð äŸïŒå³æžé€šã®æ¬ã®ç®¡ç
峿žé€šã§æ¬ã管çããããšãèããŠã¿ãŸãããïŒ
æ¬ã®æ
å ±: ã¿ã€ãã«ãèè
ãISBNïŒèå¥çªå·ïŒã貞åºç¶æ³
管çã·ã¹ãã : æ¬ãæ¢ãã貞ãåºããè¿åŽãããæ°ããæ¬ãç»é²ãã
æ°žç¶å: ã·ã¹ãã ãéããŠããæ¬ã®æ
å ±ã¯æ®ã£ãŠãã
TODOã¢ããªã§ãåãããã«ãã¿ã¹ã¯ã®æ
å ±ãäœç³»çã«ç®¡çããä»çµã¿ãå¿
èŠã§ãã
ð äœæ¥æé
1. æ¬æ ŒçãªTodoã¢ãã«ã®äœæ
ååã®åºæ¬çãçºå±ãããŠãå®çšçãªæ©èœã远å ããŸãã
ð ãªãIDãå¿
èŠïŒ
ãŸãããªãåã¿ã¹ã¯ã«ãIDããšããèå¥çªå·ãå¿
èŠãªã®ããçè§£ããŸãããã
äŸïŒã¯ã©ã¹ã®åºåžç®¡ç
åãååã®åŠçã2人ããå ŽåãåŠç±çªå·ã§åºå¥ãã
ãç°äžãããã ãã§ã¯ãã©ã¡ãã®ç°äžãããåãããªã
åŠç±çªå·ãããã°ã確å®ã«å人ãç¹å®ã§ãã
TODOã¢ããªã§ãåæ§ã«ãåãã¿ã€ãã«ã®ã¿ã¹ã¯ãè€æ°ãã£ãŠããIDã§åºå¥ã§ããŸãã
ðïž æ¹è¯çTodoã¯ã©ã¹ã®äœæ
lib/models/todo.dartãã¡ã€ã«ãç·šéããŸãïŒ
import 'package:uuid/uuid.dart'; // äžæãªIDãçæããã©ã€ãã©ãª
class Todo {
final String id; // åã¿ã¹ã¯ã®åºæèå¥çªå·
final String title; // ã¿ã¹ã¯ã®ã¿ã€ãã«ïŒäŸïŒãã¬ããŒããæžããïŒ
final String detail; // ã¿ã¹ã¯ã®è©³çްïŒäŸïŒãå¿çåŠã®ã¬ããŒãã2000åãïŒ
final DateTime dueDate; // ææ¥ïŒäŸïŒDateTime(2025, 4, 1)ïŒ
final bool isCompleted; // ãã§ãã¯æžã¿ãã©ããïŒtrue: å®äº, false: æªå®äºïŒ
Todo({
String? id, // IDãæå®ãããªãå Žåã¯èªåçæ
required this.title, // ã¿ã€ãã«ã¯å¿
é
required this.detail, // 詳现ãå¿
é
required this.dueDate, // ææ¥ãå¿
é
this.isCompleted = false, // ããã©ã«ãã¯ãæªå®äºã
}) : id = id ?? const Uuid().v4(); // IDã®èªåçæ
// æ¢åã®Todoãäžéšå€æŽããã³ããŒãäœæããã¡ãœãã
Todo copyWith({
String? title,
String? detail,
DateTime? dueDate,
bool? isCompleted,
}) {
return Todo(
id: id, // IDã¯å€æŽããªã
title: title ?? this.title, // æ°ããã¿ã€ãã« or å
ã®ã¿ã€ãã«
detail: detail ?? this.detail, // æ°ãã詳现 or å
ã®è©³çް
dueDate: dueDate ?? this.dueDate, // æ°ããææ¥ or å
ã®ææ¥ã¯å€æŽããªã
isCompleted: isCompleted ?? this.isCompleted, // æ°ããç¶æ
or å
ã®ç¶æ
);
}
}
ð ã³ãŒãã®è©³çŽ°èª¬æ
IDã®èªåçæ
id = id ?? const Uuid().v4();
ã»?? ã¯ãããå·ŠåŽãnullãªãå³åŽã䜿ãããšããæå³
ã»Uuid().v4() ã¯äžçäžã§éè€ããªãäžæãªIDãçæ
copyWithã¡ãœããã®æå³
Todo copyWith({String? title, bool? isCompleted})
ã»æ¢åã®Todoã®æ
å ±ãä¿æãã€ã€ãäžéšã ãã倿Žããæ°ããTodoãäœæ
ã»äŸïŒã¿ã¹ã¯ã®å®äºç¶æ
ã ãã倿Žãããæã«äœ¿çš
å®éã®äœ¿çšäŸ
// æ°ããã¿ã¹ã¯ãäœæ
Todo task = Todo(title: "ã¬ããŒããæžã");
// ã¿ã¹ã¯ãå®äºã«å€æŽïŒå
ã®taskã¯å€æŽãããæ°ããã€ã³ã¹ã¿ã³ã¹ãäœæïŒ
Todo completedTask = task.copyWith(isCompleted: true);
2. ããŒã¿ç®¡çãµãŒãã¹ã®äœæ
次ã«ãTODOããŒã¿ãä¿åã»èªã¿èŸŒã¿ããããµãŒãã¹ããäœæããŸãã
ð± ã¹ããŒããã©ã³ã«ããŒã¿ãä¿åããæ¹æ³
ã¹ããŒããã©ã³ã«ããŒã¿ãä¿åããæ¹æ³ã¯ããã€ããããŸãããä»åã¯SharedPreferencesãšããããã±ãŒãžã䜿ããŸãã
äŸïŒã¢ããªã®èšå®æ å ±
ã»èšèªèšå®ãããŒãèšå®ããã°ã€ã³æ
å ±ãªã©
ã»ã¢ããªãéããŠã次åèµ·åæã«åŸ©å
ããã
ã»ç°¡åãªããŒã¿ã®ä¿åã«é©ããŠãã
â° éåæåŠçã£ãŠäœïŒ
åæåŠçïŒæ®éã®åŠçïŒ
ã»A â B â C ã®é çªã§å®è¡
ã»AãçµãããŸã§Bã¯åŸ
æ©
éåæåŠç
ã»æéã®ãããäœæ¥ïŒããŒã¿ä¿åã»èªã¿èŸŒã¿ïŒãå¥ã§å®è¡
ã»ã¡ã€ã³ã®åŠçã¯æ¢ãŸããªã
ã»å®äºãããçµæãåãåã
æ¥åžžäŸïŒã¬ã¹ãã©ã³ã§ã®æ³šæ
ã»ð« åæ: äžäººã®æ³šæãå®å
šã«çµãããŸã§æ¬¡ã®äººã¯æ³šæã§ããªã
ã»â
éåæ: è€æ°ã®æ³šæãåæã«åããŠãã§ããé çªã§æäŸ
ð ïž TodoServiceã®å®è£
lib/services/todo_service.dartãã¡ã€ã«ãäœæããŸãïŒ
ãããžã§ã¯ãå
ã®ãã£ã¬ã¯ããªæ§æ
lib/ ã¢ããªã®æ žãšãªããã©ã«ã
âââ main.dart ã¢ããªã®éå§å°ç¹
âââ services/ ïŒããŒã¿ç®¡çãã©ã«ãïŒ
âââ todo_service.dart ïŒããŒã¿ã®ä¿åã»èªã¿èŸŒã¿ïŒ
import 'dart:convert'; // JSONããŒã¿ã®å€æçš
import 'package:shared_preferences/shared_preferences.dart'; // ããŒã¿ä¿åçš
import '../models/todo.dart'; // äœæããTodoã¯ã©ã¹ã䜿çš
class TodoService {
static const String _storageKey = 'todos'; // ä¿åæã®ããŒå
final SharedPreferences _prefs; // ããŒã¿ä¿åã®ä»çµã¿
TodoService(this._prefs);
// ä¿åãããŠããTODOãªã¹ããèªã¿èŸŒãïŒéåæåŠçïŒ
Future<List<Todo>> getTodos() async {
// ä¿åãããŠããJSONããŒã¿ãååŸ
final String? todosJson = _prefs.getString(_storageKey);
// ããŒã¿ããªãå Žåã¯ç©ºã®ãªã¹ããè¿ã
if (todosJson == null) return [];
// JSONæååãDartã®ãªããžã§ã¯ãã«å€æ
final List<dynamic> decoded = jsonDecode(todosJson);
// åããŒã¿ãTodoãªããžã§ã¯ãã«å€æããŠãªã¹ãã«ãã
return decoded
.map((json) => Todo(
id: json['id'],
title: json['title'],
detail: json['detail'] ?? '', // detailããªãå Žåã¯ç©ºæå
dueDate: DateTime.parse(json['dueDate'] ??
DateTime.now().toIso8601String()), // dueDateããªãå Žåã¯çŸå𿥿
isCompleted: json['isCompleted'],
))
.toList();
}
// TODOãªã¹ããä¿åããïŒéåæåŠçïŒ
Future<void> saveTodos(List<Todo> todos) async {
// Todoãªããžã§ã¯ããJSONã«å€æã§ãã圢ã«å€æ
final List<Map<String, dynamic>> encoded = todos
.map((todo) => {
'id': todo.id,
'title': todo.title,
'detail': todo.detail,
'dueDate':
todo.dueDate.toIso8601String(), // DateTimeãISO8601圢åŒã®æååã«å€æ
'isCompleted': todo.isCompleted,
})
.toList();
// JSONæååã«å€æããŠä¿å
await _prefs.setString(_storageKey, jsonEncode(encoded));
}
}
ð æè¡çšèªã®èª¬æ
JSONïŒãžã§ã€ãœã³ïŒ
JavaScript Object Notationã®ç¥
ããŒã¿ãæååã§è¡šçŸããæ¹æ³
äŸïŒ{"name": "ç°äž", "age": 20}
async/await
éåæåŠçãåãããããæžãããã®ããŒã¯ãŒã
async: ãã®é¢æ°ã¯éåæåŠçãå«ã
await: ãã®åŠçã®å®äºãåŸ
ã€
Future
ãå°æ¥å€ãè¿ãããäºå®ãã衚ãããŒã¿å
æéã®ãããåŠçïŒãã¡ã€ã«èªã¿èŸŒã¿ããããã¯ãŒã¯éä¿¡ãªã©ïŒã§äœ¿çš
3. å®éã®äœ¿çšäŸ
äœæãããµãŒãã¹ã®äœ¿ç𿹿³ïŒ
// ãµãŒãã¹ã®åæå
SharedPreferences prefs = await SharedPreferences.getInstance();
TodoService todoService = TodoService(prefs);
// ããŒã¿ã®èªã¿èŸŒã¿
List<Todo> todoList = await todoService.getTodos();
// æ°ããã¿ã¹ã¯ã远å
todoList.add(Todo(title: "æ°ããã¿ã¹ã¯", detail: "æ°ããã¿ã¹ã¯ã®è©³çް", dueDate: DateTime.now(), isCompleted: false));
// ããŒã¿ã®ä¿å
await todoService.saveTodos(todoList);
ð¡ å®è£ ã®ãã€ã³ã
ð ããŒã¿ã®å®å šæ§
äžå€æ§: äžåºŠäœã£ããªããžã§ã¯ãã¯å€æŽãããæ°ãããªããžã§ã¯ããäœæ
åå®å
š: æ£ããããŒã¿åã®ã¿ãåãå
¥ãã
â¡ å¹çæ§
éåæåŠç: UIãããªãŒãºããªã
é©åãªããŒã¿æ§é : å¿
èŠãªæ
å ±ã ããä¿å
ð§ ä¿å®æ§
責任ã®åé¢: ããŒã¿ç®¡çã¯Serviceã¯ã©ã¹ãæ
åœ
åå©çšæ§: ä»ã®ç»é¢ãããåããµãŒãã¹ã䜿çšå¯èœ
Todoãªã¹ãç»é¢ã®å®è£
åã®ã¹ãããã§ããŒã¿ã¢ãã«ã®å®è£ ãå®äºããŸããã
ãã®ç« ã§ã¯ãå®è£ ã®æŠèŠã§èª¬æãã4çªç®ã®ã¹ããããTodoãªã¹ãç»é¢ã®å®è£ ããè¡ããŸãããããŸã§äœæããããŒã¿ã¢ãã«ãšããŒããçµã¿åãããŠãå®éã«Todoãªã¹ããç»é¢ã«è¡šç€ºããæ©èœãå®è£ ããŠãããŸãã
ð¯ ãã®ç« ã®ãŽãŒã«
Todoãªã¹ãç»é¢ãå®è£
ããè€æ°ã®ã¿ã¹ã¯ãäžèŠ§è¡šç€ºãã
ListViewã䜿ã£ãã¹ã¯ããŒã«å¯èœãªãªã¹ã衚瀺ãçè§£ãã
äœæããTodoããŒããå®éã«æŽ»çšãã
åçãªãªã¹ãçæã®ä»çµã¿ãåŠã¶
宿ãªã¹ã衚瀺ã®ã€ã¡ãŒãž
ãªã¹ãã®è¡šç€º
ð ãªã¹ã衚瀺ã£ãŠäœïŒ
ð äŸïŒæ¬æ£ã®æŽç
æ¬æ£ã§æ¬ãæŽçããããšãèããŠã¿ãŸãããïŒ
瞊ã«äžŠã¹ã: æ¬ã瞊ã«ç©ã¿éããŠæŽç
åã圢åŒ: å
šãŠã®æ¬ãåãããã«è¡šç€ºããã
ã¹ã¯ããŒã«: æ¬ãå€ãå Žåã¯äžäžã«èŠãç¯å²ãç§»å
å¹çç: äžã€ã®ã¬ã€ã¢ãŠãã§å€ãã®æ
å ±ã衚瀺
TODOã¢ããªã§ãåæ§ã«ãè€æ°ã®ã¿ã¹ã¯ãå¹ççã«äžèŠ§è¡šç€ºããå¿
èŠããããŸãã
ð¯ ãªããªã¹ã衚瀺ãéèŠïŒ
å¹ççãªæ å ±è¡šç€º
1ã€ã®ç»é¢ã§å€ãã®ã¿ã¹ã¯ã確èªå¯èœ
äžè²«ãããã¶ã€ã³ã§èŠããã
ã¹ã¯ããŒã«ã§å
šãŠã®ã¿ã¹ã¯ã«ã¢ã¯ã»ã¹å¯èœ
ð äœæ¥æé
ãŸããTodoCardãå©çšããŠãªã¹ãã衚瀺ããã³ã³ããŒãã³ããäœæããŸãã
1. ãªã¹ã衚瀺ã®ä»çµã¿ãçè§£ãã
ðïž ListViewã®åºæ¬æŠå¿µ
ListViewã¯ãã¹ããŒããã©ã³ã¢ããªã§ãã䜿ããããªã¹ã衚瀺ã®ä»çµã¿ã§ãã
æ¥åžžäŸïŒãã¥ãŒã¹ã¢ããª
èšäºã®ã¿ã€ãã«ã瞊ã«äžŠãã§ãã
åããã©ãŒãããã§è¡šç€ºããã
äžäžã«ã¹ã¯ããŒã«ããŠå
šèšäºãèŠããã
æ°ããèšäºã远å ããããšèªåçã«ãªã¹ãã«è¡šç€º
ð ListView.builderã®ç¹åŸŽ
ListView.builder(
itemCount: todos.length, // 衚瀺ããé
ç®ã®æ°
itemBuilder: (context, index) { // åé
ç®ãäœããå·¥å Žã
return TodoCard(todo: todos[index]);
},
)
builderãã¿ãŒã³ã®äŸïŒãåŒåœå·¥å Ž
èšèšå³: TodoCardã®äœãæ¹
ææ: todosãªã¹ãã®ããŒã¿
å·¥å Žã®ã©ã€ã³: itemBuilder颿°
åºæ¥äžãã: ç»é¢ã«è¡šç€ºãããTodoã«ãŒãã®äžèЧ
2. å®éã®ã³ãŒãå®è£
ð todo_list.dartãã¡ã€ã«ãæºå
widgetsãã©ã«ãã«todo_list.dartãã¡ã€ã«ãäœæããŸãã
ãããžã§ã¯ãå
ã®ãã£ã¬ã¯ããªæ§æ
lib/ ã¢ããªã®æ žãšãªããã©ã«ã
âââ main.dart ã¢ããªã®éå§å°ç¹
âââ widgets/
â âââ todo_list.dart
ð ãã¹ãçšããŒã¿ã®æºå
ãŸãã衚瀺確èªã®ããã®ãµã³ãã«ããŒã¿ãäœæããŸãïŒ
final List<Todo> todos = [
Todo(
title: '倧åŠã®ã¬ããŒã',
detail: 'å¿çåŠã®ã¬ããŒãã2000åã§æžã',
dueDate: DateTime(2025, 1, 15),
isCompleted: false,
),
Todo(
title: 'è²·ãç©',
detail: 'çä¹³ããã³ãåµãè²·ã',
dueDate: DateTime(2025, 1, 10),
isCompleted: true,
),
Todo(
title: 'ã¢ã«ãã€ã',
detail: 'éææ¥ã®ã·ããã17æãã21æ',
dueDate: DateTime(2025, 1, 12),
isCompleted: false,
),
Todo(
title: 'åéãšã®çŽæ',
detail: 'åææ¥ã«æ ç»ãèŠã«è¡ã',
dueDate: DateTime(2025, 1, 20),
isCompleted: false,
),
Todo(
title: '峿žé€š',
detail: 'åããæ¬ãè¿åŽããïŒæéïŒæ¥é±ç«ææ¥ïŒ',
dueDate: DateTime(2025, 1, 9),
isCompleted: true,
),
];
ðš ç»é¢ã®ã¬ã€ã¢ãŠãæ§æ
å®å
šãªç»é¢ãäœæããã³ãŒãäŸïŒ
import 'package:flutter/material.dart';
import 'package:intl/date_symbol_data_local.dart'; // æ¥æ¬èªãªã©ãã±ãŒã«æ
å ±ãèªã¿èŸŒã
import '../models/todo.dart'; // äœæããTodoã¯ã©ã¹
import '../widgets/todo_card.dart'; // äœæããTodoCardãŠã£ãžã§ãã
class TodoList extends StatefulWidget {
const TodoList({super.key});
@override
State<TodoList> createState() => TodoListState();
}
class TodoListState extends State<TodoList> {
// ãã¹ãçšã®TodoããŒã¿ïŒããšã§è¿œå ç»é¢ããåçã«å¢ããæ³å®ïŒ
final List<Todo> todos = [
Todo(
title: '倧åŠã®ã¬ããŒã',
detail: 'å¿çåŠã®ã¬ããŒãã2000åã§æžã',
dueDate: DateTime(2025, 1, 15),
isCompleted: false,
),
Todo(
title: 'è²·ãç©',
detail: 'çä¹³ããã³ãåµãè²·ã',
dueDate: DateTime(2025, 1, 10),
isCompleted: true,
),
Todo(
title: 'ã¢ã«ãã€ã',
detail: 'éææ¥ã®ã·ããã17æãã21æ',
dueDate: DateTime(2025, 1, 12),
isCompleted: false,
),
Todo(
title: 'åéãšã®çŽæ',
detail: 'åææ¥ã«æ ç»ãèŠã«è¡ã',
dueDate: DateTime(2025, 1, 20),
isCompleted: false,
),
Todo(
title: '峿žé€š',
detail: 'åããæ¬ãè¿åŽããïŒæéïŒæ¥é±ç«ææ¥ïŒ',
dueDate: DateTime(2025, 1, 9),
isCompleted: true,
),
];
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: TodoCard(todo: todos[index]),
);
},
);
}
}
ð ã³ãŒãã®è©³çŽ°èª¬æ
â¹ïž StatefulWidget ãš StatelessWidget ãšã¯ïŒ
|çš®é¡| ãã£ããå®çŸ© |å
žåçãªäœ¿ãæ¹|
|StatelessWidget| äžåºŠæç»ãããåºæ¬çã«èŠãç®ãå€ãããªã ãŠã£ãžã§ãããå€éšããæž¡ããã å
¥åããŒã¿ ã ãã§ UI ãæ§æããå
éšã§å€ãä¿æããªãã| ã¢ã€ã³ã³ãåºå®ããã¹ããè£
食ã ãã®ã«ãŒããªã©ã衚瀺å°çšãã®ããŒã|
|StatefulWidget| æç»åŸã§ã å
éšç¶æ
ïŒStateïŒãæã¡ãsetState() ã§åæç» ã§ãããŠã£ãžã§ããããŠãŒã¶ãŒæäœããããã¯ãŒã¯çµæãªã©ã«å¿ã㊠UI ãå€ããã| å
¥åãã©ãŒã ããªã¹ãã®è¿œå åé€ããã§ãã¯ããã¯ã¹ãã¢ãã¡ãŒã·ã§ã³ãªã©ãåãã®ãããããŒã|
ãã® 2 ã€ã¯ãããŒãã®ã³ããŒããšããã¯ã€ãããŒããã®éãã«äŸããããŸãã
ã»ããŒãã®ã³ããŒïŒStatelessïŒâŠ å°å·ããåŸã¯å
容ãå€ãããªãã
ã»ãã¯ã€ãããŒãïŒStatefulïŒâŠ äœåã§ãæžãæããŠææ°æ
å ±ã衚瀺ã§ããã
â¹ïž ãªã StatefulWidget ã䜿ãã®ïŒ
ä»ã¯åºå®ã®ãã¹ãããŒã¿ã§ãããæ¬¡ã®ç« ã§ãïŒããã¿ã³ãæŒããŠæ°ãã Todo ã远å ã§ããããã«ãªããŸãã ãã®éããªã¹ãã®å 容ïŒtodos é åïŒã åçã«å€å ããããã
ã»ããŒã¿ãå€ãã£ãã setState() ã§ç»é¢ãåæç»ãã
ãšããä»çµã¿ãå¿
èŠã§ãããããå®çŸã§ããã®ã StatefulWidget ã§ãã
äžæ¹ã§ãTodoCard ã®ããã«è¡šç€ºå 容ãå€éšããæž¡ãããã ãã§å éšç¶æ ãæããªã UI 㯠StatelessWidget ã®ãŸãŸã§ OK ã§ãã
ListView.builder
ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: TodoCard(todo: todos[index]),
);
},
)
ã»itemCount: ãäœåã®é
ç®ã衚瀺ãããã
ã»itemBuilder: ãåé
ç®ãã©ãäœãããã®é¢æ°
ã»index: çŸåšäœæäžã®é
ç®çªå·ïŒ0, 1, 2, ...ïŒ
ã»PaddingïŒããã£ã³ã°ïŒ
Padding(
padding: EdgeInsets.all(8.0),
child: TodoCard(...),
)
åTodoCardéã«äœçœã远å
èŠãããã¬ã€ã¢ãŠããäœããã
3. åäœã®æµã
1.ããŒã¿æºå: todosãªã¹ãã«5ã€ã®TodoããŒã¿ãæ ŒçŽ
2.ListViewèµ·å: 5ã€ã®é
ç®ã衚瀺ããæç€º
3.ç¹°ãè¿ãåŠç: index 0ã4 ãŸã§é çªã«å®è¡
index=0: 1ã€ç®ã®Todoã倧åŠã®ã¬ããŒããã§TodoCardäœæ
index=1: 2ã€ç®ã®Todoãè²·ãç©ãã§TodoCardäœæ
...以äžåæ§
4.ç»é¢è¡šç€º: äœæããã5ã€ã®TodoCardã瞊ã«äžŠãã§è¡šç€º
5.ã¹ã¯ããŒã«: é
ç®ãå€ãå Žåã¯äžäžã¹ã¯ããŒã«å¯èœ
4. Todoãªã¹ãã衚瀺ããŠã¿ãã
TodoList ãŠã£ãžã§ããã衚瀺ããåå° ãšãªããªã¹ãç»é¢ãäœããŸãããã¡ã€ã«æ§æã¯æ¬¡ã®ããã«ãªããŸãã
ãããžã§ã¯ãå
ã®ãã£ã¬ã¯ããªæ§æ
lib/
âââ main.dart
âââ screens/
â âââ list_screen.dart â â
æ°èŠ
âââ widgets/
â âââ todo_card.dart
â âââ todo_list.dart â ãã®ç« ã§å®è£
æžã¿
list_screen.dart ã以äžã®ã³ãŒãã§äœæããŸãããã
lib/screens/list_screen.dart
import 'package:flutter/material.dart';
import '../widgets/tood_list.dart';
class ListScreen extends StatefulWidget {
const ListScreen({super.key});
@override
ListScreenState createState() => ListScreenState();
}
class ListScreenState extends State<ListScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('TODOãªã¹ã')),
body: TodoList(), // TodoList ãŠã£ãžã§ãããé
眮
);
}
}
main.dart ã§ã¯ ListScreen ãåŒã³åºãã ãã§ãªã¹ãç»é¢ã衚瀺ã§ããŸãã
1.lib/main.dart ãéããŸãã
2.MaterialApp ã® home ã§ TodoCard ã ã£ãéšåã ListScreen ã«çœ®ãæããŸãããã
lib/main.dart
import 'package:flutter/material.dart';
import 'package:intl/date_symbol_data_local.dart'; // æ¥æ¬èªãªã©ãã±ãŒã«æ
å ±ãèªã¿èŸŒã
import 'screens/list_screen.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// DateFormat ã§æ¥æ¬èªè¡šèšã䜿ãããããã±ãŒã«ãåæå
await initializeDateFormatting('ja'); // ä»èšèªã®å Žåã¯"en"ãªã©ã«å€æŽ
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: ListScreen(),
);
}
}
ð ã³ãŒãã®è©³çŽ°èª¬æ
ãªããã±ãŒã«èšå®ïŒinitializeDateFormattingïŒãå¿
èŠïŒ
æ¥ä»ãã12æ30æ¥(æ)ãã®ããã«æ¥æ¬èªè¡šèšã§è¡šç€ºããã«ã¯ã端æ«ã«ããæ¥æ¬èªã®ææ¥ã»æåããŒã¿ãã¢ããªåŽãèªã¿èŸŒãå¿
èŠããããŸãã
ã€ã¡ãŒãžãšããŠã¯ã
ð èŸæžïŒãã±ãŒã«ããŒã¿ïŒãéããŠãæ°åã® "12" ãèŠããšãã«ãDecemberãã§ã¯ãªãã12æããšèªãæ¹æ³ãæãã
ãšããäœæ¥ãäžåºŠã¢ããªèµ·åæã«è¡ãæãã§ãã
initializeDateFormatting('ja') ãåŒã¶ããšã§ã
1.æ¥æ¬èªãã±ãŒã«ã®èŸæžãã¡ã€ã«ãèªã¿èŸŒã¿
2.DateFormat('Mædæ¥(E)') ãæ£ããæ¥æ¬èªã§æ¥ä»ãçæ
ãšãªããŸããè±èªã ãã§è¯ãå Žåã¯äžèŠã§ãããæ¥æ¬èªã»ãã©ã³ã¹èªãªã©ç¹å®èšèªã§ææ¥ã衚瀺ãããæã¯å¿
é ã§ãã
â 5ã€ã®TodoCardã衚瀺ãããã°æåã§ãïŒ
ãªã¹ãã®è¡šç€º
æ°èŠäœæãã¿ã³ã®å®è£
ð¯ ãŽãŒã«
ç»é¢å³äžã« Todo远å ãã¿ã³ïŒFloatingActionButtonïŒãé
眮ãã
â»å®éã®ç»é¢é·ç§»ã¯æ¬¡ã®ç« ã§è¡ããŸãã
宿ã€ã¡ãŒãž
远å ãã¿ã³è¡šç€º
ð äœæ¥æé
- ãã¿ã³ãã¬ã€ã¢ãŠãã«è¿œå
Scaffold ã«ã¯æšæºã§ floatingActionButton ãšããããããã£ãçšæãããŠããŸããããã« FloatingActionButton ãèšå®ããã ãã§ãå³äžã« "ãµãã£" ãšæµ®ãã¶ãã¿ã³ã衚瀺ãããŸãã
import 'package:flutter/material.dart';
import '../models/todo.dart';
import '../widgets/tood_list.dart';
import 'add_todo_screen.dart';
class ListScreen extends StatefulWidget {
const ListScreen({super.key});
@override
ListScreenState createState() => ListScreenState();
}
class ListScreenState extends State<ListScreen> {
// TodoList ã®ç¶æ
ãæäœããããã®ããŒ
final GlobalKey<TodoListState> _todoListKey = GlobalKey<TodoListState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('TODOãªã¹ã')),
body: TodoList(key: _todoListKey), // TodoList ãŠã£ãžã§ãããé
眮
floatingActionButton: FloatingActionButton(
onPressed: () {}, // ç»é¢é·ç§»ã«ã€ããŠã¯æ¬¡ã®ç« ã§å®è£
ããŸã
backgroundColor:
const Color.fromARGB(255, 0, 0, 255), // ãã¿ã³è²ïŒRGBAã§ãæå®ã§ããŸãïŒ
foregroundColor: Colors.white,
child: const Icon(Icons.add), // Flutteræšæºã®ãïŒãã¢ã€ã³ã³
),
);
}
}
ð ã³ãŒãã®è§£èª¬
â¹ïž FloatingActionButton ã£ãŠãªã«ïŒ
FloatingActionButton ã¯æšæºã§äžžããã¿ã³ãçšæãããŠããã®ã§ãã¢ã€ã³ã³ãæž¡ãã ãã§OKã§ãã
â¹ïž Icons.add ã£ãŠãªã«ïŒ
Icons.add 㯠Flutterã«æåããå«ãŸããŠãã远å ã¢ã€ã³ã³ã§ãããïŒãããŒã¯ã衚瀺ããŸãã
GlobalKey ã£ãŠãªã«ïŒ
GlobalKey<TodoListState> 㯠ç¹å®ã®ãŠã£ãžã§ããïŒããã§ã¯ TodoListïŒã®ãäœæã ãã¢ããªå
šäœã§äžæã«ç€ºãæã®ãããªãã®ã§ãã
ãã®æã䜿ããšãå¥ã®å Žæã«ãããŠã£ãžã§ããããã§ã ãã®ãŠã£ãžã§ããã®ç¶æ
(State) ã«å®å
šã«ã¢ã¯ã»ã¹ã§ããŸãã
äŸã話ïŒ
ð® éµäŸ¿çªå· + äœæ = å®¶ãäžçºã§ç¹å®ã§ãã
GlobalKey = ãŠã£ãžã§ãããäžçºã§ç¹å®ã§ãã
å®éã®äœ¿ãæ¹ïŒä»åã®ã³ãŒãïŒ
// 1) ListScreen ã§ããŒãäœæ
final _todoListKey = GlobalKey<TodoListState>();
// 2) TodoList ã«ããŒãæž¡ã
body: TodoList(key: _todoListKey),
// 3) 远å ç»é¢ããæ»ã£ãŠããããšã«ãªã¹ããžæ°ãã Todo ã远å
_todoListKey.currentState?.addTodo(newTodo);
ãã€ã³ãã¯æ¬¡ã® 3 ã€ã§ãã
1.äžææ§: åãããŒã¯ 1 ã€ã ããã ãã確å®ã«ãã®ãŠã£ãžã§ãããæã瀺ããã
2.State ãžã®ã¢ã¯ã»ã¹: currentState ããããã£çµç±ã§ãŠã£ãžã§ããå
éšã®ã¡ãœãããåŒã¹ãã
3.ä¹±çšæ³šæ: 䟿å©ã§ããå€çšãããšäŸåé¢ä¿ãè€éã«ãªãã®ã§ããã©ãããŠãå¿
èŠãªå Žé¢ãã«çµã£ãŠäœ¿ããŸãããã
ä»åã®ã±ãŒã¹ã§ã¯ãListScreenïŒèŠªïŒåŽãã TodoListïŒåïŒã«åããŠãç»é¢é·ç§»åŸã«ååŸããæ°ãã Todo ã远å ãã ãšããæç¢ºãªç®çããããã GlobalKey ãé©åã«æ©èœããŸãã
å®éã®ããŒã¿ãåæ ã§ããããã«ãã
次ã®ç« ã§ã¯æ°èŠã®Todoã远å ããŸãã å®éã«ããŒã¿ãåæ ã§ããããã«ããããã«ããã¹ãããŒã¿ãã空ã®ãªã¹ãã«å€æŽããŠãããŸãã ãŸããTodoã®è¿œå ç»é¢ããããŒã¿ãåãåã£ãŠãªã¹ãã«è¿œå ããããã«ã颿°addTodo ãå®çŸ©ããŠãããŸãã
äžèšã®ããã«ãTodoList ã¯ã©ã¹å ã®ç©ºã®ãªã¹ããšãaddTodo颿°ãå®çŸ©ããŸãã
// äžéšçç¥
class TodoListState extends State<TodoList> {
final List<Todo> todos = []; // â 空ã®ãªã¹ã ïŒãã¹ãããŒã¿ãåé€ïŒ
void addTodo(Todo newTodo) { // â Todoã®è¿œå ç»é¢ããããŒã¿ãåãåã颿°
setState(() => todos.add(newTodo));
}
}
Todo远å ç»é¢ã®å®è£
åã®ã¹ãããã§Todoãªã¹ãç»é¢ã®å®è£ ãå®äºããŸããã
ãã®ç« ã§ã¯ãå®è£ ã®æŠèŠã§èª¬æãã5çªç®ã®ã¹ããããTodo远å ç»é¢ã®å®è£ ããè¡ããŸãããŠãŒã¶ãŒãæ°ããã¿ã¹ã¯ãå ¥åã»è¿œå ã§ããç»é¢ãäœæãããªã¹ãç»é¢ãšé£æºãããŠãããŸãã
ð¯ ãã®ç« ã®ãŽãŒã«
æ°ããã¿ã¹ã¯å
¥åç»é¢ãäœæãã
ç»é¢éã®ç§»åïŒããã²ãŒã·ã§ã³ïŒãå®è£
ãã
å
¥åãã©ãŒã ã®ä»çµã¿ãçè§£ããå®è£
ãã
å
¥åããŒã¿ã®æ€èšŒïŒããªããŒã·ã§ã³ïŒãåŠã¶
宿Todo远å ç»é¢ã®ã€ã¡ãŒãž
äœæãã¿ã³ãéæŽ»æ§ç¶æ
äœæãã¿ã³ãéæŽ»æ§ç¶æ
äœæãã¿ã³ã掻æ§ç¶æ
äœæãã¿ã³ã掻æ§ç¶æ
_openAddTodoScreen: Navigator.push ã§å
¥åç»é¢ãéããNavigator.pop ã§æ»ãéã«æ°ãã Todo ããŒã¿ãåãåããŸãã
setState: ãªã¹ãã«ããŒã¿ã远å ããåŸã«åŒã¶ãšãç»é¢ãèªåã§æŽæ°ãããŸãã
ðª ç»é¢é·ç§»ã£ãŠäœïŒ
ð äŸïŒå³æžé€šã§ã®æ¬ã®æ€çŽ¢
峿žé€šã§æ¬ãæ¢ãããšãèããŠã¿ãŸãããïŒ
ã¡ã€ã³ç»é¢: 峿žé€šã®æ¡å
æ¿ïŒå
šäœã®æ¡å
ïŒ
æ€çŽ¢ç»é¢: æ¬ã®æ€çŽ¢ãã©ãŒã ïŒã¿ã€ãã«ãèè
ãå
¥åïŒ
çµæç»é¢: æ€çŽ¢çµæã®äžèЧïŒèŠã€ãã£ãæ¬ã®ãªã¹ãïŒ
詳现ç»é¢: ç¹å®ã®æ¬ã®è©³çްæ
å ±
åç»é¢ã¯ãæ»ãããé²ãããå¥ã®ç»é¢ãžããªã©ã®ç§»åãã§ããŸãã
ã¹ããŒããã©ã³ã¢ããªã§ãåæ§ã«ãè€æ°ã®ç»é¢ãè¡ãæ¥ããããšã§æ§ã ãªæ©èœãæäŸããŸãã
ð¯ ãªãå¥ç»é¢ãå¿ èŠïŒ
ç»é¢ã®åœ¹å²åæ
ãªã¹ãç»é¢: äžèŠ§è¡šç€ºã«ç¹åãèŠããã
å
¥åç»é¢: å
¥åäœæ¥ã«ç¹åã䜿ãããã
ç·šéç»é¢: ä¿®æ£äœæ¥ã«ç¹åãééããé²ã
ð äœæ¥æé
1. ç»é¢é·ç§»ã®ä»çµã¿ãçè§£ãã
ð Navigatorã®åºæ¬æŠå¿µ
Navigatorã¯ãã¢ããªå
ã§ã®ç»é¢ç§»åã管çããä»çµã¿ã§ãã
æ¥åžžäŸïŒæ¬ã®ããŒãžããã
push: æ°ããããŒãžãäžã«éããïŒæ°ããç»é¢ãéãïŒ
pop: äžã®ããŒãžãåãé€ãïŒåã®ç»é¢ã«æ»ãïŒ
stack: ããŒãžã®éãªãå
·åã管ç
// æ°ããç»é¢ãéã
Navigator.push(
context,
MaterialPageRoute(builder: (context) => TodoInputScreen()),
);
// åã®ç»é¢ã«æ»ã
Navigator.pop(context);
- 空ã®å
¥åç»é¢ãäœæãã
æ¬æ Œçãªãã©ãŒã ãäœãåã«ããŸãã¯ã¿ã€ãã«ããŒã ãã®ç©ºç»é¢ãäœæããŠç»é¢é·ç§»ãæ£ããåãã確èªããŸãããã
ãããžã§ã¯ãå
ã®ãã£ã¬ã¯ããªæ§æ
lib/
âââ screens/
â âââ add_todo_screen.dart â â
æ°èŠ
lib/screens/add_todo_screen.dart
import 'package:flutter/material.dart';
class AddTodoScreen extends StatefulWidget {
const AddTodoScreen({super.key});
@override
State<AddTodoScreen> createState() => _AddTodoScreenState();
}
class _AddTodoScreenState extends State<AddTodoScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('æ°èŠäœæ')),
body: const Center(child: Text('ããã«ãã©ãŒã ãäœæããŠãããŸã')), // 仮眮ã
);
}
}
3. ListScreen ããé·ç§»ãã
äžèšã®ããã« ListScreen ã¯ã©ã¹ã®äžã§ AddTodoScreen ã¯ã©ã¹ãã€ã³ããŒãããŠãé·ç§»ããããã®é¢æ°Navigator.push ãåŒã³åºããŸãã
import 'package:flutter/material.dart';
import 'package:todo_app/models/todo.dart';
import 'package:todo_app/screens/add_todo_screen.dart';
import '../widgets/tood_list.dart';
class ListScreen extends StatefulWidget {
const ListScreen({super.key});
@override
ListScreenState createState() => ListScreenState();
}
class ListScreenState extends State<ListScreen> {
// TodoList ã®ç¶æ
ãæäœããããã®ããŒ
final GlobalKey<TodoListState> _todoListKey = GlobalKey<TodoListState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('TODOãªã¹ã')),
body: TodoList(key: _todoListKey), // TodoList ãŠã£ãžã§ãããé
眮
floatingActionButton: FloatingActionButton(
onPressed: () async {
// ç»é¢é·ç§»ããæ»ã£ãŠãããçµæïŒæ°èŠ TodoïŒãåãåã
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const AddTodoScreen()),
);
// è¿åŽãããããŒã¿ã Todo ã§ããã°ãªã¹ããžè¿œå
if (result != null) {
// åŸã
䜿ãã®ã§äžæŠã³ã¡ã³ãã¢ãŠã
// _todoListKey.currentState?.addTodo(result);
}
}, // ç»é¢é·ç§»ã«ã€ããŠã¯æ¬¡ã®ç« ã§å®è£
ããŸã
backgroundColor:
const Color.fromARGB(255, 0, 0, 255), // ãã¿ã³è²ïŒRGBAã§ãæå®ã§ããŸãïŒ
foregroundColor: Colors.white,
child: const Icon(Icons.add), // Flutteræšæºã®ãïŒãã¢ã€ã³ã³
),
);
}
}
â ç»é¢é·ç§»ããŠã¿ã€ãã«ããŒãæ°èŠäœæãã衚瀺ãããã°æºåå®äºã§ãã
空ã®è¿œå ç»é¢ã®è¡šç€º
4. å ¥åç»é¢ã®å®è£
ð åºæ¬çãªå ¥åãã©ãŒã ã®äœæ
import 'package:flutter/material.dart';
import '../models/todo.dart';
class AddTodoScreen extends StatefulWidget {
const AddTodoScreen({super.key});
@override
AddTodoScreenState createState() => AddTodoScreenState();
}
class AddTodoScreenState extends State<AddTodoScreen> {
// å
¥åå
容ã管çããã³ã³ãããŒã©ãŒ
final TextEditingController _titleController = TextEditingController();
final TextEditingController _detailController = TextEditingController();
final TextEditingController _dateController =
TextEditingController(); // ææ¥è¡šç€ºçš
DateTime? _selectedDate; // éžæãããææ¥
// ãã©ãŒã ã®å
¥åæ€èšŒçš
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
bool _isFormValid = false; // ãã©ãŒã å
¥åãå®äºããŠããã
@override
void initState() {
super.initState();
// ããã¹ãå
¥åãå€ãããã³ã«ãã§ãã¯
_titleController.addListener(_updateFormValid);
_detailController.addListener(_updateFormValid);
}
/// å
šå
¥åæ¬ãåãŸã£ãŠããããå€å®ãã
/// ãã¿ã³ã®æŽ»æ§ç¶æ
ïŒæŒãã/æŒããªãïŒãæŽæ°ããã¡ãœãã
void _updateFormValid() {
setState(() {
_isFormValid = _titleController.text.isNotEmpty &&
_detailController.text.isNotEmpty &&
_selectedDate != null; // ææ¥ãéžæãããŠããã
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('æ°ããã¿ã¹ã¯ã远å '),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
// å
¥åãã©ãŒã ã®æ çµã¿
key: _formKey,
child: Column(
children: [
// ã¿ã€ãã«å
¥åãã£ãŒã«ã
TextFormField(
controller: _titleController,
decoration: const InputDecoration(
labelText: 'ã¿ã¹ã¯ã®ã¿ã€ãã«',
hintText: '20æå以å
ã§å
¥åããŠãã ãã',
border: OutlineInputBorder(),
),
validator: (value) {
// å
¥åãã§ãã¯
if (value == null || value.isEmpty) {
return 'ã¿ã€ãã«ãå
¥åããŠãã ãã';
}
return null;
},
),
const SizedBox(height: 16), // äœçœ
// 詳现å
¥åãã£ãŒã«ã
TextFormField(
controller: _detailController,
decoration: const InputDecoration(
labelText: 'ã¿ã¹ã¯ã®è©³çް',
hintText: 'å
¥åããŠãã ãã',
border: OutlineInputBorder(),
),
maxLines: 3, // è€æ°è¡å
¥åå¯èœ
validator: (value) {
if (value == null || value.isEmpty) {
return '詳现ãå
¥åããŠãã ãã';
}
return null;
},
),
const SizedBox(height: 16),
// ð
ææ¥å
¥åãã£ãŒã«ãïŒDatePickerïŒ
TextFormField(
controller: _dateController,
readOnly: true, // ããŒããŒãã衚瀺ããªã
decoration: const InputDecoration(
labelText: 'ææ¥',
hintText: '幎/æ/æ¥',
border: OutlineInputBorder(),
),
onTap: () async {
// æ¥ä»éžæãã€ã¢ãã°ãéã
DateTime? picked = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2100),
);
if (picked != null) {
// éžæããæ¥ä»ãã³ã³ãããŒã©ã«åæ
_selectedDate = picked;
_dateController.text =
'${picked.year}/${picked.month}/${picked.day}';
// ææ¥ãéžãã ããšããã©ãŒã ç¶æ
ãåè©äŸ¡
_updateFormValid();
}
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'ææ¥ãéžæããŠãã ãã';
}
return null;
},
),
const SizedBox(height: 24),
// äœæãã¿ã³
ElevatedButton(
onPressed: _isFormValid ? _saveTodo : null,
style: ElevatedButton.styleFrom(
backgroundColor: _isFormValid
? const Color.fromARGB(255, 0, 0, 255)
: Colors.grey.shade400,
padding:
const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
), // å
¥åå®äºã§æŽ»æ§å
child: Text(
'ã¿ã¹ã¯ã远å ',
// ããã¹ãã®è²ã倿Ž
style: TextStyle(
color: _isFormValid ? Colors.white : Colors.grey,
fontSize: 18,
),
),
),
],
),
),
),
);
}
// ã¿ã¹ã¯äœæåŠç
void _saveTodo() {
if (_formKey.currentState!.validate()) {
// å
¥åãã§ãã¯
// æ°ããTodoãäœæ
Todo newTodo = Todo(
title: _titleController.text,
detail: _detailController.text,
dueDate: _selectedDate!,
);
// åã®ç»é¢ã«æ»ãïŒäœæããTodoããŒã¿ãšäžç·ã«ïŒ
Navigator.pop(context, newTodo);
}
}
@override
void dispose() {
// ç»é¢ãéããããæã®åŠç
_titleController.dispose(); // ã¡ã¢ãªã®è§£æŸ
_detailController.dispose();
_dateController.dispose();
super.dispose();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
// åæè¡šç€ºæã«ãããªããŒã·ã§ã³
_updateFormValid();
}
}
ð ã³ãŒãã®è©³çŽ°èª¬æ
StatefulWidget
class TodoInputScreen extends StatefulWidget
ç¶æ
ãå€åããç»é¢ïŒå
¥åå
容ãå€ããïŒ
ãŠãŒã¶ãŒã®å
¥åã«å¿ããŠç»é¢ãåçã«å€å
TextEditingController
final TextEditingController _titleController = TextEditingController();
ããã¹ãå
¥åãã£ãŒã«ãã®å
容ã管ç
å
¥åãããæååãååŸã»èšå®å¯èœ
Form & TextFormField
Form(
key: _formKey,
child: TextFormField(...)
)
Form: è€æ°ã®å
¥åãã£ãŒã«ãããŸãšããŠç®¡ç
TextFormField: æ€èšŒæ©èœä»ãã®å
¥åãã£ãŒã«ã
validatorïŒããªããŒã¿ãŒïŒ
validator: (value) {
if (value == null || value.isEmpty) {
return 'ã¿ã€ãã«ãå
¥åããŠãã ãã';
}
return null;
}
å
¥åå
å®¹ã®æ€èšŒïŒç©ºæåãã§ãã¯ãªã©ïŒ
ãšã©ãŒã¡ãã»ãŒãžã®è¡šç€º
å
¥åå¿
é é
ç®ã®ç¢ºèª
DatePickerïŒæ¥ä»éžæïŒ ãã£ãŒã«ããã¿ãããããšã«ã¬ã³ããŒã衚瀺ããéžãã æ¥ä»ã _dateController ãžæžã蟌ãã
_isFormValid ãã©ã° & _updateFormValid ã¡ãœãã
bool _isFormValid = false;
ã¿ã€ãã«ã»è©³çŽ°ã»ææ¥ã®3é ç®ããã¹ãŠå ¥åæžã¿ãã©ããã確èªããäœæãã¿ã³ã®æŽ»æ§/éæŽ»æ§ãå³æåæ ããã
ElevatedButtonïŒäœæãã¿ã³ïŒ
onPressed: _isFormValid ? _saveTodo : null
ãã©ãŒã ãæªå ¥åã®ãšãã¯ãã¿ã³ãæŒããªãããã« null ãæž¡ããèæ¯è²ãã°ã¬ãŒã«ããŠãŠãŒã¶ãŒã«ç¶æ ãäŒããŸãã
dispose() ãš didChangeDependencies() ç»é¢ãéããããéã«ã³ã³ãããŒã©ãè§£æŸããŠã¡ã¢ãªãªãŒã¯ãé²ããåææç»çŽåŸã«ãããªããŒã·ã§ã³ãå®è¡ããŸãã
5. ç»é¢éã§ã®ããŒã¿åãæž¡ã
ð€ ããŒã¿ãè¿åŽããåŽïŒå ¥åç»é¢ïŒ
// åã®ç»é¢ã«æ»ãæã«ããŒã¿ãæž¡ã
Navigator.pop(context, newTodo);
ð¥ è¿åŽãããããŒã¿ãåãåãåŽïŒãªã¹ãç»é¢ïŒ
ListScreenState ã®äžã«ãã åŸã
䜿ãã®ã§äžæŠã³ã¡ã³ãã¢ãŠãã®ã³ã¡ã³ãã¢ãŠããå€ããŠã¿ãŸãããã 远å ç»é¢ã§äœæããTodoãäžèЧç»é¢ã®ãªã¹ãã«è¿œå ããããšãã§ããããã«ãªããŸãã
// è¿åŽãããããŒã¿ã Todo ã§ããã°ãªã¹ããžè¿œå
if (result != null) {
// åŸã
䜿ãã®ã§äžæŠã³ã¡ã³ãã¢ãŠã
_todoListKey.currentState?.addTodo(result); // ã³ã¡ã³ãã¢ãŠããå€ã
}
6. ãŠãŒã¶ããªãã£ã®åäž
ðš 䜿ããããå
¥åãã©ãŒã ã®äœæ
ãã³ãããã¹ãã®æŽ»çš
decoration: InputDecoration(
labelText: 'ã¿ã¹ã¯ã®ã¿ã€ãã«',
hintText: 'äŸïŒã¬ããŒããæžã', // å
¥åäŸã衚瀺
border: OutlineInputBorder(),
)
é©åãªå ¥åã¿ã€ãã®æå®
TextFormField(
keyboardType: TextInputType.multiline, // è€æ°è¡å
¥åçšããŒããŒã
maxLines: 3, // æå€§3è¡ãŸã§è¡šç€º
)
ãã©ãŒã«ã¹ç®¡ç
// èªåçã«æåã®ãã£ãŒã«ãã«ãã©ãŒã«ã¹
autofocus: true,
ð¡ å®è£ ã®ãã€ã³ã
ð å
¥åæ€èšŒïŒããªããŒã·ã§ã³ïŒ
å¿
é é
ç®ãã§ãã¯: 空æåã®é²æ¢
æåæ°å¶é: é©åãªé·ãã®ç¢ºèª
å³åº§ã®ãã£ãŒãããã¯: ãšã©ãŒã¡ãã»ãŒãžã®è¡šç€º
ð± ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹
çŽæçãªãã¶ã€ã³: ãã¿ã³ã®è²ãé
眮
åãããããã©ãã«: äœãå
¥åããããæç¢º
é©åãªããŒããŒã: å
¥åå
容ã«å¿ããããŒããŒã衚瀺
ð ããŒã¿ã®æµã
ç»é¢é·ç§»: push â å
¥å â pop
ããŒã¿åãæž¡ã: åã®ç»é¢ãšã®æ
å ±å
±æ
ç¶æ
æŽæ°: ãªã¹ãã®å³åº§ãªåæ
ç¶æ 管çã®å®è£
åã®ã¹ãããã§Todo远å ç»é¢ã®å®è£ ãå®äºããŸããã
ãã®ç« ã§ã¯ãå®è£ ã®æŠèŠã§èª¬æãã6çªç®ïŒæåŸïŒã®ã¹ããããç¶æ 管çã®å®è£ ããè¡ããŸãããããŸã§ã«äœæããå šãŠã®éšåãçµã¿åãããŠãå®å šã«åäœããTodoã¢ããªã宿ãããŸãã
ãŸãä»ãŸã§äœæããã¢ããªã¯ãã¢ããªã®ã¡ã¢ãªäžã«ããŒã¿ãä¿åãããŠããã ãã§ãäžåºŠã¢ããªãçµäºãããšããŒã¿ã倱ãããŠããŸããŸãã
ãã®ç« ã§ã¯ãã¢ããªãçµäºããŠãããŒã¿ã倱ãããªãããã«ãããŒã¿ãæ°žç¶åããæ¹æ³ãåŠã³ãŸãã
ð¯ ãã®ç« ã®ãŽãŒã«
ç¶æ
管çã®æŠå¿µãçè§£ããå®è£
ãã
ç»é¢éã§ã®ããŒã¿å
±æãå®çŸãã
ãªã¢ã«ã¿ã€ã ãªç»é¢æŽæ°ãå¯èœã«ãã
ããŒã¿ã®æ°žç¶åãå®çŸãã
å®å
šã«åäœããTodoã¢ããªã宿ããã
ð ç¶æ
管çã£ãŠäœïŒ
ðª äŸïŒåå Žã§ã®æŒå
åå Žã§ã®æŒåãèããŠã¿ãŸãããïŒ
å°æ¬: å
šäœã®ã¹ããŒãªãŒïŒã¢ããªã®èšèšïŒ
æŒåºå®¶: å
šäœã管çãã人ïŒç¶æ
管çã·ã¹ãã ïŒ
俳åª: å圹å²ãæŒãã人ïŒåç»é¢ã»ã³ã³ããŒãã³ãïŒ
å°éå
·: åäžã§äœ¿ãããç©ïŒããŒã¿ïŒ
æŒåºå®¶ã®åœ¹å²
俳åªå士ã®é£æºã管ç
å°éå
·ã®åºãå
¥ãã調æŽ
å
šäœã®æµããææ¡ãã調æŽ
ã¢ããªã§ãåæ§ã«ãåç»é¢ãããŒã¿ã®é£æºã管çãããæŒåºå®¶ãçãªä»çµã¿ãå¿
èŠã§ãã
ð ãªãç¶æ 管çãéèŠïŒ
ããŒã¿ã®äžè²«æ§
ãªã¹ãç»é¢ã§è¡šç€ºãããã¿ã¹ã¯æ°
远å ç»é¢ã§å
¥åãããæ°ããã¿ã¹ã¯
å®äºããã¿ã¹ã¯ã®ç¶æ
ãããã®æ
å ±ããå
šãŠã®ç»é¢ã§åžžã«äžèŽããŠããå¿
èŠããããŸãã
äŸïŒéè¡å£åº§ã®ç®¡ç
ATMã§èšé²ãããæ®é«
ã¹ããã¢ããªã§è¡šç€ºãããæ®é«
éåž³ã«èšèŒãããæ®é«
ããããç°ãªã£ãŠããã倧åé¡ã§ããããã¢ããªã§ãåãããšãèšããŸãã
ð äœæ¥æé
1. main.dartã®å€æŽ
ããã§ã¯ SharedPreferences ãåæåãããã®ã€ã³ã¹ã¿ã³ã¹ã䜿ã£ãŠ TodoService ãçæããŸããçæãããµãŒãã¹ã¯ã¢ããªå šäœã§äœ¿ããããã« MyApp ãŠã£ãžã§ãããžæž¡ããŸããããã«ãããã©ã®ç»é¢ããã§ã Todo ããŒã¿ã®èªã¿æžããè¡ããããã«ãªããŸãã
ð¡ ã€ã³ã¹ã¿ã³ã¹ã£ãŠäœïŒ
ããã°ã©ã ã§ãèšèšå³ïŒã¯ã©ã¹ïŒãããå®éã«äœ¿ãããã¢ãããäœã£ãç¶æ
ã ã€ã³ã¹ã¿ã³ã¹ ãšåŒã³ãŸãã
ã»SharedPreferences prefs = ... ã® prefs ã¯ãSharedPreferences ãšããèšèšå³ããäœã£ãå®ç©ãã
ã»TodoService todoService = TodoService(prefs) ã® todoService ãåæ§ã«ãTodoService ã®å®ç©ãã§ã å
éšã« prefs ãæ±ããŠããã®ã§å®éã®ä¿åã»èªã¿èŸŒã¿ãã§ããããã«ãªããŸãã
å®¶ã建ãŠãã€ã¡ãŒãžã§èšãã°ãTodoService ã¯ã©ã¹ããèšèšå³ããtodoService ãã建ãŠãå®¶ãã«ãªããŸãã
import 'services/todo_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
// ã»ãã® import ã¯çç¥
void main() async {
// Flutter ã®ãã©ã°ã€ã³åæåãéåæåŠçãè¡ãå Žåã¯å¿
é
WidgetsFlutterBinding.ensureInitialized();
// â SharedPreferences ãåæåïŒç«¯æ«ã«å°ããªããŒïŒããªã¥ãŒã§ä¿åã§ããïŒ
final prefs = await SharedPreferences.getInstance();
// â¡ SharedPreferences ã䜿ã£ãŠ TodoService ãçæïŒä¿åã»èªã¿èŸŒã¿ã®çªå£ïŒ
final todoService = TodoService(prefs);
// ⢠TodoService ãã¢ããªå
šäœãžæž¡ã
runApp(MyApp(todoService: todoService));
}
class MyApp extends StatelessWidget {
const MyApp({super.key, required this.todoService});
// ã¢ããªå
šäœã§å
±æãã TodoService
final TodoService todoService;
@override
Widget build(BuildContext context) {
return MaterialApp(
// ListScreen ã«todoServiceãåŒæ°ãšããŠããã
home: ListScreen(todoService: todoService),
);
}
}
2. list_screen.dart 倿Ž
ListScreen ã§ã¯ãmain.dartããåãåã£ã TodoService ãåãŠã£ãžã§ããã® TodoList ãšæ°èŠè¿œå ç»é¢ AddTodoScreen ã«åãæž¡ããŸãããŸãã远å ãå®äºããåŸã«ãªã¹ããåèªã¿èŸŒã¿ã§ãããã UniqueKey ã䜿ã£ãŠ TodoList ãåæç»ããŸãã
ð¡ UniqueKey ãšã¯ïŒ
Flutter ã§ã¯ ããŒ(Key) ãä»ããããšã§ãŠã£ãžã§ãããäžæã«èå¥ã§ããŸãã
UniqueKey() 㯠ãŠã£ãžã§ãããèå¥ããããã®ããŒã®äžçš®ã§ãç¹ã«ãŠã£ãžã§ããã®ç¶æ
ããªã»ãããããå Žåã«æå¹ã§ãã åãåã®ãŠã£ãžã§ãããè€æ°ååšããå Žåã§ãããããããåºå¥ããåæ§ç¯ãå¿
èŠãªå Žåã«ã æ°ãããŠã£ãžã§ãããšããŠæ±ãããããšãã§ããŸãã
è€éãªåæç»ããžãã¯ãæžããã« æè»œã«ãŠã£ãžã§ãããäœãçŽããã¯ãã㯠ãšèŠããŠãããŸãããã
import '../services/todo_service.dart';
ïŒçç¥ïŒ
class ListScreen extends StatefulWidget {
const ListScreen({super.key, required this.todoService});ã// â远å
final TodoService todoService;ã// â远å
ïŒçç¥ïŒ
class ListScreenState extends State<ListScreen> {
Key _listKey = UniqueKey(); // â远å
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('TODOãªã¹ã')),
body: TodoList(
key: _listKey, // â远å
todoService: widget.todoService, // â远å
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
// ç»é¢é·ç§»ããæ»ã£ãŠãããçµæïŒæ°èŠ TodoïŒãåãåã
final updated = await Navigator.push( // Todoã«è¿œå ããã£ããtrueãè¿ã
context,
MaterialPageRoute(
builder: (context) => AddTodoScreen(
todoService: widget.todoService, // â远å
)),
);
// 远å ããã£ããåæç»ïŒTodoList ãåååŸïŒ // â远å
if (updated == true) {
setState(() {
_listKey = UniqueKey(); // æ°ããããŒã§ TodoList ãåæ§ç¯
});
}
},
ïŒçç¥ïŒ
3. tood_list.dartã®å€æŽ
TodoList ã¯å®éã« Todo ããŒã¿ã衚瀺ã»è¿œå ã»åé€ãããŠã£ãžã§ããã§ãã
ç»é¢ã衚瀺ãããã _loadTodos() ã§ã¹ãã¬ãŒãžããããŒã¿ãèªã¿èŸŒã¿ãŸãã
æ°ããã¿ã¹ã¯ã远å ãããã addTodo() ã§ãªã¹ãã«è¿œå ããããš saveTodos() ã§ä¿åããŸãã
ãã§ãã¯ã¢ã€ã³ã³ãæŒãããã _deleteTodo() ã§ãªã¹ãããåé€ããåæ§ã«ä¿åããŸãã
ããŒãã£ã³ã°äžã¯ CircularProgressIndicator ã衚瀺ããŠãŠãŒã¶ãŒã«åŸ
æ©ãç¥ãããŸãã
import '../services/todo_service.dart'; // â远å
ïŒçç¥ïŒ
class TodoList extends StatefulWidget {
const TodoList({super.key, required this.todoService}); // â远å
final TodoService todoService; // â远å
ïŒçç¥ïŒ
class TodoListState extends State<TodoList> {
List<Todo> _todos = [];
bool _isLoading = true; // â远å
@override
void initState() {
super.initState();
_loadTodos(); // â远å SharedPreferences ããèªã¿èŸŒã¿
}
// ããŒã¿èªã¿èŸŒã¿åŠç颿°ã远å
Future<void> _loadTodos() async {
final todos = await widget.todoService.getTodos();
setState(() {
_todos = todos;
_isLoading = false;
});
}
// 远å ç»é¢ããåŒã°ãã远å 颿°ã远å
void addTodo(Todo newTodo) async {
setState(() => _todos.add(newTodo));
await widget.todoService.saveTodos(_todos);
}
// ãã§ãã¯ãã¿ã³ããåŒã°ããåé€é¢æ°ã远å
Future<void> _deleteTodo(Todo todo) async {
setState(() => _todos.removeWhere((t) => t.id == todo.id));
await widget.todoService.saveTodos(_todos);
}
@override
Widget build(BuildContext context) {
if (_isLoading) { // èªèŸŒäžã¯ããŒãã£ã³ã°ã€ã³ãžã±ãŒã¿ãŒã衚瀺
return const Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: _todos.length,
itemBuilder: (context, index) {
final todo = _todos[index]; // â远å
return Padding(
padding: const EdgeInsets.all(8.0),
child: TodoCard(
todo: todo,
onToggle: () => _deleteTodo(todo), // ãã§ãã¯ã§åé€ããåŠçã远å
),
ïŒçç¥ïŒ
4. add_todo_screen.dartã®å€æŽ
æ°èŠã¿ã¹ã¯ãäœæãããšãã«ãå ¥åå 容ã Todo ãªããžã§ã¯ãã«å€æã TodoService ãä»ããŠä¿åããŸããä¿åãå®äºããã Navigator.pop(context, true) ã§ããªã¹ããæŽæ°ããŠãã ããããšããåå³ã ããåã®ç»é¢ãžè¿ããŸãã
ïŒçç¥ïŒ
// äœæãã¿ã³
ElevatedButton(
onPressed: _isFormValid ? () => _saveTodo() : null, // äœææã«ä¿åããåŠçã远å
style: ElevatedButton.styleFrom(
ïŒçç¥ïŒ
// ã¿ã¹ã¯äœæåŠç
void _saveTodo() {
if (_formKey.currentState!.validate()) {
// å
¥åãã§ãã¯
// æ°ããTodoãäœæ
Todo newTodo = Todo(
title: _titleController.text,
detail: _detailController.text,
dueDate: _selectedDate!,
);
// æ¢åãªã¹ããååŸããŠè¿œå ããåŠçã远å // â远å
final todos = await widget.todoService.getTodos();
todos.add(newTodo);
await widget.todoService.saveTodos(todos);
// ãã®ç»é¢ããŸã é衚瀺ã«ãªããã«æ®ã£ãŠãã確èª
if (!mounted) return;
// åã®ç»é¢ãžãæŽæ°ãããããšã ãç¥ããã
Navigator.pop(context, true); // â倿Ž
}
}
â Todoã远å ããŠäžåºŠã¢ããªãçµäºãããŠã¿ãŸããããå床ã¢ããªãèµ·åããŠç«ã¡äžãããã远å ããTodoã衚瀺ãããŠããã¯ãã§ãã
空ã®è¿œå ç»é¢ã®è¡šç€º
ð¡ å®è£
ã®ãã€ã³ã
ðš ãŠãŒã¶ããªãã£
èªã¿èŸŒã¿äžè¡šç€º: ããŒã¿ååŸäžã®ã€ã³ãžã±ãŒã¿ãŒ
ð ããŒã¿ã®æµã
åæå: ã¢ããªèµ·åæã«ããŒã¿èªã¿èŸŒã¿
æäœ: ãŠãŒã¶ãŒã®æäœãåãä»ã
æŽæ°: ç»é¢ã®å³åº§æŽæ°
ä¿å: ããŒã¿ã®æ°žç¶å
ð 宿ïŒ
â
å®äºããã¹ããã
â
ãããžã§ã¯ãã®æ°èŠäœæ: éçºç°å¢ã®æºå
â
TodoããŒãã®å®è£
: åå©çšå¯èœãªéšåäœæ
â
ããŒã¿ã¢ãã«ã®å®è£
: ããŒã¿æ§é ãšç®¡çãµãŒãã¹
â
Todoãªã¹ãç»é¢ã®å®è£
: äžèŠ§è¡šç€ºæ©èœ
â
Todo远å ç»é¢ã®å®è£
: æ°èŠã¿ã¹ã¯å
¥åæ©èœ
â
ç¶æ
管çã®å®è£
: å
šäœçµ±åãšåäœå®æ
ð¯ 宿ããã¢ããªã®æ©èœ
â
ã¿ã¹ã¯äžèŠ§è¡šç€º: ç»é²ããã¿ã¹ã¯ãèŠããã衚瀺
â
ã¿ã¹ã¯è¿œå : æ°ããã¿ã¹ã¯ã®å
¥åã»ç»é²
â
å®äºåãæ¿ã: ã¿ã¹ã¯ã®å®äºã»æªå®äºç¶æ
管ç
â
ã¿ã¹ã¯åé€: äžèŠãªã¿ã¹ã¯ã®åé€
â
ããŒã¿æ°žç¶å: ã¢ããªãéããŠãæ
å ±ãä¿æããã
ð åºæ¬éšåã®å®è£ å®äºïŒ
ç¶æ 管çã®å®è£ ãå®äºããŸããïŒããã§åºæ¬éšåã®å®è£ ãå®äºããTodoã¢ããªã宿ããŸããã
ð åŠç¿ããå
容
â
èŠä»¶ã®ç¢ºèª: Todoã¢ããªã®ä»æ§ãšç®æšãçè§£
â
å®è£
ã®æŠèŠ: éçºã®æµããšã¢ãŒããã¯ãã£ãææ¡
â
ãããžã§ã¯ãäœæ: Flutteréçºç°å¢ã®æºå
â
TodoããŒãå®è£
: åå©çšå¯èœãªUIã³ã³ããŒãã³ãã®äœæ
â
ããŒã¿ã¢ãã«å®è£
: ããŒã¿æ§é ãšãµãŒãã¹ã®èšèš
â
Todoãªã¹ãç»é¢å®è£
: ããŒã¿è¡šç€ºæ©èœã®å®è£
â
Todo远å ç»é¢å®è£
: ããŒã¿å
¥åæ©èœã®å®è£
â
ç¶æ
管çå®è£
: ã¢ããªå
šäœã®ç¶æ
å¶åŸ¡
ð¯ ç¿åŸããã¹ãã«
以äžã®éèŠãªã¹ãã«ãç¿åŸããããšãã§ããŸããïŒ
ð± Flutteréçºã®åºç€
Flutterãããžã§ã¯ãã®äœæãšèšå®
ãŠã£ãžã§ããã®æ§æãšäœ¿ãæ¹
ç¶æ
管çã®åºæ¬æŠå¿µ
ðïž ã¢ããªèšèšã»å®è£
ã³ã³ããŒãã³ãæåã®éçº
ããŒã¿ã¢ãã«ã®èšèš
ç»é¢éã®é£æºãšç¶æ
管ç
ðŸ ããŒã¿ç®¡ç
ããŒã«ã«ããŒã¿ã®æ°žç¶å
ããŒã¿ããŒã¹ã®åºæ¬çãªäœ¿ãæ¹
éåæåŠçã®å®è£
ðš UI/UXå®è£
ãªã¹ã衚瀺ã®å®è£
ãã©ãŒã å
¥åã®åŠç
ãŠãŒã¶ãŒã€ã³ã¿ã©ã¯ã·ã§ã³ã®å®è£
ð ä»åã¯ãFlutterã䜿ã£ãæ¬æ Œçãªã¢ããªéçºã®åºç€ãåŠç¿ããŸããã
Discussion