Save 37% off PRO during our Black Friday Sale! »

ゼロから実装する縦書きTextViewとその周辺技術 / Vertical TextView from Scratch and Related Technologies

2e72046813bf3dc01173fe54919a6d1d?s=47 cc4966
February 08, 2019

ゼロから実装する縦書きTextViewとその周辺技術 / Vertical TextView from Scratch and Related Technologies

ゼロから実装する縦書きTextViewとその周辺技術

発表者: 六々 (@496_)
View + InputConnection + Editable + Bitmapを使って縦書きのTextViewを実装した話をします。
TextVIewやStringを使わなくても文字入力ができるViewを作ることが可能です。

iOS / UWP / Windows / macOS / Ubuntuなどの他プラットフォームでの縦書きTextViewの実装経験も交えて、Androidでの縦書きTextView実装の概要と注意点について話します。
また周辺技術としてUnicodeの話、OpenTypeの仕様を中心としたフォントの話もあります。

# 内容
- TextViewとは何者か
- 文字列入力系としての側面
- フォント描画系としての側面
- IMEとは何か
- 文字入力の仕組み
- IMEとアプリの関係性
- InputConnectionの罠
- StringとEditableについて
- StringとAndroid Studioの関係 (閑話)
- UnicodeとフォントからBitmapが作られるまで
- テキストレンダリングエンジン実装の概要
- フォントの役割とOpenTypeの仕様
- OpenTypeや文字列描画系から見たUnicode Emoji事情 (閑話)
- 昨今のAndroid内のフォント事情
- Variable Fontの登場
- 縦書きTextView実装で気をつけるべきこと

受講対象者
文字についてUnicode / IME / フォントと言われて何となくイメージが浮かぶ方を対象にしています。

特に: TextViewの独自実装に興味のある方 / 文字入力システムに興味のある方 / 文字描画システムに興味のある方 / 縦書きに興味のある方 に聞いてもらえると嬉しいです。

2e72046813bf3dc01173fe54919a6d1d?s=128

cc4966

February 08, 2019
Tweet

