Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Flutterコンテストを開催した話

 Flutterコンテストを開催した話

774a937b74096e82576b37678d00aeca?s=128

Daisuke Kishino

November 03, 2020
Tweet

Transcript

  1. 'MVUUFSίϯςετΛ։࠵ͨ͠࿩ %BJTVLF,JTIJOP ߹ಉษڧձJOେ౎ձԬࢁ8JOUFS0OMJOF 

  2. ࣗݾ঺հ w ϐʔϓϧιϑτ΢ΣΞגࣜձࣾ w ؛໺େีʢ!LJTIJTVLFʣ w Ԭࢁݝ૔ෑࢢࡏॅ w ͜͜೥͸εϚϗΞϓϦ։ൃ͕ϝΠϯ ʢ.POBDBɺ7VFKTɺ4XJGUͱ͔ʣ

    w .POBDB6(0,":"."΍ͬͯ·͢
  3. ࠓ೔࿩͢͜ͱ wࣗࣾͰ'MVUUFSΞϓϦίϯςετΛߦͬͨ wࢀՃऀͱͯࣗ͠਎΋'MVUUFSΞϓϦΛॳΊͯຊ࡞ͬͨ wίϯςετͷऔΓ૊Έ΍'MVUUFSͷ঺հΛߦ͍ͭͭɺ࡞ͬͨ ΞϓϦͰͷܦݧΛ͓࿩͠·͢

  4. 'MVUUFSͱ͸ʁ w(PPHMF͕։ൃ͍ͯ͠ΔΫϩεϓϥοτϑΥʔϜΞϓϦ։ൃπʔϧ w8JEHFUπϦʔͰ6*Λߏஙʢ3FBDUɺ7VFͷԾ૝%0.ಉ͡Πϝʔδʣ w4LJBͰϨϯμϦϯάΛߦ͏ʢωΠςΟϒͷ6*ίϯϙʔωϯτʹґଘ͍ͯ͠ ͳ͍ʣ w։ൃݴޠ͸%BSU w։ൃத͸%BSU7.ʹΑΔ)PU3FMPBEͰߴ଎։ൃ wετΞެ։࣌͸"05Ͱߴ଎ಈ࡞

  5. 'MVUUFSίϯςετ։࠵ͷ͖͔͚ͬ w'MVUUFS஥ؒΛ૿΍ͯ͠։ൃͷϞνϕʔγϣϯ্͍͛ͨɻ͔͠͠ɺதʑ ू·Βͳ͍ʜ w৆ۚग़ͯ͠ίϯςετΛ։࠵ͨ͠Βू·Δ͔΋ʁ wͪͳΈʹओ࠵ऀ͸ผͷํͰ͢ wࢲ͸ٕज़αϙʔτͱ͍͏໾ׂʢॳ৺ऀͳͷʹαϙʔτͱͳʁʣ

  6. 'MVUUFSίϯςετΛ։࠵͢ΔϝϦοτ w'MVUUFSͷٕज़ऀ͕૿͑Δʂ wࣾ಺Πϕϯτ΁ͷࢀՃऀ͕૿͑Δʂʂ wձࣾͷΞϐʔϧʹͳΔʂʂʂ

  7. 'MVUUFSίϯςετͷ֓ཁ wԠืظؒ͸ࠓ೥ͷʙ݄ w։ൃ༻ͷ"OESPJE୺຤Λ഑෍ wษڧձ΍4MBDLͰϑΥϩʔΞοϓ wදজ͸׬੒౓ɺΞΠσΞɺ69ɺ༗ӹੑͷΧςΰϦʔ৆ͱάϥϯϓϦ wਓͷΤϯτϦʔʂʢఏग़͕͋ͬͨͷ͸ΞϓϦʣ w৽ਓ໊ʴϕςϥϯ໊Ͱ৹ࠪ w৆ۚ͋Γʢձࣾ࣋ͪʣ wͦͷଞɺৄࡉ͸ҎԼهࣄͰ঺հ͍ͯ͠·͢ʂ wIUUQTUFDIQTDTSWDPKQࣾ಺ΞϓϦίϯςετΛ࣮ࢪͯ͠Έͯ

  8. ࡞ͬͨΞϓϦͷ঺հ wٯ೔Ί͘ΓΧϨϯμʔ w͋ͱԿ೔͔ͳʁΛָ͘͢͠ΔΧ΢ϯτμ΢ ϯΞϓϦ wखಈͰ೔Ί͘Γ͢Δ6*ͳͷ͕ಛ௃ w࣮͸ੲϦϦʔεͯͨ͠ΞϓϦͷϦϝΠΫ wͪͳΈʹࢲ͸׬੒౓৆͍͖ͨͩ·ͨ͠

  9. ͔͜͜Β͸ٕज़తͳ࿩Ͱ͢ ΞϓϦΛ࢝Ίͯ࡞ͬͯΈͯɺ͜͜͸ॏཁͩͳ ͱࢥͬͨͱ͜ΖͳͲΛϐοΫΞοϓ͠·ͨ͠

  10. ঢ়ଶ؅ཧ wঢ়ଶ؅ཧʢ7VFKTͰ͍͏ͱ͜ΖͷEBUB΍7VFYʣ͸Ͳ͏͢ΔΜͩΖ͏ʁ w#-P$ͱ͔4UBUF/PUJGJFSͱ͔ɺ͍Ζ͍Ζ΍Γํ͕͋ΔΈ͍͚ͨͩͲʜ

  11. ঢ়ଶ؅ཧ w·ͣ͸γϯϓϧʹ4UBUFGVM8JEHFUͱTFU4UBUFͰ࣮૷ w4UBUFGVM8JEHFU͸4UBUFʢঢ়ଶʣΛ࣋ͭ8JEHFU wঢ়ଶΛ࣋ͨͳ͍4UBUFMFTT8JEHFU΋͋Δ w4UBUFͷ৘ใΛ΋ͱʹ8JEHFUΛߏங͢Δ

  12. class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState();

    } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, child: Icon(Icons.add), ), ); } } ᶃ4UBUFGVM8JEHFU͕ 4UBUFΛੜ੒͢Δ ᶄ4UBUFͰ8JEHFUΛߏங ᶅ࠷ॳ͸Ͱඳը͞ΕΔ ᶆʴϘλϯΛλοϓ࣌ʹ TFU4UBUFʹ౉ͨؔ͠਺ͷதͰ ม਺ΛΠϯΫϦϝϯτ ᶇCVJMEؔ਺͕ ࠶౓࣮ߦʢϦϏϧυʣ͞Ε ͕ඳը͞ΕΔ
  13. ঢ়ଶ؅ཧ w4UBUFGVM8JEHFUͱTFU4UBUF͸γϯϓϧͰ෼͔Γ΍͍͢ w͔͠͠ɺ8JEHFUͷ֊૚͕ਂ͘ͳΔͱTFU4UBUFͰ͸ݫ͘͠ͳͬͯ͘Δ wྫ͑͹ɺμʔΫϞʔυ΁ͷมߋͱ͔

  14. MaterialApp MainScreen EventDetailScreen EventsScreen GalleryScreen SettingsScreen ScrollablePositionedList EventListTile Text theme

    = light theme.textTheme TFU4UBUFͩͱ ࢠ8JEHFUʹ஋ UIFNF Λ ౉͍ͯ͘͠ඞཁ͕͋Δ
  15. ঢ়ଶ؅ཧʢ1SPWJEFSͱ$IBOHF/PUJGJFSʣ Ұ෦ͷঢ়ଶ؅ཧΛ1SPWJEFSͱ$IBOHF/PUJGJFSͷ૊Έ߹Θͤʹมߋ w1SPWJEFS w%*ͷ࢓૊ΈΛఏڙ͢ΔެࣜϥΠϒϥϦ w4UBUFΛࢠ8JEHFUʹ஫ೖ͢Δ͜ͱͰঢ়ଶ؅ཧʹ΋࢖͑Δ w$IBOHF/PUJGJFS w஋͕มߋ͞Εͨ͜ͱΛࢠ8JEHFUʹ఻͑ΔͨΊͷ࢓૊ΈʢΫϥεʣ wTFU4UBUFతͳ໾ׂ

  16. MaterialApp MainScreen EventDetailScreen EventsScreen GalleryScreen SettingsScreen ScrollablePositionedList EventListTile Text theme

    = light theme.textTheme .BUFSJBM"QQ͕࣋ͭ UIFNFΛ௚઀ࢀরͰ͖Δ
  17. class AppThemeController extends ChangeNotifier { AppTheme _lightTheme; AppTheme _darkTheme; AppThemeMode

    _themeMode; AppTheme get theme => _themeMode == AppThemeMode.light ? _lightTheme : _darkTheme; void setThemeMode(AppThemeMode themeMode) { _themeMode = themeMode; notifyListeners(); } } $IBOHF/PUJGJFSΛܧঝ͠ ͨΫϥεʹ4UBUFΛ࣋ͭ 4UBUFΛม͑ͨΒ OPUJGZ-JTUFOFSTΛݺͼग़͢ ʢTFU4UBUFͱಉ͡Πϝʔδʣ
  18. void main() { runApp( ChangeNotifierProvider( create: (_) => AppThemeController() )

    ); } Widget build(BuildContext context) { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), color: context.select<AppThemeController, Color>( (value) => value.theme.highlightColor), ), child: Column(children: children), ); } શମͰࢀর͍ͨ͠ͷͰ ϧʔτͰఆٛ ֤8JEHFUͰ 4UBUF UIFNF Λࢀর $IBOHF/PUJGJFSΛࢀর ͢ΔͨΊͷ1SPWJEFS
  19. ঢ়ଶ؅ཧ w1SPWJEFSͷ୅ସͱͯ͠3FWFSQPE w$IBOHF/PUJGJFSͷ୅ସͱͯ͠4UBUF/PUJGJFS ͱ͍͏ͷ΋͋Δ  4UBUFGVM8JEHFU TFU4UBUF  1SPWJEFS $IBOHF/PUJGJFS

     1SPWJEFSPS3FWFSQPE 4UBUF/PUJGJFS ͷॱͰ͍֮͑ͯ͘ͱྑͦ͞͏ͩͱײͨ͡
  20. ΧϨϯμʔΛΊ͘Δ6*͕ΧΫπΫʜ wΧϨϯμʔΛΊ͘Δ6*͸ࢦΛಈ͔͢౓ ʹ8JEHFUͷϦϏϧυΛߦ͍ͬͯΔ͔Β ෛՙ͕͔͔͍ͬͯΔʁ

  21. ϦϏϧυͷ࣮ߦίετ wϦϏϧυ͞Εͨ8JEHFUπϦʔΛ΋ͱʹɺ6*ͷϨΠΞ΢τͱඳը͕ߦΘΕ Δ w6*ͷϨΠΞ΢τͱඳը͸ࠩ෼൓ө͞ΕΔ w3FBDU΍7VFͷԾ૝%0.ͱ%0.ͷΠϝʔδ w8JEHFU͸ߏ੒৘ใΛ࣋ͭ୯ͳΔΠϯελϯεͳͷͰɺੜ੒ίετ͸௿͍

  22. ϦϏϧυͷ࠷దԽΛ͢΂͖ύλʔϯ wΞχϝʔγϣϯͳͲͰ୹͍࣌ؒͰ͔ͳΓͷճ ਺ϦϏϧυ͕࣮ߦ͞ΕΔ৔߹͸ཁ஫ҙ wΧϨϯμʔΛΊ͘Δ6*΋ͦͷύλʔϯ wϦϏϧυ͸Ί͘Δ6*෦෼͚ͩͰ͸ͳ͘ɺϖʔ δશମͰߦΘΕΔͨΊ݁ߏߴίετʹͳΔ w࠷దԽ͠ͳͪ͘Όʢ࢖໋ײʣ

  23. ϦϏϧυ͞Ε͍ͯΔՕॴ Ί͘Δ6*ͷ8JEHFU ΧϨϯμʔ6*ͷ8JEHFU ʢؔ܎ͳ͍ͱ͜Ζ·Ͱ ϦϏϧυ͞Ε͍ͯΔ ʣ

  24. ϦϏϧυͷ࠷దԽ Widget build(BuildContext context) { return Container( height: height, child:

    Stack( overflow: Overflow.clip, children: <Widget>[ const _EventPageMain(), Transform.translate( //... ) ], ), ); } Widget build(BuildContext context) { return Container( height: height, child: Stack( overflow: Overflow.clip, children: <Widget>[ Positioned( //... ), Transform.translate( //... ) ], ), ); } ผ8JEHFUʹ෼͚ͯɺ ίϯύΠϧ࣌ఆ਺ʢDPOTUʣ ͱͯ͠ఆٛ
  25. class _EventPageMain extends StatelessWidget { const _EventPageMain(); @override Widget build(BuildContext

    context) { final event = context .select<EventDetailScreenController, Event>((value) => value.event); final eventDate = context .select<EventPageController, EventDate>((value) => value.eventDate); final eventCaptureKey = context.select<EventPageController, GlobalKey>( (value) => value.eventCaptureKey); // ೔Ί͘Γ࣌ʹϦϏϧυ͢ΔͨΊɺselect͓ͯ͘͠ context.select<EventDetailScreenController, DateTime>( (value) => value.event.lastTearOffDate); final statusBarHeight = Device.instance.statusBarHeight; final textColor = getEventTextColor(event, eventDate); final width = MediaQuery.of(context).size.width; return Positioned( //... ); } } 4UBUFMFTT8JEHFUΛܧঝ ίϯετϥΫλͷύϥϝʔ λʔ͕શͯDPOTUͰ͋Δඞཁ ͕͋ΔͨΊɺঢ়ଶ͸1SPWJEFS ͔Βऔಘ ίϯετϥΫλʹ΋DPOTU
  26. Ί͘Δ6*ͷ8JEHFU ΧϨϯμʔ6*ͷ8JEHFU ʢϦϏϧυ͞Εͯͳ͍ ʣ ΧϨϯμʔ6*ͷ8JEHFU ʢϦϏϧυ͞Εͯͳ͍ ʣ

  27. 1MVHJOΛ࡞Δ wࣗࣾαʔϏεʢ#BB4!SBLV[Bʣ࢖͍͍ͨ wωΠςΟϒͷ"1*ʹΞΫηε͢Δ৔߹͸1MVHJOΛ࢖͏ʢͳ͍ͷͰ࡞ͬͨʣ

  28. static const MethodChannel _channel = MethodChannel('baasatrakuza_flutter'); MethodChannel get channel =>

    _channel; @override Future<Data> getData(String objectId, String code) async { final data = await channel.invokeMapMethod<String, dynamic>( 'getData', {'objectId': objectId, 'code': code}); return Data.fromMap(data); } fun getData(call: MethodCall, result: MethodChannel.Result) { val objectId = call.argument<String>("objectId") val code = call.argument<String>("code") this.client.getData(objectId, code) { data, rkzResponseStatus -> if (rkzResponseStatus.isSuccess) { result.success(exportObject(data)) } else { result.error(rkzResponseStatus.statusCode, rkzResponseStatus.message, null) } } } Dart (Flutter) Kotlin (Android) ωΠςΟϒଆͷॲཧ͸ .FUIPE$IBOOFMΛհͯ͠ ݺͼग़͢ .FUIPE$IBOOFM3FTVMUʹ݁ ՌΛ౉͢ͱ%BSUଆʹฦΔ
  29. 1MVHJOͲ͏ͳΜʁ wόΠτྻͰσʔλͷ΍ΓͱΓͰ͖ΔͨΊΦʔόʔϔου͸গͳͦ͏ʢ+40/΋Մೳʣ wࠓճ͸࢖༻͍ͯ͠ͳ͍͕ɺ1MBUGPSN7JFXΛ࢖ͬͯωΠςΟϒͷ6*ίϯϙʔωϯτΛ ඳը͢Δ͜ͱ΋ՄೳʢHPPHMF@NBQT@GMVUUFSͳͲʣ wৄࡉ͸ҎԼΛࢀর͍ͩ͘͞ʂ wIUUQTUFDIQTDTSWDPKQCBBTSBLV[BͷGMVUUFSTEL։ൃத

  30. ศརͳϥΠϒϥϦΛ୳͢ wQVCEFWͰ୳͢

  31. ྫ TDSPMMBCMF@QPTJUJPOFE@MJTU wઌ಄ͷΧϨϯμʔͷ݄͕มΘͬͨΒλΠτϧ ʢ೥݄ʣ΋ม͑Δ wΧϨϯμʔλϒΛλοϓ͢Δͱɺࠓ೔ͷҐஔʹ εΫϩʔϧ͢Δ wͳͲɺඪ४ͷ-JTU7JFXͩͱ೉͍͠εΫϩʔϧॲ ཧΛ؆୯ʹ࣮૷Ͱ͖Δ

  32. ίϯςετͰ'MVUUFSΞϓϦ࡞ͬͯΈͯ w'MVUUFSͷධՁ wੜ࢈ੑ͸ߴ͍ɻ)PU3FMPBE͕ΊͬͪΌศར wֶशίετ͸ߴ͍ͱݴΘΕΔ͕ɺ3FBDU΍7VFͳͲͷએݴత6*ͷ։ൃʹ׳Ε͍ͯΕ ͹ͦΕ΄ͲͰ΋ͳ͍ʢ%BSU͸4XJGUͱ͔5ZQF4DSJQU஌͍ͬͯΕ͹໰୊ͳ͠ʣ w༗༻ͳϥΠϒϥϦ͕ଟ͘ɺ৽͍͠؀ڥͷΘΓʹॆ࣮͍ͯ͠Δ wίϯςετ wΞϓϦ࡞Γͳ͕Βͩͱ֮͑Δͷ͕ૣ͍ʢ͋ͱ ͷϞνϕʔγϣϯʣ wҰॹʹ࡞Δਓ͕͍ΔͱϞνϕʔγϣϯ্͕͕Δ

    wίϯςετ͸ܦݧऀΛ૿΍͢ྑ͍ࢪࡦ͔΋
  33. ࠷ޙʹ

  34. 'MVUUFS։ൃऀΛ૿΍͍ͨ͠ w'MVUUFS͸ૉ੖Β͍ٕ͠ज़͕ͩɺ8FC΍ωΠςΟϒܥͷΤίγεςϜʢͱ ΓΘ͚ٕज़ऀʣΛͦͷ··औΓࠐΊͳ͍ wͦ͜Ͱɺࣾ಺Ͱ·ٕͣज़ऀΛ૿΍ͨ͢ΊʹίϯςετΛ։࠵ wԬࢁશମͰ΋ٕज़ऀΛ૿΍͍͖͍ͯͨ͠ wͱࢥͬͯɺ͓࿩͍͖ͤͯͨͩ͠͞·ͨ͠ wڵຯ͕͋Ε͹ͥͻ'MVUUFS৮ͬͯΈͯԼ͍͞ʂ