Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Flutterコンテストを開催した話
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Daisuke Kishino
November 03, 2020
Programming
460
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Flutterコンテストを開催した話
Daisuke Kishino
November 03, 2020
More Decks by Daisuke Kishino
See All by Daisuke Kishino
Monaca、WKWebViewに移行しようぜ!
kishino
0
950
Ionicあらまし@okayama-js
kishino
0
1.1k
MonacaアプリをネイティブのUXに近づけるために
kishino
0
970
Sign In with Appleを実装してみた
kishino
0
440
Fluid interfaces for Monaca
kishino
0
260
Vue.jsの特徴
kishino
0
620
Monacaでアプリ名の多言語化
kishino
0
780
Other Decks in Programming
See All in Programming
Dataformのリポジトリを立ち上げるときにまずやること / dataform-day0-2026
snhryt
0
170
Contextとはなにか
chiroruxx
1
330
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
260
Honoでのサプライチェーン侵害対策 〜 3つのライブラリに学ぶ
yusukebe
6
1.3k
Lessons from Spec-Driven Development
simas
PRO
0
210
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
11
4.2k
Creating Composable Callables in Contemporary C++
rollbear
0
140
TypeScript+Orvalで実現する型安全かつ堅牢でスケーラブルなマルチチャネル通知基盤 / TSKaigi Night talks ~after conference~
d0riven
0
340
CSC307 Lecture 17
javiergs
PRO
0
320
Java × distroless で 軽量なコンテナイメージを / Java on Distroless
contour_gara
0
550
Developing with AI Agents — Codex, Claude Code & Cowork Practical Guide
x5gtrn
PRO
0
1.3k
AI 輔助遺留系統現代化的經驗分享
jame2408
1
230
Featured
See All Featured
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
230
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
200
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Optimising Largest Contentful Paint
csswizardry
37
3.7k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
The SEO identity crisis: Don't let AI make you average
varn
0
490
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Leo the Paperboy
mayatellez
7
1.8k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
730
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.1k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
Transcript
'MVUUFSίϯςετΛ։࠵ͨ͠ %BJTVLF,JTIJOP ߹ಉษڧձJOେձԬࢁ8JOUFS0OMJOF
ࣗݾհ w ϐʔϓϧιϑτΣΞגࣜձࣾ w ؛େีʢ!LJTIJTVLFʣ w Ԭࢁݝෑࢢࡏॅ w ͜͜εϚϗΞϓϦ։ൃ͕ϝΠϯ ʢ.POBDBɺ7VFKTɺ4XJGUͱ͔ʣ
w .POBDB6(0,":"."ͬͯ·͢
ࠓ͢͜ͱ wࣗࣾͰ'MVUUFSΞϓϦίϯςετΛߦͬͨ wࢀՃऀͱͯࣗ͠'MVUUFSΞϓϦΛॳΊͯຊ࡞ͬͨ wίϯςετͷऔΓΈ'MVUUFSͷհΛߦ͍ͭͭɺ࡞ͬͨ ΞϓϦͰͷܦݧΛ͓͠·͢
'MVUUFSͱʁ w(PPHMF͕։ൃ͍ͯ͠ΔΫϩεϓϥοτϑΥʔϜΞϓϦ։ൃπʔϧ w8JEHFUπϦʔͰ6*Λߏஙʢ3FBDUɺ7VFͷԾ%0.ಉ͡Πϝʔδʣ w4LJBͰϨϯμϦϯάΛߦ͏ʢωΠςΟϒͷ6*ίϯϙʔωϯτʹґଘ͍ͯ͠ ͳ͍ʣ w։ൃݴޠ%BSU w։ൃத%BSU7.ʹΑΔ)PU3FMPBEͰߴ։ൃ wετΞެ։࣌"05Ͱߴಈ࡞
'MVUUFSίϯςετ։࠵ͷ͖͔͚ͬ w'MVUUFSؒΛ૿ͯ͠։ൃͷϞνϕʔγϣϯ্͍͛ͨɻ͔͠͠ɺதʑ ू·Βͳ͍ʜ wۚग़ͯ͠ίϯςετΛ։࠵ͨ͠Βू·Δ͔ʁ wͪͳΈʹओ࠵ऀผͷํͰ͢ wࢲٕज़αϙʔτͱ͍͏ׂʢॳ৺ऀͳͷʹαϙʔτͱͳʁʣ
'MVUUFSίϯςετΛ։࠵͢ΔϝϦοτ w'MVUUFSͷٕज़ऀ͕૿͑Δʂ wࣾΠϕϯτͷࢀՃऀ͕૿͑Δʂʂ wձࣾͷΞϐʔϧʹͳΔʂʂʂ
'MVUUFSίϯςετͷ֓ཁ wԠืظؒࠓͷʙ݄ w։ൃ༻ͷ"OESPJEΛ wษڧձ4MBDLͰϑΥϩʔΞοϓ wදজɺΞΠσΞɺ69ɺ༗ӹੑͷΧςΰϦʔͱάϥϯϓϦ wਓͷΤϯτϦʔʂʢఏग़͕͋ͬͨͷΞϓϦʣ w৽ਓ໊ʴϕςϥϯ໊Ͱ৹ࠪ wۚ͋Γʢձࣾ࣋ͪʣ wͦͷଞɺৄࡉҎԼهࣄͰհ͍ͯ͠·͢ʂ wIUUQTUFDIQTDTSWDPKQࣾΞϓϦίϯςετΛ࣮ࢪͯ͠Έͯ
࡞ͬͨΞϓϦͷհ wٯΊ͘ΓΧϨϯμʔ w͋ͱԿ͔ͳʁΛָ͘͢͠ΔΧϯτμ ϯΞϓϦ wखಈͰΊ͘Γ͢Δ6*ͳͷ͕ಛ w࣮ੲϦϦʔεͯͨ͠ΞϓϦͷϦϝΠΫ wͪͳΈʹࢲ͍͖ͨͩ·ͨ͠
͔͜͜Βٕज़తͳͰ͢ ΞϓϦΛ࢝Ίͯ࡞ͬͯΈͯɺ͜͜ॏཁͩͳ ͱࢥͬͨͱ͜ΖͳͲΛϐοΫΞοϓ͠·ͨ͠
ঢ়ଶཧ wঢ়ଶཧʢ7VFKTͰ͍͏ͱ͜ΖͷEBUB7VFYʣͲ͏͢ΔΜͩΖ͏ʁ w#-P$ͱ͔4UBUF/PUJGJFSͱ͔ɺ͍Ζ͍ΖΓํ͕͋ΔΈ͍͚ͨͩͲʜ
ঢ়ଶཧ w·ͣγϯϓϧʹ4UBUFGVM8JEHFUͱTFU4UBUFͰ࣮ w4UBUFGVM8JEHFU4UBUFʢঢ়ଶʣΛ࣋ͭ8JEHFU wঢ়ଶΛ࣋ͨͳ͍4UBUFMFTT8JEHFU͋Δ w4UBUFͷใΛͱʹ8JEHFUΛߏங͢Δ
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͕ؔ ࠶࣮ߦʢϦϏϧυʣ͞Ε ͕ඳը͞ΕΔ
ঢ়ଶཧ w4UBUFGVM8JEHFUͱTFU4UBUFγϯϓϧͰ͔Γ͍͢ w͔͠͠ɺ8JEHFUͷ֊͕ਂ͘ͳΔͱTFU4UBUFͰݫ͘͠ͳͬͯ͘Δ wྫ͑ɺμʔΫϞʔυͷมߋͱ͔
MaterialApp MainScreen EventDetailScreen EventsScreen GalleryScreen SettingsScreen ScrollablePositionedList EventListTile Text theme
= light theme.textTheme TFU4UBUFͩͱ ࢠ8JEHFUʹ UIFNF Λ ͍ͯ͘͠ඞཁ͕͋Δ
ঢ়ଶཧʢ1SPWJEFSͱ$IBOHF/PUJGJFSʣ Ұ෦ͷঢ়ଶཧΛ1SPWJEFSͱ$IBOHF/PUJGJFSͷΈ߹Θͤʹมߋ w1SPWJEFS w%*ͷΈΛఏڙ͢ΔެࣜϥΠϒϥϦ w4UBUFΛࢠ8JEHFUʹೖ͢Δ͜ͱͰঢ়ଶཧʹ͑Δ w$IBOHF/PUJGJFS w͕มߋ͞Εͨ͜ͱΛࢠ8JEHFUʹ͑ΔͨΊͷΈʢΫϥεʣ wTFU4UBUFతͳׂ
MaterialApp MainScreen EventDetailScreen EventsScreen GalleryScreen SettingsScreen ScrollablePositionedList EventListTile Text theme
= light theme.textTheme .BUFSJBM"QQ͕࣋ͭ UIFNFΛࢀরͰ͖Δ
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ͱಉ͡Πϝʔδʣ
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
ঢ়ଶཧ w1SPWJEFSͷସͱͯ͠3FWFSQPE w$IBOHF/PUJGJFSͷସͱͯ͠4UBUF/PUJGJFS ͱ͍͏ͷ͋Δ 4UBUFGVM8JEHFU TFU4UBUF 1SPWJEFS $IBOHF/PUJGJFS
1SPWJEFSPS3FWFSQPE 4UBUF/PUJGJFS ͷॱͰ͍֮͑ͯ͘ͱྑͦ͞͏ͩͱײͨ͡
ΧϨϯμʔΛΊ͘Δ6*͕ΧΫπΫʜ wΧϨϯμʔΛΊ͘Δ6*ࢦΛಈ͔͢ ʹ8JEHFUͷϦϏϧυΛߦ͍ͬͯΔ͔Β ෛՙ͕͔͔͍ͬͯΔʁ
ϦϏϧυͷ࣮ߦίετ wϦϏϧυ͞Εͨ8JEHFUπϦʔΛͱʹɺ6*ͷϨΠΞτͱඳը͕ߦΘΕ Δ w6*ͷϨΠΞτͱඳըࠩө͞ΕΔ w3FBDU7VFͷԾ%0.ͱ%0.ͷΠϝʔδ w8JEHFUߏใΛ࣋ͭ୯ͳΔΠϯελϯεͳͷͰɺੜίετ͍
ϦϏϧυͷ࠷దԽΛ͖͢ύλʔϯ wΞχϝʔγϣϯͳͲͰ͍࣌ؒͰ͔ͳΓͷճ ϦϏϧυ͕࣮ߦ͞ΕΔ߹ཁҙ wΧϨϯμʔΛΊ͘Δ6*ͦͷύλʔϯ wϦϏϧυΊ͘Δ6*෦͚ͩͰͳ͘ɺϖʔ δશମͰߦΘΕΔͨΊ݁ߏߴίετʹͳΔ w࠷దԽ͠ͳͪ͘Όʢ໋ײʣ
ϦϏϧυ͞Ε͍ͯΔՕॴ Ί͘Δ6*ͷ8JEHFU ΧϨϯμʔ6*ͷ8JEHFU ʢؔͳ͍ͱ͜Ζ·Ͱ ϦϏϧυ͞Ε͍ͯΔ ʣ
ϦϏϧυͷ࠷దԽ 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ʣ ͱͯ͠ఆٛ
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
Ί͘Δ6*ͷ8JEHFU ΧϨϯμʔ6*ͷ8JEHFU ʢϦϏϧυ͞Εͯͳ͍ ʣ ΧϨϯμʔ6*ͷ8JEHFU ʢϦϏϧυ͞Εͯͳ͍ ʣ
1MVHJOΛ࡞Δ wࣗࣾαʔϏεʢ#BB4!SBLV[Bʣ͍͍ͨ wωΠςΟϒͷ"1*ʹΞΫηε͢Δ߹1MVHJOΛ͏ʢͳ͍ͷͰ࡞ͬͨʣ
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ଆʹฦΔ
1MVHJOͲ͏ͳΜʁ wόΠτྻͰσʔλͷΓͱΓͰ͖ΔͨΊΦʔόʔϔουগͳͦ͏ʢ+40/Մೳʣ wࠓճ༻͍ͯ͠ͳ͍͕ɺ1MBUGPSN7JFXΛͬͯωΠςΟϒͷ6*ίϯϙʔωϯτΛ ඳը͢Δ͜ͱՄೳʢHPPHMF@NBQT@GMVUUFSͳͲʣ wৄࡉҎԼΛࢀর͍ͩ͘͞ʂ wIUUQTUFDIQTDTSWDPKQCBBTSBLV[BͷGMVUUFSTEL։ൃத
ศརͳϥΠϒϥϦΛ୳͢ wQVCEFWͰ୳͢
ྫ TDSPMMBCMF@QPTJUJPOFE@MJTU wઌ಄ͷΧϨϯμʔͷ݄͕มΘͬͨΒλΠτϧ ʢ݄ʣม͑Δ wΧϨϯμʔλϒΛλοϓ͢ΔͱɺࠓͷҐஔʹ εΫϩʔϧ͢Δ wͳͲɺඪ४ͷ-JTU7JFXͩͱ͍͠εΫϩʔϧॲ ཧΛ؆୯ʹ࣮Ͱ͖Δ
ίϯςετͰ'MVUUFSΞϓϦ࡞ͬͯΈͯ w'MVUUFSͷධՁ wੜ࢈ੑߴ͍ɻ)PU3FMPBE͕ΊͬͪΌศར wֶशίετߴ͍ͱݴΘΕΔ͕ɺ3FBDU7VFͳͲͷએݴత6*ͷ։ൃʹ׳Ε͍ͯΕ ͦΕ΄ͲͰͳ͍ʢ%BSU4XJGUͱ͔5ZQF4DSJQU͍ͬͯΕͳ͠ʣ w༗༻ͳϥΠϒϥϦ͕ଟ͘ɺ৽͍͠ڥͷΘΓʹॆ࣮͍ͯ͠Δ wίϯςετ wΞϓϦ࡞Γͳ͕Βͩͱ֮͑Δͷ͕ૣ͍ʢ͋ͱ ͷϞνϕʔγϣϯʣ wҰॹʹ࡞Δਓ͕͍ΔͱϞνϕʔγϣϯ্͕͕Δ
wίϯςετܦݧऀΛ૿͢ྑ͍ࢪࡦ͔
࠷ޙʹ
'MVUUFS։ൃऀΛ૿͍ͨ͠ w'MVUUFSૉΒ͍ٕ͠ज़͕ͩɺ8FCωΠςΟϒܥͷΤίγεςϜʢͱ ΓΘ͚ٕज़ऀʣΛͦͷ··औΓࠐΊͳ͍ wͦ͜ͰɺࣾͰ·ٕͣज़ऀΛ૿ͨ͢ΊʹίϯςετΛ։࠵ wԬࢁશମͰٕज़ऀΛ૿͍͖͍ͯͨ͠ wͱࢥͬͯɺ͓͍͖ͤͯͨͩ͠͞·ͨ͠ wڵຯ͕͋Εͥͻ'MVUUFS৮ͬͯΈͯԼ͍͞ʂ