前人未踏の領域へ Androidアプリ開発編

Androidアプリ開発に関する調査メモ置き場。古い記事にはアプリ以外も含まれます。

Android : bindingAdapterPositionとabsoluteAdapterPositionの違い

課題

RecyclerView.ViewHoldergetAdapterPositiondeprecatedになったので、getBindingAdapterPositiongetAbsoluteAdapterPositionのどちらかに変更する必要がある。どちらを選択すればよいか。

結論

  • bindingAdapterPositionはadapterごとの位置情報を返す
  • absoluteAdapterPositionConcatAdapter全体でみたときの位置情報を返す
  • onBindViewHolderの引数のpositionbindingAdapterPositionと同じ(adapterごと)

ConcatAdapterを使っていない場合はおそらく関係なし。 取得されたpositionを使って何をしたいかによって変わってくるので適宜検討する必要がある。

調査

bindingAdapterPositionabsoluteAdapterPositionConcatAdapterで複数のAdapterを使った場合に影響する。 ドキュメントを読んでも言ってることが良く分からなかったのでコードを書いて確認。

実験

とりあえずでこさえた実験用コード。一部省略。単にコピペするとコンパイルエラーになります。

val adapter1 = object : RecyclerView.Adapter<HogeViewHolder>() {
    override fun onBindViewHolder(holder: HogeViewHolder, position: Int) {
        Log.d("Adapter1", "${holder.bindingAdapterPosition}:${holder.absoluteAdapterPosition}")
    }
    override fun getItemCount(): Int = 3
}
val adapter2 = object : RecyclerView.Adapter<HogeViewHolder>() {
    override fun onBindViewHolder(holder: HogeViewHolder, position: Int) {
        Log.d("Adapter2", "${holder.bindingAdapterPosition}:${holder.absoluteAdapterPosition}")
    }
    override fun getItemCount(): Int = 3
}
val adapter3 = object : RecyclerView.Adapter<HogeViewHolder>() {
    override fun onBindViewHolder(holder: HogeViewHolder, position: Int) {
        Log.d("Adapter3", "${holder.bindingAdapterPosition}:${holder.absoluteAdapterPosition}")
    }
    override fun getItemCount(): Int = 3
}

// ListViewにセット
listView.adapter =  ConcatAdapter(config, header,header2, adapter!!, footer)

結果

Logcatの出力結果はこちら。bindingAdapterPosition の方がadapterごとの位置情報を返していることがわかる。

// bindingAdapterPosition:absoluteAdapterPosition

D/Adapter1: 0:0
D/Adapter1: 1:1
D/Adapter1: 2:2
D/Adapter2: 0:3
D/Adapter2: 1:4
D/Adapter2: 2:5
D/adapter3: 0:6
D/adapter3: 1:7
D/adapter3: 2:8

Android:Jetpack ComposeでNoto Sans JPフォントを使えるようにする

追記

Issueが解決され、記事になっていた。今後は includeFontPadding=falseがデフォルトで適用されるようになるため 本記事の問題は影響しなくなるだろう。 medium.com

課題

これまでアプリでGoogle FontsからNotoフォントをダウンロードして使っていたが、Jetpack Composeに適用とすると上下に余白が出てしまう。

上下に余白が出る例。Robotoフォントとの比較
どうすればよいか。

対応

参考ページにもあるようにISSUE化はされているが現時点で対応されていない。
仕方がないのでフォントセット自体を修正して対応することに。
幸い同ISSUEの方にfonttoolsを使って上下幅を設定できるという投稿があり、それを試してみることにした。以下はその手順。

対応手順

前提条件:fonttoolsはpythonで書かれているのでpip3コマンドを使えるようにする。

  1. fonttoolsをインストール
  2. otfファイルのヘッダー情報を取得する
  3. ttxファイルを更新する
  4. otfファイルを作成する
  5. otfファイルを差し替え

fonttoolsをインストール

fonttoolsをインストールする

$ pip3 install fonttools

otfファイルのヘッダー情報を取得する。

