飴屋

Kotlin/FloatingActionButtonも設置する

Composableに移管中の画面にはFloatingActionButtonもついてました。Scaffoldに丁度、floatingActionButton というスロットも生えているようなので、そこに設定を加えてみます。

Scaffold(
    floatingActionButton = {
        FloatingActionButton(onClick = {}) {
            Image(
                painter = painterResource(id = R.drawable.ic_fab,
                contentDescription = stringResource(id = R.string.label_fab)
            )
        }
        FloatingActionButton(onClick = {}) {
            Image(
                painter = painterResource(id = R.drawable.ic_fab2,
                contentDescription = stringResource(id = R.string.label_fab2)
            )
        }
    }
) { innerPadding ->
    // ...
}

Imageを内包させて、クリック時の処理を書けばよさそうです。ImageってHTMLのimgタグを連想させますね。painter がsrc属性で、contentDescription がalt属性みたいな感じでしょうか。contentDescription みたいな設定は重要性がわからないかもしれませんが、バリアフリーに貢献することが障害を持つと身にしみてわかるようになるのでした。

しかし、このままビルドしたら画面の下に超デカいボタンができあがりました。FloatingActionButton がメインのアクションへの導線だとはいえこれはあまりにもビッグすぎる。
SmallFloatingActionButton に変更してみてもサイズは変わらず、ScaffoldにfloatingActionButtonPositionを設定してもサイズは変わらず、ImageをIconに変更してみると・・・これはアイコン向けの色に変わったので採用できるケースがあるかもと思いつつ、サイズは変わらず。なぜ、見本のようにやっても見本のような出力を得られないのか・・・また、調べ物が始まるのでした。

FloatingActionButtonのModifierに直接サイズを指定する、という手段もあるのですが、マテリアルデザインの考え方的にはNGらしいので、これは最後の手段ですね。FloatingActionButtonのshapeがデフォルトでは角丸な四角だったのでCircleShape(円形)に修正しておきます・・・すると、巨大アイコンの角丸がとれて、左肩にできたスペースに、大きくない通常サイズのFloatingActionButton が一つ現れました。二つ配置するつもりだったボタンの片方は正常サイズ・・・一つ目しかうまくいかないのか?と思って、ボタンを入れ替えてみたところ、今度は二つ目のボタンが正常なサイズになりました。どうも使ってる画像に問題があるっぽいな、これ。

R.drawable.ic_fab2 に該当するベクターグラフィックはずーっと昔に自作したデータなんですが、widthとheightがかなり大きかったんですね。前はそれをFloatingActionButton に入れてもうまくサイズを調整してくれていたみたいですが、Composable関数版ではダメってことですね。幸いviewportWidthやviewportHeightは据え置きで、倍率を揃えてwidthとheightを小さくしたら、ボタンが正常なサイズになりました。サイズは大きい幅の方を24dpとして、高さはそれに合わせて調整しました。

で、それだけではダメで、二つFloatingActionButtonを並べる場合は、並べるレイアウトを間に挟む必要がありました。RowとかColumnってやつですね。ボタンを縦並びにしたかったのでColumnを使います。

Scaffold(
    floatingActionButton = {
        Column(
            verticalArrangement = Arrangement.spacedBy(16.dp),
            horizontalAlignment = Alignment.End
        ) {
            FloatingActionButton(
                onClick = {},
                shape = CircleShape,
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_fab),
                    contentDescription = stringResource(id = R.string.label_fab)
                )
            }
            FloatingActionButton(
                onClick = {},
                shape = CircleShape,
            ) {
                Icon(
                    painter = painterResource(id = R.drawable.ic_fab2),
                    contentDescription = stringResource(id = R.string.label_fab2),
                )
            }
        }
    }
) { innerPadding ->
    // ...
}

ArrangementとかAlignmentを指定してレイアウトを作っていくんですね。CSSではFLEXレイアウトを組んでる感覚に近かったですね。

ちなみにボタンのアイコン色と背景色はマテリアルデザイン3でいうところの onPrimaryContainer と primaryContainer のようです。任意の色に変更したいときは、contentColor と containerColor を変更すえばよいようです。

FloatingActionButton(
    onClick = {},
    contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
    containerColor = MaterialTheme.colorScheme.primaryContainer,
    shape = CircleShape,
)

一覧へ