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を言い訳にしない!アプリの使い心地改善テクニック5選🔥
Search
Kuno Ayana
November 20, 2024
Programming
3
590
Flutterを言い訳にしない!アプリの使い心地改善テクニック5選🔥
FlutterKaigi 2024 の LT です!
Kuno Ayana
November 20, 2024
Tweet
Share
More Decks by Kuno Ayana
See All by Kuno Ayana
iOS 18 がやってきた!
kno3a87
1
170
おうちハッカソン #2
kno3a87
0
120
ミクアカ成果報告会
kno3a87
0
22
SXSW2021
kno3a87
0
39
ミクアカ中間発表会
kno3a87
0
13
大学院進学ガイダンス
kno3a87
0
75
画像処理論セミナー7-1-3
kno3a87
0
15
内定者自己紹介LT
kno3a87
0
69
画像処理論セミナー7-1,2
kno3a87
0
13
Other Decks in Programming
See All in Programming
Внедряем бюджетирование, или Как сделать хорошо?
lamodatech
0
930
ESLintプラグインを使用してCDKのセオリーを適用する
yamanashi_ren01
2
230
AWSのLambdaで PHPを動かす選択肢
rinchoku
2
390
歴史と現在から考えるスケーラブルなソフトウェア開発のプラクティス
i10416
0
300
AWS re:Invent 2024個人的まとめ
satoshi256kbyte
0
100
はてなにおけるfujiwara-wareの活用やecspressoのCI/CD構成 / Fujiwara Tech Conference 2025
cohalz
2
2.6k
Fibonacci Function Gallery - Part 2
philipschwarz
PRO
0
210
「とりあえず動く」コードはよい、「読みやすい」コードはもっとよい / Code that 'just works' is good, but code that is 'readable' is even better.
mkmk884
6
1.4k
ErdMap: Thinking about a map for Rails applications
makicamel
1
580
Fixstars高速化コンテスト2024準優勝解法
eijirou
0
190
DMMオンラインサロンアプリのSwift化
hayatan
0
170
AHC041解説
terryu16
0
340
Featured
See All Featured
Unsuck your backbone
ammeep
669
57k
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
3
350
Art, The Web, and Tiny UX
lynnandtonic
298
20k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
38
1.9k
VelocityConf: Rendering Performance Case Studies
addyosmani
327
24k
Reflections from 52 weeks, 52 projects
jeffersonlam
348
20k
Fashionably flexible responsive web design (full day workshop)
malarkey
406
66k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
1.2k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
Practical Orchestrator
shlominoach
186
10k
Transcript
ʙΞϓϦͷ͍৺վળςΫχοΫબʙ 'MVUUFSΛݴ͍༁ʹ͠ͳ͍ʂ
None
ͳΜ͔εΫϩʔϧ͢Δͱ ΧΫπΫΜ͚ͩͲʜ
ͳΜ͔εΫϩʔϧ͢Δͱ ΧΫπΫΜ͚ͩͲʜ ͔ͣͬ͠ͱݟͯΔͱ ͕͘ͳͬͯΔؾ͕͢Δʂ
None
ಈը͕දࣔ͞Ε͍ͯΔͱ͖ʹͦ͏
None
˞J1IPOF J04 Λ༻
None
Ƃō
None
5FYUVSF8JEHFU͏ͱ ݹΊͷJ1IPOFͰύϑΥʔϚϯε͕ൃੜ 1MBUGPSN7JFXΛ͓͏ʂ
None
ݱࡏͷϏσΦϑϨʔϜͷ(16্ͷϐΫηϧόοϑΝʔΛ ຖϑϨʔϜ$16ʹίϐʔ͍ͯ͠Δ ͦΕ͕ॏͦ͏ʁ
1MBUGPSN7JFX͔͓ͭ?@?
None
ݟ͚ͭͨʂʂʂ ˞࣮ࡍͷϓϩμΫτͰɼωΠςΟϒଆͰ)-4ϓϨΠϦετͷඇಉظϩʔυ͕ඞཁͩͬͨΓ )%3ରԠ͕ඞཁͩͬͨΓͨ͠ͷͰɼͪ͜ΒͷϥΠϒϥϦΛࢀߟʹϑϧεΫϥονͯ͠·͢
˞J1IPOF J04 Λ༻
None
ͳΜ͔ΞΠίϯઃఆ ө͞ΕΔ·Ͱ͘ͳ͍ʁ
None
UP#ZUF%BUBͰQOHΛ%BSU7.Ͱ Τϯίʔυ͢Δͱ͜ΖͰ͕͔͔࣌ؒͬͯΔ
ϥΠϒϥϦଆͰը૾ʹͤͣ 3(#"όΠτͷ··ฦ͢Α͏ʹϥΠϒϥϦΛվ ωΠςΟϒଆͰ3(#"ΛΫϩοϓͯ͠ը૾Խ͢ΔΑ͏ʹʂ
None
None
J1IPOF࣌ܭͷͱ͜λοϓͰϦετ͕ Ұ൪্·Ͱͬͯཉ͍͠Μ͚ͩͲʜ
None
Ұ൪্·ͰεΫϩʔϧͯ͘͠Εͳ͍ʜ
4DB ff PME -JTU7JFX
4DB ff PME -JTU7JFX 1SJNBSZ4DSPMM$POUSPMMFS
4DB ff PME -JTU7JFX 1SJNBSZ4DSPMM$POUSPMMFS 1SJNBSZ4DSPMM$POUSPMMFS
4DB ff PME -JTU7JFX 1SJNBSZ4DSPMM$POUSPMMFS 4DSPMM$POUSPMMFS ԣʹεΫϩʔϧόʔΛग़ͨ͠Γ Ϧετඌ·ͰεΫϩʔϧ͞ΕͨݕΛ͢ΔͨΊՃ
4DB ff PME -JTU7JFX 1SJNBSZ4DSPMM$POUSPMMFS 4DSPMM$POUSPMMFS εΫϩʔϧόʔΛग़ͨ͠Γ Ϧετඌ·ͰεΫϩʔϧ͞ΕͨݕΛ͢ΔͨΊՃ εςʔλεόʔλοϓͷݕ ͬͪ͜ʹ͘Δʂ
4DB ff PME -JTU7JFX 1SJNBSZ4DSPMM$POUSPMMFS 4DSPMM$POUSPMMFS εΫϩʔϧόʔΛग़ͨ͠Γ Ϧετඌ·ͰεΫϩʔϧ͞ΕͨݕΛ͢ΔͨΊՃ εςʔλεόʔλοϓͷݕ ͬͪ͜ʹ͘Δʂ
ແԠʂ
4DB ff PME -JTU7JFX 1SJNBSZ4DSPMM$POUSPMMFS 4DSPMM$POUSPMMFS εΫϩʔϧόʔΛग़ͨ͠Γ Ϧετඌ·ͰεΫϩʔϧ͞ΕͨݕΛ͢ΔͨΊՃ εςʔλεόʔλοϓͷݕ ͬͪ͜ʹ͘Δʂ
ແԠʂ 1SJNBSZ4DSPMM$PUSPMMFSͷ λοϓݕΛΩϟον͢Εྑ͍ʂ
class _FakeScrollPositionWithSingleContext extends ScrollPositionWithSingleContext { _FakeScrollPositionWithSingleContext({ required BuildContext context, required
Future<void> Function() callback, }) : _callback = callback, super( physics: const NeverScrollableScrollPhysics(), context: _FakeScrollContext(context), ); final Future<void> Function() _callback; @override Future<void> animateTo( double to, { required Duration duration, required Curve curve, }) { return _callback.call(); } }
class _FakeScrollPositionWithSingleContext extends ScrollPositionWithSingleContext { _FakeScrollPositionWithSingleContext({ required BuildContext context, required
Future<void> Function() callback, }) : _callback = callback, super( physics: const NeverScrollableScrollPhysics(), context: _FakeScrollContext(context), ); final Future<void> Function() _callback; @override Future<void> animateTo( double to, { required Duration duration, required Curve curve, }) { return _callback.call(); } } ͕ࣗͨͪͨ͠ ίʔϧόοΫ͕ݺΕΔΑ͏ʹ
class _FakeScrollPositionWithSingleContext extends ScrollPositionWithSingleContext { _FakeScrollPositionWithSingleContext({ required BuildContext context, required
Future<void> Function() callback, }) : _callback = callback, super( physics: const NeverScrollableScrollPhysics(), context: _FakeScrollContext(context), ); final Future<void> Function() _callback; @override Future<void> animateTo( double to, { required Duration duration, required Curve curve, }) { return _callback.call(); } } ͕ࣗͨͪͨ͠ ίʔϧόοΫ͕ݺΕΔΑ͏ʹ 4DSPMM1PTJUJPO8JUI4JOHMF$POUFYUΛ ܧঝِͨ͠Λ࡞Δʂ
final primaryScrollController = PrimaryScrollController.maybeOf(Navigator.of(context).context) ?? PrimaryScrollController.maybeOf(context); if (primaryScrollController == null)
return; final scrollPositionWithSingleContext = _FakeScrollPositionWithSingleContext( context: context, callback: widget.onTap, ); primaryScrollController.attach(scrollPositionWithSingleContext);
final primaryScrollController = PrimaryScrollController.maybeOf(Navigator.of(context).context) ?? PrimaryScrollController.maybeOf(context); if (primaryScrollController == null)
return; final scrollPositionWithSingleContext = _FakeScrollPositionWithSingleContext( context: context, callback: widget.onTap, ); primaryScrollController.attach(scrollPositionWithSingleContext); ͦͷِΛ 1SJNBSZ4DSPMM$POUSPMMFSʹΞλονʂ
None
None
J1IPOFඪ४ͱൺͯ ֆจࣈͷදࣔখ͘͞ͳ͍ʁ
None
None
SwiftUI Flutter
SwiftUI Flutter
SwiftUI Flutter খ͍͞Θʂʂʂ
ྗٕͰ ղܾ
import 'package:flutter/material.dart'; class EmojiUtil { static const r = r'[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-
\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED- \u23EF\u23F1\u23F2\u23F8- \u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600- \u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E \u262F\u2638-\u263A\u2640\u2642\u2648- \u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694 - \u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4 \u26C8\u26CF\u26D1\u26E9\u26F0- \u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D \u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05- \u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?| [\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?: \uD83C[\uDFFB-\uDFFF])?|[\u23E9- \u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD \u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]| \u26D3\uFE0F?(?:\u200D\uD83D\uDCA5)?|\u26F9(?:\uFE0F|\uD83C[\uDFFB-
text.splitMapJoin( EmojiUtil.regex, onMatch: (m) { final emojiCharacters = m.group(0)!.characters; for
(final emojiCharacter in emojiCharacters) { state._add(emojiCharacter, true); } return ''; }, onNonMatch: (s) { if (s == '\u200D') { // ZeroWidthJoinerֆจࣈͱͯ͠ొ͓ͯ͘͠ state._add(s, true); } else { state._add(s, false); } return ''; }, ); return state._build(); } }
text.splitMapJoin( EmojiUtil.regex, onMatch: (m) { final emojiCharacters = m.group(0)!.characters; for
(final emojiCharacter in emojiCharacters) { state._add(emojiCharacter, true); } return ''; }, onNonMatch: (s) { if (s == '\u200D') { // ZeroWidthJoinerֆจࣈͱͯ͠ొ͓ͯ͘͠ state._add(s, true); } else { state._add(s, false); } return ''; }, ); return state._build(); } } ड͚औͬͨςΩετΛ ֆจࣈͱจࣈʹׂ
TextStyle _emojiStyle(TextStyle textStyle, double originalFontSize) { if (Platform.isAndroid) { return
textStyle; } else { return textStyle.copyWith( fontSize: textStyle.fontSize! * 1.4, fontFamilyFallback: [], height: 1.0, ); } } ͱΓ͋͑ͣഒʹͯ͠ΈΔʂ
Before After
࣮ࡍͷϓϩμΫτͰͪ͜ΒͷJTTVFΛࢀߟʹɼϑΥϯτͷେ͖͞ʹΑͬͯֆจࣈͷഒΛม͑ͨΓ จࣈͱ֦େֆจࣈͷηϯλʔϥΠϯΛἧ͑ͨΓ͍ͯ͠·͢ʂ
None
ͳΜ͔J1IPOFͩͱ จࣈ͕ࡉͯ͘ݟʹ͍͘ؾ͕͢Δʜ
SwiftUI Flutter
None
None
ϑΥϯτϨϯμϦϯά࣌ͷ ΞϯνΤΠϦΞεͷೱ͕ωΠςΟϒͱҧ͏ʂ
ྗٕͰ ղܾ
return Scaffold( backgroundColor: Colors.white, appBar: AppBar( title: Text(widget.title), ), body:
const Center( child: Stack( children: [ Text( 'Hello, FlutterKaigi 2024 LT!', style: TextStyle(fontSize: 24), ), Text( 'Hello, FlutterKaigi 2024 LT!', style: TextStyle(fontSize: 24), ), ], ), ), );
ild: Stack( children: [ Text( 'Hello, FlutterKaigi 2024 LT!', style:
TextStyle(fontSize: 24), ), Text( 'Hello, FlutterKaigi 2024 LT!', style: TextStyle(fontSize: 24), ),
Before After
˞࣮ࡍͷϓϩμΫτͰͪ͜ΒͷJTTVFίϝϯτIUUQTHJUIVCDPN fl VUUFS fl VUUFSJTTVFTJTTVFDPNNFOUΛࢀߟʹ ͨͩ4UBDLͰॏͶΔͷͰͳ͘4USPLFΛௐͯͨ͠Γ͠·͢ʂ
Sample GitHub: https://github.com/kno3a87/flutterkaigi-2024-lt ͓ΘΓ
,VOP"ZBOB גࣜձࣾ.*9*ͨΜΆΆࣨ 'MVUUFS,BJHJӡӦελοϑ