以下のコマンド使ってotfファイルのヘッダー情報を取得する

$ ttx -t head noto_sans_jp_regular.otf

すると noto_sans_jp_regular.ttxというファイルが生成される。

ttxファイルを更新する

ヘッダー情報を更新する。Robotoフォントの上下幅の設定を参考にする。以下は関係する部分の抜粋

  • 1em辺りのデータサイズ(この辺は適当)が unitsPerEm で定義されている
  • roboto.ttxではunitsPerEm2048に対して notoでは1000が設定されている。なので設定値比率は2048 : 1000である
  • roboto.ttxのyMinとyMaxを参考にnotoの値をセットする
// roboto.ttx
<unitsPerEm value="2048"/>
<yMin value="-555"/>
<yMax value="2163"/>

2048 : 1000 なので -555 : yMin、 2163 : yMaxでRobotと同じ余白になるように合わせる

// noto_sans_jp_regular.ttx
<unitsPerEm value="1000"/>
<yMin value="-270"/>
<yMax value="1056"/>

otfファイルを作成する

$ ttx -m noto_sans_jp_regular.otf -b noto_sans_jp_regular.ttx

するとnoto_sans_jp_regular#1.otf というファイルが生成される。

otfファイルを差し替え

それをnoto_sans_jp_regular.otfに上書きコピーすればOK

mv -f noto_sans_jp_regular#1.otf noto_sans_jp_regular.otf

無事余白がRobotoと揃った

備考

Style(Bold, Mediumなど)ごとに微妙にyMin,yMaxが異なるのでそれに合わせて1ポイントずつ余白を少なくした方がいい感じになる。
使用される文字によってはおかしくなる場合があるかもしれない。

参考

検証に使ったコード

@Composable
fun NotoText() {
    Text(text = "Noto Sans JP", fontFamily = NotoSansJpFamily, fontWeight = FontWeight.Medium)
}

@Composable
fun RobotoText() {
    Text(text = "Roboto", fontFamily = RobotoFamily, fontWeight = FontWeight.Medium)
}

@Preview
@Composable
fun NotoPreview() {
    Surface(Modifier.background(Color.White)) {
        NotoText()
    }
}

@Preview
@Composable
fun RobotoPreview() {
    Surface(Modifier.background(Color.White)) {
        RobotoText()
    }
}

Apple Silicon版のAndroid StudioをToolbox Appで使えるようにする

課題

Apple Silicon版のMacBook Proの購入に伴い、Android StudioApple Silicon版にしたいが、 できればJetBrainsのToolbox App経由で使いたい。どうすれば良いか。

対応

  1. JetBrains Toolbox AppをApple Silicon版にする
  2. Toolbox上のAndroid Studioをアンインストールする
  3. 再インストールする
  4. 確認

1. JetBrains Toolbox AppをApple Silicon版にする

こちらのサイトにアクセスし、 www.jetbrains.com

プルダウンメニューから .dmg (macOS Apple Silicon) を選択する f:id:takeR:20211203155357p:plain

ダウンロードしたら置き換えでインストールでOK。

2. Toolbox上のAndroid Studioをアンインストールする

Toolbox上で既存のAndroidをアンインストールする。
ただし、Android Studioを1種類しかインストールしていない場合は再インストールのメニューが どこかにいってしまうかもしれないので下の3のインストールのところで「追加インスタンスをインストール」を試すとよいかも(未確認)。

3. 再インストールする

Toolboxを開き、Android Stdioのメニューから「他のバージョン」を選ぶ。
f:id:takeR:20211203155921p:plain

「インストール」ボタンを押下
f:id:takeR:20211203160339p:plain

ToolboxがApple Silicon版になっていればApple Silicon版のAndroid Studioを勝手にインストールしてくれる。

4. 確認

Android Studioを起動し、About Android Studioで概要を確認。 aarch64 になっていればOK.

f:id:takeR:20211203155624p:plain

備考

Apple Silicon版にしたらビルド時間が4分の1ぐらいになり待ち時間が激減。オススメ。