DroidKaigiお疲れ様でした!公式アプリでRTL周りのPull Requestを出したので何をしたのか備忘録のメモを残しておきます。
Issue
Pull Request
やったこと
Left / Right をgrepして適切なものに置き換え
ConstraintLayout周りとかLintで指摘してくれないものがあるのでleft
/ right
でgrepした方がいいと思います。
grepした結果を機械的に置き換えれば良いというわけではなく、例えば情報としてはひとまとまりなんだけどviewとしては別れているみたいなケースがあります。
例えば、下記の画像の場合、
What is "
が一つのTextView, DroidKaigi
が一つのImageVIew, " ?
が一つのTextViewで構成されています。
RTL表示の場合でも英字はLTRの方向で表示するため、単純にleft / right をstart / end に置き換えてしまうと表示がおかしくなってしまいます。
RTL対応、今までParent ViewGroup作って対応していたところがConstraintLayoutでどうやるか悩む… A B C Dみたいなviewを4つ並べるデザインで、B Cが意味のひとかたまりだと、D B C A みたいな表示にしたいけど、各Viewに制約つけるとうまくいかないし、ConstraintLayoutで子の階層深くするのは悔しい
— むーむー (@muumuumuumuu) 2018年2月5日
ConstraintLayoutの中に置いたRelativeLayoutのwidthをwrap_contentにしているのだけど、RTLの時だけなぜかmatch_parentとして振る舞うようになってしまって泣いてる
— むーむー (@muumuumuumuu) 2018年2月5日
RelativeLayoutに `android:layoutDirection="ltr"` つけるのも考えたけど、RelativeLayout自体のgravityをrtlにしたいので却下。さてどうすればいいんだ…
— むーむー (@muumuumuumuu) 2018年2月5日
上記のように色々試行錯誤した結果たどり着いたのがこちら。
真ん中のViewに余白大きめにとってそこを起点に制約をつけていくというハックを覚えた
— むーむー (@muumuumuumuu) 2018年2月5日
具体的に書くと、DroidKaigi
のImageViewの(画像自体に)左右に余白を取って、そこを起点に左右のViewに制約をつける方法で回避しました。
今気がついたんだけど、なぜか" ?
の方だけRTL設定の時に? "
になっちゃってますね。
What is "
の方は大丈夫なんだけど。
" ?
の方のTextViewにandroid:textDirection="ltr"
を指定してLocaleに関係なく文字方向を固定することで回避できます。
Localeに関わらずTextViewにRTLを強制する場合は android:textAlignment を設定
例えばこのような条件の場合、
2で設定したリソースは右から表示されます。
今回のDroidKaigiの公式アプリはアラビア語リソースは用意されていないので、「開発者向けオプション」> 「RTLレウアウト方向を使用」にチェックを入れて表示確認をして行きます。この場合だと英語リソースのままレイアウト方向はRTLになりますが、逆にいうとレイアウト方向しかRTLにならないのでmatch_parentなTextViewのtextは左から表示されます。
こんな感じ。
そこでandroid:textAlignment="viewStart"
を設定することでレイアウト方向とテキスト方向が連動するようになります。
directional symbolは反転させる
directional symbolって日本語でなんていうのがポピュラーなのかわかっていませんが、矢印のように方向性を持ったシンボル(そのまんまや…)のことです。Droidkaigi公式アプリではほとんどvector drawableでアイコンが作られていたので<vector>
tagのなかにandroid:autoMirrored="true"
を指定してやればRTL表示時に反転します。
stringsのplaceholderは(必要があれば)RTL用のものを作る
そのまんま。必要があればこんな感じでRTL用のplaceholderを作ります。
<string name="room_format" translatable="false">%1$s%2$s</string> <string name="room_format_rtl" translatable="false">%2$s%1$s</string>
アラビア語のリソースを用意するのであれば不要かもしれません。ケースバイケース。
上で書いたように今回は同じ言語リソース(英語と日本語)でRTLの場合とそうでない場合に対応するのでコードで、動的にどちらを読むか判断しています。
どちらを読むかについては下記の拡張関数を作ってレイアウト方向をチェックして判断するようにしました。
fun View.isLayoutDirectionRtl() =
resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
コードからPadding設定するとき用に拡張関数作る
View#setPadding()
メソッドは引数を4つ持ちますが、そのうち第1引数は(startではなく)left固定、第3引数も同様にright固定となります。そのため、RTL表示の場合はleftとrightを入れ替える拡張関数を作りました。
fun View.setPaddingWithLayoutDirction(start: Int, top: Int, end: Int, bottom: Int) = if (isLayoutDirectionRtl()) { setPadding(end, top, start, bottom) } else { setPadding(start, top, end, bottom) }
おまけ
全く気がつかなかったのですが自分のPull Requestにtypoがあって気がついた方に直してもらいました…
今まで出したPR見たら29個できりが悪かった感じしたので30個目のPR出した(Typo修正)https://t.co/VIxwSR8fCo
— Rui Kowase (@rkowase) 2018年2月11日
圧倒的申し訳なさ…!
アアアアtypo気づかなかった本当に申し訳ないありがとうございます🙏🙏🙏🙏🙏
— むーむー (@muumuumuumuu) 2018年2月11日