Transcript

  1. ゼロから実装する 縦書きTextViewと その周辺技術 六々@496_ / DroidKaigi 2019 Room 6 -

    2019/02/08 15:40-16:30 Keynoteに続いてGoogle スライドも縦書きができなかった
  2. 自己紹介 • 六々(ろくろく) • @496_ • 趣味でTATEditorという縦書きエディタを作ってます ◦ Windows /

    macOS / Ubuntu版は公開中 ◦ Android / iOS / UWP版は開発中
  3. TATEditor • クロスプラットフォームな縦書きエディタ • C/C++製で2013年から公開

  4. 縦書きTextViewって? • カスタムViewの話です ◦ 縦書きでテキストが表示できる ◦ 縦書きでテキストが編集できる • AndroidのTextView /

    EditTextに相当
  5. 縦書きTextView • テキストが入力できてる! • 縦書きで表示されてる!

  6. 今回話す内容 • TextViewの話 • 文字コードという概念 • フォントという概念 • 縦書きテキストの作り方 •

    IMEの話 • AndroidのIMEをViewから利用する方法 • AndroidのTextViewのその他の便利機能について
  7. TextViewとは?

  8. AndroidのTextView / EditText • ViewerであるTextView • EditorであるEditText • 実はちょっと違う

  9. TextViewとEditTextの違い • テキストを選択する関数が生えているかどうか • getTextでEditableが返ることが保証されているかどうか • デフォルトのプロパティの違い • TextViewでもテキスト編集は可能 ◦

    android:enabled="true" ◦ android:focusableInTouchMode="true" ◦ android:inputType="text" ◦ android:textIsSelectable="true"
  10. TextViewとは?

  11. AndroidのTextViewの機能 • テキストを表示できる • テキストを入力できる • テキストを選択できる

  12. TextViewとは? • どのOSでも標準のTextViewが用意されています →非常にプリミティブなView

  13. TextViewとは? • プリミティブなViewだけどちっともシンプルではない • 色々なものが交わる魔窟 ◦ 入力装置(≒人間) ◦ アプリ ◦

    OS ◦ IME
  14. 一方、縦書きのTextViewは • 縦書きのTextViewが横書きのTextViewと違うところ ◦ テキスト表示が縦書き(見た目だけの問題)

  15. 一方、縦書きのTextViewは • 縦書きのTextViewが横書きのTextViewと違うところ ◦ テキスト表示が縦書き(見た目だけの問題) ◦ ほとんどのOSに標準で用意されてない

  16. 一方、縦書きのTextViewは • 縦書きのTextViewが横書きのTextViewと違うところ ◦ テキスト表示が縦書き(見た目だけの問題) ◦ ほとんどのOSに標準で用意されてない • 縦書きのTextViewを使いたければ作る必要がある ◦

    一般的なOSなら縦書き含む独自のTextViewが作れる ◦ そのためには何をすると良いのかを話します
  17. タイトルの「ゼロから実装する」について • TextViewやEditTextは使いません ◦ 縦書きができないので • drawTextなどは使いません ◦ 縦書きができないので

  18. タイトルの「ゼロから実装する」について • 文字コードは作りません ◦ Unicodeを使います • フォントは作りません ◦ 端末にインストールされているフォントを使います •

    IMEは作りません ◦ 端末にインストールされているIMEを使います • ViewとdrawBitmapは使います
  19. アウトライン • TextViewの主な機能の縦書きでの実装可能性 1. テキストを表示する 2. テキストを編集する 3. その他の便利な機能

  20. TextViewの機能その1 テキストを表示する

  21. テキストを表示する • このテキストはどうやって表示されていますか?

  22. テキストを表示する • このテキストはどうやって表示されていますか? ◦ ざっくりと言うと画像が表示されています

  23. テキストを表示する=画像を作る 入力 テキスト描画系 出力 テキスト 画像

  24. 画像、Androidなら例えばBitmap • Bitmapを作ればディスプレイに表示できる ◦ 中身はARGB_8888が推奨されている ▪ 32bitで上位ビットからAlpha, Red, Green, Blue

    ▪ 0xFFFFFFFFだと白 ◦ 表示方法 ▪ ViewのonDrawでcanvas.drawBitmap ▪ ImageViewでも良い
  25. テキスト描画系(テキスト描画エンジン) 入力 テキスト描画系 出力 テキスト 画像 この魔法の箱が 欲しい

  26. テキスト描画系という魔法の箱 • 本来ならCanvasのdrawTextがこの「魔法の箱」に相当 • drawTextは縦書きができない ◦ 魔法の箱を自作します

  27. この「テキスト描画系」を分解していきます 入力 テキスト描画系 出力 テキスト 画像

  28. テキストも所詮ただのバイト列 入力 テキスト描画系 出力 画像 文字コードの 知識 バイト列 (テキスト)

  29. 文字コード • 機械やそれを使う人同士でのプロトコル ◦ みんなでこのバイト列はこの文字に相当するものとして扱 いましょうという約束 ◦ でっかい表 • プロトコルを取り違えてしまうのがいわゆる文字化け

    • 最近だとだいたいUnicode
  30. テキストを表示するためにはフォントが必要 入力 テキスト描画系 出力 画像 文字コードの 知識 参照する バイト列 (テキスト)

    フォントファイ ル
  31. フォント • 文字コードのバイト列から人間の目と脳に優しい画像情報を 生成するための全ての情報を格納したファイル ◦ どの文字がどういう形なのか ◦ 文字の大きさはどれくらいなのか • 最近だとだいたいOpenTypeフォント

    https://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html
  32. テキストを表示する 入力 テキスト描画系 出力 バイト列 画像 文字コードの 知識 参照する (テキスト)

    フォントファイ ル バイト列と文字コードを照ら し合わせて適切な文字の形 状をフォントから取得して画 像に出力する
  33. 用語 • コードポイント ◦ Unicodeに収録されている文字(意味) • グリフ ◦ OpenTypeフォントに収録されている文字(形状) U+0041

    U+3042 U+5B89 A あ 安 B い 以 コードポイント グリフ
  34. Unicodeについて簡単に • バイト列を文字列として扱うための規格 • 符号化文字集合のひとつ ◦ U+0000 ~ U+10FFFFを文字に対応づけたもの ◦

    U+xxxxがコードポイント、U+後ろは16進数表記 • UTF-8 / UTF-16 / UTF-32は文字符号化形式 ◦ U+0000 ~ U+10FFFFの21bitの情報をどのようにバイト 列で表現するかを定めたもの
  35. AndroidのStringとその周辺 • AndroidのString (CharSequence) はchar[]で構成される ◦ charは16bit整数=内部データはUTF-16 • 表のInterfaceは下が上を継承している Interface

    Object(実装) 役割 CharSequence String 文字列へのアクセス Spanned SpannedString 文字列とマークアップへのアクセス Spannable SpannableString 編集可能なマークアップ Editable SpannableStringBuilder 編集可能な文字列とマークアップ
  36. 余談: Android StudioとString • Android Studioを使ったAndroidアプリのデバッグ ◦ ブレークポイントを置くと変数の中身を確認できる ◦ CharSequenceのtoString()経由でAndroid

    Studioが取得 • これを知らずにデバッグ中にブレークポイントで止めるとクラッ シュする問題で困った ◦ CharSequenceのtoString()は初期前でも空文字列を返す ようにした
  37. OpenTypeフォントについて簡単に • フォントファイルの仕様のひとつ ◦ グリフを最大65534個格納できる ◦ 最初の1つは.notdefと定められている ▪ いわゆる豆腐 ◦

    グリフは基本的にベクター画像として格納されている ▪ Bitmapにするにはラスタライズする必要がある
  38. テキストを画像にするまで 入力 出力 バイト列 画像 グリフ列 文字コードの 知識 (テキスト) コードポイント列

    U+0041 U+3042 U+5B89 A あ 安 Aあ安 フォントファイ ル
  39. Androidとフォント • システムのフォントファイルのありか ◦ /system/etc/fonts.xml にフォント情報がある ▪ Android 5.0からはこれだけを見ればよくなった https://github.com/google/skia/blob/master/src/ports/SkFontMgr_android_parser.cpp

    ◦ fonts.xmlにフォントファイルのパスが記されている https://android.googlesource.com/platform/frameworks/base.git/+/master/graphics/java/android/graphics/FontListParser.java ▪ 普通に開いて読み込むことができる ▪ FreeTypeを使うとだいたいのことができる
  40. 余談: 最近のAndroidとフォント • Variable Font (OpenType 1.8で導入された新機能) ◦ Android 8.0からVariable

    Fontをバンドル可能になった ◦ 合わせてfonts.xmlの仕様も一部拡張されている ◦ font-weight等が無段階になる機能
  41. テキストを画像にするまで 入力 出力 バイト列 画像 グリフ列 文字コードの 知識 (テキスト) コードポイント列

    U+0041 U+3042 U+5B89 A あ 安 Aあ安 フォントファイ ル 今ここ
  42. UnicodeとOpenTypeをつなぐもの • OpenTypeのcmapテーブル ◦ コードポイントからグリフのIDへの変換表 ◦ グリフIDの0は.notdefと呼ばれるいわゆる豆腐文字 U+0041..U+0042 U+3042..U+0043 U+5B89

    1: A 2: B コードポイント フォント内のグリフ 3: あ 4: い 5: 安 0: (.notdef) U+1F389 cmap
  43. テキストを画像にするまで 入力 出力 バイト列 画像 グリフ列 文字コードの 知識 (テキスト) コードポイント列

    U+0041 U+3042 U+5B89 A あ 安 Aあ安 フォントファイ ル 今ここ
  44. グリフのラスタライズ • 読み込みにはFreeTypeというライブラリがよく使われる ◦ PostScript (CFF) 系、TrueType系をまとめて扱える ◦ コードポイントからグリフIDへの変換 ◦

    グリフIDを指定したラスタライズ画像の取得 ▪ グリフは基本的にベクター画像
  45. グリフ列を画像にするまで 出力 画像 グリフ列 A あ 安 Aあ安 ラスタライズ画像列 A,

    あ, 安 画像化 FreeTypeなど
  46. グリフ列を画像にするまで 出力 画像 グリフ列 A あ 安 Aあ安 ラスタライズ画像列 A,

    あ, 安 どこに? 画像化
  47. グリフをテキストエリアに配置する • 以下を繰り返す ◦ グリフを置く ◦ グリフの幅だけ進む • ただし、改行文字や折り返しで次の行にジャンプする https://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html

  48. 改行にはUnicodeの知識が必要です • Windowsの改行は\r\n ◦ Carriage ReturnとLine Feedの間では改行されない U+000D CARRIAGE RETURN

    \r Mac OS 9まで U+000A LINE FEED \n Linux / macOS U+000C FORM FEED \f U+000B TABULATION \v U+2028 LINE SEPARATOR U+2029 PARAGRAPH SEPARATOR U+0085 NEW LINE
  49. 改行にはUnicodeの知識が必要です • Windowsの改行は\r\n ◦ Carriage ReturnとLine Feedの間では改行されない U+000D CARRIAGE RETURN

    \r Mac OS 9まで U+000A LINE FEED \n Linux / macOS U+000C FORM FEED \f U+000B TABULATION \v U+2028 LINE SEPARATOR U+2029 PARAGRAPH SEPARATOR U+0085 NEW LINE Carriage Return: 行頭に戻る Line Feed: 行を進める
  50. グリフ列を画像にするまで 出力 画像 グリフ列 A あ 安 Aあ安 画像化 {画像,

    座標}の列 A, {0, 0} あ, {100, 0} 安, {200, 0} 1. グリフを置く 2. グリフの幅だけ進む ただし改行文字で次の行にジャンプ
  51. テキストを表示してみる • 簡単のためまずは横書き

  52. テキストを折り返してみる • “textarea” という英単語が分割されてしまった……

  53. 折り返しにもUnicodeの知識が必要です • UAX #14: Unicode Line Break Algorithm ◦ Unicode標準の一部

    ◦ テキストのどこが折り返し可能かを定義している ◦ 行頭/行末禁止・分割禁止 • ICU (International Component for Unicode) ◦ これのLineBreakIteratorを使うと良い ◦ ICUはAndroidにも組み込まれている ◦ もともとIBM主導のOSSで今はUnicodeに属してる
  54. テキストの折り返しを正しく • いい感じですね

  55. テキストの折り返しを正しく • いい感じですね ハイフネーションという折り返し方法もあ りますが、そのあたりのことは 2/8 12:50~のSeigo Nonakaさんのセッショ ン「Best practice

    for text on Android and its internals.」が参考になります
  56. ところで縦書き要素はどこに?

  57. テキストについて再考 • データ上、テキストの進行方向はひとつ ◦ 配列のindexが増える方向だけ • 一方、画像は2次元情報 ◦ テキストの進行方向は無数にある 普通は文字が左から右、行は上から下に進む

  58. 書字方向(文字の進む方向) • 横書き(左から右) • 右横書き(右から左) ◦ アラビア語など ◦ 昔の日本のメディア ◦

    トラックや屋台の右側面の文字 • 縦書き(上から下) ◦ 今回のトピック https://commons.wikimedia.org/wiki/File:RIKEN_VITAMIN.png
  59. 改行方向(行が進む方向) • 書字方向とは直交する方向 ◦ 横書き(上から下) ◦ 右縦書き(右から左、vertical-rl) ▪ 日本語 ◦

    左縦書き(左から右、vertical-lr) ▪ モンゴル語(モンゴル文字を使った場合) • 今はキリル文字が一般に使われている
  60. 余談: その他の書字方向 • 牛耕式(Boustrophedon) ◦ 書字方向が右から左、左から右と交互に繰り返す ◦ 古代ギリシャ語 • 螺旋形

    ◦ ファイストス円盤(未解読文字) ◦ Unicodeにも収録されている ▪ U+101D0~U+101FD
  61. 縦書きと横書きの違い • 縦書きも横書きも内部の文字列は同じ ◦ 表示されている画像が違うだけ

  62. 縦書きの要件 • 文字が水平方向ではなく、垂直方向に進む • 行が垂直方向ではなく、水平方向に進む • じゃあ、縦に並べてみましょう

  63. 縦書きのテキストを表示……?

  64. 縦書きのテキストを表示……?

  65. 縦書きの要件 • 文字が水平方向ではなく、垂直方向に進む • 行が垂直方向ではなく、水平方向に進む • 上の2つの他に以下2つの要件がある ◦ フォントの縦書き用のグリフを使用する ▪

    「。」「、」「ょ」「㍻」「(」「)」「ー」 ◦ アルファベット等の文字を90度回転させる ▪ 半角だと回転する、全角だと回転しない
  66. 縦書きの際グリフをどう描画すべきか • UAX #50: Unicode Vertical Text Layout ◦ 4つに分類して定義されている(U/T/Ur/Tr)

    分類 内容 対象コードポイント U (Upright) 正立(そのまま)で表示 漢字等 R (Rotated) 時計回りに回転して表示 Alphabet etc... Tu Uだが専用グリフが必要 、。ょ㍻ Tr Rだが専用グリフが必要 ()ー
  67. 横書き専用のグリフに変換する • これはFreeTypeでは対応できないのでOpenTypeの仕様を 読んで実装すると良い • OpenTypeのGSUB (Glyph Substitution) ◦ グリフを別のグリフに置換するOpenTypeの機能

    ◦ 縦書きの場合は1グリフ↦1グリフ ▪ vert / vrt2 / vrtrというタグのもの ▪ 他の用途だとNグリフ↦Mグリフの場合もある
  68. 完成!? • だいたい良さそう

  69. 完成!? • だいたい良さそう 豆腐

  70. グリフの形式の多様化について • 一昔前までは白黒の世界で全てが閉じていた • カラー絵文字の登場でここが複雑化している

  71. Unicodeとカラー絵文字の話 • UTS #51: Unicode Emoji (ごく最近version 12.0が出た) ◦ 絵文字の大雑把な類型

    ▪ 国旗 ▪ 囲み数字 ▪ 結合文字 (ZWJ) ▪ Presentation Selector ▪ Emoji Modifier ▪ Tag Sequence 2/7 15:40~のTakeichi Yukiさ んのセッション「Androidエンジ ニアが抑えておくべき Unicode Emojiの知識」が参 考になります
  72. OpenTypeフォントとカラー絵文字 • OpenTypeのカラー絵文字の仕様は大きく4種類 形式 主なプラットフォーム 中身の形式 CBDT / CBLC Android

    / Linux PNG画像 COLR / CPAL Windows 普通のグリフと色情報 SVG␣ / (CPAL) Adobe / Mozilla SVG画像(と色情報) sbix Apple macOS: PNG画像 iOS: emjc画像
  73. 余談: OpenTypeフォントとカラー絵文字 • カラー絵文字に関する責務が散らばっているので大変 ◦ Unicodeの領域 ▪ 何をどう表示すべきかという仕様 ◦ フォントの領域

    ▪ 表示することのできる文字の提供 ◦ テキスト描画系の領域 ▪ カラー絵文字を使うか白黒文字を使うかの判断
  74. テキストの描画 • 完成!

  75. 今回話していないこと • 横書きのメトリクス・縦書きのメトリクス • 1コードポイント=1グリフの例外 ◦ IVS(異体字セレクタ) • 日本語組版処理の要件(JLREQ) •

    日本語以外のテキストについて ◦ リガチャ ◦ bidi • 等々
  76. アウトライン • TextViewの主な機能の縦書きでの実装可能性 1. テキストを表示する ← ここが終わった 2. テキストを編集する 3.

    その他の便利な機能 入力 テキスト描画系 出力 テキスト 画像
  77. TextViewの機能その2 テキストを編集する

  78. テキストを編集する • 文字列を選択する • 選択範囲を別の文字列で置換する

  79. テキストを編集する • 文字列を選択する ◦ キーボード操作による変更 ◦ マウス操作・タッチ操作による変更 • 選択範囲を文字列で置換する ◦

    キーボードから受け取った文字列で置換 ◦ クリップボードの文字列で置換
  80. デスクトップのテキスト入力の模式図 テキストだと 嬉しいけど……

  81. デスクトップのテキスト入力の模式図

  82. キーボードからの入力 • キーコードのストリームとキー配列からどうにかテキストを生 成しないといけない ◦ アルファベットはいいとして日本語は……? ▪ キーの数が足りない • これを解決するためにIMEというものがあります

  83. デスクトップのテキスト入力の模式図

  84. スマホのテキスト入力の模式図

  85. TextViewのおさらい • TextViewがすべきこと ◦ テキストの表示 ◦ テキストの編集 ▪ IMEからのテキスト入力を受け取る必要がある

  86. TextViewとIMEの関係

  87. TextViewとIMEの関係 • IMEが必要なのはわかった ◦ IMEとViewは一体どうやって情報をやり取りするの? ▪ SDK? ▪ 通信?

  88. TextViewとIMEの関係

  89. IME APIとは • OSがTextView実装のために用意するViewとIMEのインター フェース ◦ Viewは具体的な実装を知ることなくIMEを利用できる ◦ IMEは専用のSDKなどを用意せずにViewにその機能を提 供できる

  90. IME APIの概観 • IME APIがViewに要求するのは ◦ テキストの取得と変更 ◦ 選択範囲の取得と変更 ◦

    View上での文字の位置情報 ◦ 未確定文字列の管理(例: スクショの「変換」が未確定文字 列=挿入されていない) ◦ Viewのテキスト・選択範囲・レイアウトの変更通知
  91. 各プラットフォームのIME API一覧 IME APIの名称 (View側) / 標準実装 縦書き対応 (縦書きである事を伝える方法) コメント

    Windows ITextStoreACP / MSFTEDIT_CLASS あり 難解だけど高機能 macOS NSTextInputClient / NSTextView あり attributedString() がつらい GTK+ GtkIMContext / GtkTextView あり - Gtk 3.6.18以降 (ただし対応IMEがない気がする) やけにドキュメントが少ない Android BaseInputConnection / TextView 不可能ではないはず (CursorAnchorInfoのsetMatrix) 黎明期の闇が垣間見える UWP Windows.UI.Text.Core / TextBox なし 縦書きがあれば…… iOS UITextInput / UITextView ないのと同じ UITextPositionは素晴らしい
  92. 文字を入力する際の人間を含めたループ • 人間がキーボードを叩く • IMEがキーコードを受け取る • IMEがアプリに確定または未確定文字列を渡す • アプリが現在のテキストをディスプレイに表示する •

    IMEが必要な変換候補ウィンドウなどを表示する • 人間がディスプレイを見る
  93. AndroidでViewをTextViewのようにするには? • 素のViewはIMEとやり取りをすることはできない • AndroidのIME APIに適合する必要がある

  94. AndroidでViewをTextViewのようにする • カスタムViewでIMEを使うには2つのクラスが登場する ◦ BaseInputConnection ▪ インタフェース ▪ ViewがIMEの要求を受信する(IMEから叩かれる) ◦

    InputMethodManager ▪ サービス(システム) ▪ Viewの変更をIMEに通知する(Viewから叩く)
  95. InputMethodManager • キーボードの表示状態を変えるのによく使われる • IMEのためにViewから変更を伝える関数がある ◦ updateExtractedText ←テキスト ◦ updateSelection

    ←選択範囲 ◦ updateCursorAnchorInfo ←選択位置(画面上の)
  96. BaseInputConnection • IMEのためにView側が実装するべきこと ◦ 文字列の取得と編集のInterfaceを提供 ◦ 選択範囲の情報の取得と変更のInterfaceを提供 ◦ 未確定文字列の描画

  97. 未確定文字列の描画

  98. 未確定文字列 • 未確定文字列とはIME上で編集中の文字列のこと ◦ 確定していないテキスト • Spannedを通して装飾情報が渡される ◦ TextViewがテキストに装飾を反映する ◦

    変換中であること・どこが変換対象になっているかなどを ユーザーわかるように
  99. Viewでテキスト入力を受け付けるためのまとめ • カスタムViewに以下の実装をする ◦ InputMethodManagerを通しIMEにViewの状態を通知 ◦ BaseInputConnectionを実装しIMEの要求に応える

  100. 縦書きで編集 • 動画再掲

  101. 注意: BaseInputConnection • 実際はInputConnectionというInterfaceを継承したObject ◦ アプリがInputConnectionを直接継承しても良い ◦ しかしBaseInputConnectionはInputMethodManagerの @hideなプロパティを読み書きしている ▪

    BaseInputConnectionを使った方が良い
  102. アウトライン • TextViewの主な機能の縦書きでの実装可能性 1. テキストを表示する ← ここが終わった 2. テキストを編集する ←

    ここが終わった 3. その他の便利な機能
  103. TextViewの機能その他 その他

  104. テキストを表示・編集する以外の機能 • アンドゥ・リドゥ • ドラッグ&ドロップ • コンテキストメニュー • 文字選択中のMagnifier

  105. アンドゥ・リドゥ • TextViewに標準で実装されている ◦ android.R.id.undo / android.R.id.redo ▪ API Level

    23~ • キーボードなどからアンドゥ・リドゥができる ◦ キーイベントでアンドゥ・リドゥを実行する ◦ 編集履歴は自分で作る必要がある
  106. • ドラッグ&ドロップ • TextViewに標準で実装されている • 選択文字列の長押しで以下を呼ぶ ◦ ViewのstartDrag / startDragAndDrop

    ▪ API Level ~23 / 24~
  107. コンテキストメニュー • TextViewでテキストを選択したときの編集メニュー • Activity.startActionModeを使うと良い ◦ TextClassifierを使うと図のようなCallも出せる

  108. 文字選択中のMagnifier • Magnifier ◦ API Level 28~実装された ◦ 横書き専用の機能 ◦

    縦書きする場合は自作しましょう
  109. 縦書きTextView • 動画再掲

  110. スマホと縦書き • 縦書きはソフトキーボードとの相性が非常に悪い ◦ 縦書きのリフローは画面幅ではなく、表示領域の高さの変 更で起きる ◦ キーボードの表示の有無で可視領域の高さが変わる ◦ IMEの変換候補の有無でも高さが変わることがある

    ▪ リフロー発生! • キーボードの高さへの追従とリフローの指針はきちんと考える 必要がある
  111. まとめ • テキストを表示 ◦ Unicodeのコードポイント ◦ OpenTypeのグリフ ◦ 改行と折り返し •

    テキストの編集 ◦ BaseInputConnectionの継承 ◦ InputMethodManagerの呼び出し