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
Textの構造を理解する/Understanding the Structure of Text
Search
Kakeru Nakabachi
November 29, 2021
Programming
2.7k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Textの構造を理解する/Understanding the Structure of Text
Kakeru Nakabachi
November 29, 2021
More Decks by Kakeru Nakabachi
See All by Kakeru Nakabachi
Flutterアプリで可用性を向上させたFeatureFlagの運用戦略とその方法
b4tchkn
0
1.9k
Inside Flutter Text
b4tchkn
1
290
Flutterアプリのセキュリティ対策を考えてみる
b4tchkn
6
8k
チームで採用しているriverpodを使ったFlutterのアーキテクチャとriverpod v1.0.0
b4tchkn
6
5k
Other Decks in Programming
See All in Programming
CSC307 Lecture 17
javiergs
PRO
0
320
AIだと陥りがちなJakarta EE最新技術への移行時の落とし穴と解決策
tnagao7
0
110
New "Type" system on PicoRuby
pocke
1
920
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
6k
技術記事、AIに書かせるか、自分で書くか? 〜それでも私が自分の手で書く理由〜 / #QiitaConference
jnchito
2
1.4k
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
2
640
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
130
The ROI of Quarkus for Spring Boot Applications
hollycummins
0
120
dRuby over BLE
makicamel
2
340
TAKTでAI駆動開発の品質を設計する
j5ik2o
6
1.3k
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
2.1k
スマートグラスで並列バイブコーディング
hyshu
0
140
Featured
See All Featured
How STYLIGHT went responsive
nonsquared
100
6.2k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.7k
Done Done
chrislema
186
16k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
860
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Faster Mobile Websites
deanohume
310
31k
WENDY [Excerpt]
tessaabrams
11
38k
Paper Plane
katiecoart
PRO
1
51k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
300
Transcript
Textの構造を理解する Flutter Kaigi 2021 November 29-30, 2021
Kakeru Nakabachi - batch CyberAgent, Inc 株式会社WinTicketでモバイルアプリをFlutterでリ プレイス中 About me
2
本セッションのゴール Textの構造を理解して実装できるようになる💪💪 3
アジェンダ • Text • Textの構造 • AndroidとiOSでTextを描画したときの問題について • チームで対応した問題の対処法 •
まとめ 4
Text 5
Text 文字を表示するためのWidget • プロパティたち ◦ maxLines ◦ overflow ◦ strutStyle
◦ style ◦ textAlign ◦ textHeightBehavior ◦ ... https://api.flutter.dev/flutter/widgets/Text-class.html 6
Text 文字を表示するためのWidget • プロパティたち ◦ maxLines ◦ overflow ◦ strutStyle
◦ style ◦ textAlign ◦ textHeightBehavior ◦ ... https://api.flutter.dev/flutter/widgets/Text-class.html debugLabel fontFamily fontFamilyFallback fontSize fontStyle fontWeight forceStrutheight hashCode height leading leadingDistribution 7 TextStyleのプロパティ
Text 8 https://api.flutter.dev/flutter/painting/TextStyle-class.html
Text 9 https://api.flutter.dev/flutter/painting/TextStyle-class.html
Text 文字を表示するためのWidget • maxLines • overflow • strutStyle • style
• textAlign • textHeightBehavior • ... https://api.flutter.dev/flutter/widgets/Text-class.html 10
Text 文字を表示するためのWidget • maxLines • overflow • strutStyle • style
• textAlign • textHeightBehavior • ... https://api.flutter.dev/flutter/widgets/Text-class.html 11
Text 文字を表示するためのWidget • maxLines • overflow • strutStyle • style
• textAlign • textHeightBehavior • ... https://api.flutter.dev/flutter/widgets/Text-class.html 12
Textの構造 13
Textの構造 このようなTextを表示した場合、どのような構造でTextが構築されて表示されて いるかをみていく Flutterのvisual debuggingツールを有効化 https://flutter.dev/docs/testing/debugging#visual-debugging https://docs.flutter.dev/development/tools/devtools/inspector 14
Textの構造 実行結果 Android https://api.flutter.dev/flutter/painting/TextStyle-cl ass.html Textが確保している領域 15
Textの構造 実行結果 Android https://api.flutter.dev/flutter/painting/TextStyle-cl ass.html Textのbaseline 16
それぞれの線の意味 baseline ascent: baselineから上部までの高さ descent: baselineから下部までの高さ leading: ある行の下端から次の行の上端までの高さ、TextStyle.height * TextStyle.fontSize
- TextStyle.fontSize これらを意識してTextをつくっていく。今回は以下の3つにフォーカスする height、leadingDistribution、textHeightBehavior Textの構造 AaBbGgJj 17
Textの構造 • height 行の高さをフォントサイズの倍数で調整で きる nullと1.0は別の意味 18 https://api.flutter.dev/flutter/painting/TextStyle-class.html
Textの構造 • leadingDistribution leadingを上下にどのように配置するかを決める。 asent descent Top leading Bottom leading
19
Textの構造 • leadingDistribution TextLeadingDistribution.proportionalと.evenがある leadingを上下にどのように配置するかを決める。nullの場合は TextLeadingDistribution.proportionalと同じ挙動 20
Textの構造 • leadingDistribution leadingを上下にどのように配置するかを決める。 TextLeadingDistribution.evenにした場合はascentとdescentから上下に等 しくleadingが設定される 21
Textの構造 • textHeightBehavior applyHeightToFirstAscentとapplyHeightToLastDescentのbool値を設定す ることでTextの上下のleadingを除くことができる デフォルトはtrueでleadingあり falseを設定してleadingを除いた場合、textHeightBehaviorは効かなくなる 22
Textの構造 • heightとleadingDistributionとtextHeightBehavior Configuration 1 fontSizeとheight以外はすべてデフォル ト設定 leadingDistributionは TextLeadingDistribution.proportional 23
Textの構造 • heightとleadingDistributionとtextHeightBehavior Configuration 2 Configuration 1に TextHeightBehavior.applyHeightToFir stAscentをfalseに設定 24
Textの構造 • heightとleadingDistributionとtextHeightBehavior Configuration 3 leadingDistributionを TextLeadingDistribution.evenに設定 25
Textの構造 • heightとleadingDistributionとtextHeightBehavior Configuration 4 Configuration 3の設定に TextHeightBehavior.applyHeightToLa stDescentにfalseを追加で設定したとき 26
Textの構造 • 複数行の場合 27
Textの構造 • 複数行の場合 height: 2.5を追加 28
Textの構造 • 複数行の場合 TextHeightBehavior.applyHeightToFirstAscent: falseを追加 29
Textの構造 • 複数行の場合 TextHeightBehavior.applyHeightToLastDescent: falseを追加 30
Textの構造 • 複数行の場合 leadingDistributionにTextLeadingDistribution.proportionalの設定 31
Textの構造 • 複数行の場合 leadingDistributionにTextLeadingDistribution.evenの設定 32
Textの構造 • 複数行の場合 TextStyleのleadingDistributionとTextHeightBehaviorの leadingDistribution TextStyle側が優先されて使われる 33
Textの構造 • 複数行の場合 TextStyleのleadingDistributionとTextHeightBehaviorの leadingDistribution TextStyle側が優先されて使われる 34
AndroidとiOSでTextを描画したときの 問題について 35
問題1:OSごとにTextのサイズが違う • 実はAndroidとiOSでは同じフォントサイズなどstyleの設定でもTextの高さ が異なる ➢ 高さ固定のWidgetの中にTextなど配置した場合に、片方のOSでは収ま るけど、もう一方では収まらなかったり、OS間で異なったデザインにな る 両OSのデザインがある場合は大丈夫 弊チームではiOSのデザインしかなくどのように対応するか考える必要があった
36
問題1:OSごとにTextのサイズが違う 実はiOSとAndroidでは同じフォントサイズなどの設定でもTextの高さが異なる Android 37
問題1:OSごとにTextのサイズが違う 実はiOSとAndroidでは同じフォントサイズなどの設定でもTextの高さが異なる iOS 38
問題1:OSごとにTextのサイズが違う なぜ起こる? OSによってleadingの高さが違う、、? →TextHeightBehaviorを設定して上下のleadingをなくしたらどうなるか AaBbGgJj 39
問題1:OSごとにTextのサイズが違う TextHeightBehaviorを設定してみる Android 40
問題1:OSごとにTextのサイズが違う TextHeightBehaviorを設定してみる iOS 41
問題1:OSごとにTextのサイズが違う AndroidとiOSでTextHeightBehaviorの設定の挙動が違いそう?バグ、、? Android iOS 42
問題1:OSごとにTextのサイズが違う 結論:fontFamilyを指定しなかった場合、OSごとに読み込まれるフォントが異 なり、ascentとdescentが異なるため Android Pixel 4a 和文フォント:Noto Sans Japanese? 欧文フォント:Roboto
iOS iPhone 12 Pro 和文フォント:ヒラギノ角ゴシック 欧文フォント:San Francisco Pro 43
問題1:OSごとにTextのサイズが違う TextStyle.backgroundColorを設定して、Textの中でフォントが確保している領域 を見てみる。和文フォントで大きく確保する領域に違いがある Android iOS 44
問題1:OSごとにTextのサイズが違う TextStyle.backgroundColorを設定して、Textの中でフォントが確保している領域 を見てみる。和文フォントで大きく確保する領域に違いがある Android iOS Androidのフォントが確保している領域が iOSより広い 45
問題2:Androidだと文字が下寄りに見える https://github.com/flutter/flutter/issues/79931 46
問題2:Androidだと文字が下寄りに見える Android iOS 24.0 32.0 fontSize 47
問題2:Androidだと文字が下寄りに見える Androidの方がフォントがデフォルトで確保している ascentとdescentが大きく、ascentの方が大きいので 下寄りに見える Android iOS 48
問題2:Androidだと文字が下寄りに見える Androidの方がフォントがデフォルトで確保しているascentと descentが大きく、ascentの方が大きいので下寄りに 見える Android iOS 49
チームで対応した問題の対処法 50
チームで対応した問題の対処法 ▪ 一般的な対処法と思われるもの • AndroidとiOSで共通のascentとdescentが小さいフォントを使う • AndroidだけiOSのシステムフォントのようなascentとdescentが小さい フォントを使う 51
チームで対応した問題の対処法 ▪ 一般的な対処法と思われるもの • AndroidとiOSで共通のascentとdescentが小さいフォントを使う • AndroidだけiOSのシステムフォントのようなascentとdescentが小さい フォントを使う ➢ 弊チームでの対応はこれ
52
チームで対応した問題の対処法 ▪ AndroidでiOSのシステムフォントのようなascentとdescentが小さいフォン トを使うためには Androidで角ゴシックを使えば両プラットフォームで全く同じTextにすることが できるが、、、 ➢ Androidユーザは普段と違うフォントを目にすることになって違和感か もしれない ➢
ライセンス問題( https://developer.apple.com/forums/thread/89094 ) 53
チームで対応した問題の対処法 ▪ Android用にascentとdescentが小さいフォントを用意する必要がある ➢ NotoSans CJKを使用 CJK = Chinese Japanese
Korean 今はJapaneseのみが入ったファイルサイズの小さいNotoSansJapaneseがあ る https://fonts.google.com/noto/specimen/Noto+Sans+JP 54
チームで対応した問題の対処法 ▪ Android用にascentとdescentが小さいフォントを用意する必要がある NotoSans CJKのままでは、中国語や韓国語など使わないフォントも多いので、サ ブセット化してフォントファイルサイズを削減 .otf → .woff →
.ttf → サブセット化(JIS第1水準+JIS第2水準+その他) NotoSans CJK RegularとNotoSans CJK Boldを用意 サブセット化前 サブセット化後 34MB 3MB 55
チームで対応した問題の対処法 ▪ Android用にascentとdescentが小さいフォントを用意する必要がある コンバートする段階でascentとdescentが除かれたフォントができあがることを 利用してiOSのフォントのような扱いをしている https://github.com/minoryorg/Noto-Sans-CJK-JP ライセンス的には商用利用可、改変可 https://fonts.google.com/noto/use#bundle-noto-fonts-with-your-native-app https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL 56
チームで対応した問題の対処法 ▪ Android用にascentとdescentが小さいフォントを用意する必要がある フォントの指定方法 なにも指定がない場合、OSのデフォルトのシステムフォントが使われる 57 ← 最初に読み込もうとするフォントを指定 ← fontFamilyで対応できなかった文字を描画す
るためのフォントを指定
チームで対応した問題の対処法 ▪ Android用にascentとdescentが小さいフォントを用意する必要がある フォントの指定方法 用意したフォントは日本語表示用に、英語はシステムフォントでデフォルトで選 択されるRobotoを使いたい fontFamilyに何も指定しない場合→Robotoが使われる 日本語を表示しようとしたとき、Robotoだけでは対応できずfontFamilyFallback に設定されているフォントを読み込もうとする なので、今回は用意したフォントをfontFamilyFallbackに設定
58
チームで対応した問題の対処法 ▪ ボタンなどの垂直方向の中央に文字が表示されるようにleadingの調整 ascentとdescentが小さいフォントを使うことにより、 デフォルトのleadingが効 くようになり、文字が厳密にはまだ中心に配置されていない TextStyle.leadingDistributionにTextLeadingDistribution.evenを設定して、上 下に等しくleadingを配置して文字が垂直方向に中心に配置されるようにする 59 フォント変更前
フォント変更後
まとめ • Textは様々な要素で構成されている • AndroidとiOSではフォントを指定しない場合、読み込むシステムフォントが それぞれ違うため、全く同じ見た目のTextを描画しない ◦ 高さが違う ◦ 文字が下よりに見える
• 対応方法の1つにAndroidのときはデフォルトでasecntとdescentが大きいシ ステムフォントが使われるため、それらが小さいフォントを指定してiOSの 挙動に近づける • TextStyle.leadingDistributionにTextLeadingDistribution.evenを設定して 上下のleadingを均等に配分して文字を中央にする 60
参考 • https://flutter.dev/docs/testing/debugging#visual-debugging • https://flutter.dev/docs/development/tools/devtools/inspector • https://stackoverflow.com/questions/56799068/what-is-the-strutstyl e-in-the-flutter-text-widget • https://api.flutter.dev/flutter/painting/TextStyle-class.html
• https://github.com/flutter/flutter/issues/79931 • https://fonts.google.com/noto/use#bundle-noto-fonts-with-your-nativ e-app • https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL • https://github.com/minoryorg/Noto-Sans-CJK-JP 61
Thank you 62