概要
AppBarを使った際leadingにIconボタン以外のカスタムボタンを置きたかったときにハマったのでメモ
内容
AppBarのLeftにIconButtonではなくTextでキャンセルという文字を置きたかった。
しかし、leadingにTextを設定してもDefalutの56pxのWidthが設定されており、意図した通りに表示できなくて困った。
色々調べて解決策は以下
[2022/02/14追記]
現在は leadingWidth
プロパティが設定できるようになっているので単純に指定の幅を設定してあげれば良い
(@akita3375さん、コメントありがとうございます)
方法
- [推奨] leadingWidthを使う
- OverflowBoxを使う
- TitleにStackを使う
[2022/02/14追記] leadingWidth
現在は下記のように leadingWidth
に適切なサイズを指定してあげるだけで問題ない。
この方法だとタップ領域も正しく反映される。
AppBar(
leadingWidth: 110, //leadingWidthを設定する
leading: TextButton(
child: Text(
'キャンセル',
style: TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
),
OverflowBox
カスタムアイコン以外に設定しようと調べても出てこない中こんなISSUEを見つけた。
https://github.com/flutter/flutter/issues/21991#issuecomment-441728934
その中でこのようなコメントがあった。
I too wanted to have a wider Leading widget than the default 56. I wanted to have the word 'Cancel' presented to the user (versus the standard X icon), when using the route as a fullScreenDialog. I was able to work around this 'issue' by wrapping my leading 'Flatbutton' in an OverflowBox, with a maxWidth of 90.0.
つまりFlatButtonをOveerflowBoxで囲むとleadingのWidthを大きくできるよ的な内容だった
下記のような感じ
appBar: AppBar(
leading: OverflowBox(
maxWidth: 110,
child: FlatButton(
child: Text(
"キャンセル",
style: TextStyle(
color: Colors.grey,
fontSize: 14
),
),
),
),
)
しかし、overflowBoxを指定すると中心が変わらずWidthの上限が広がるので、画面から文字がはみだしてしまう。ためContainerでleft paddingをつける必要があった。
[6/17] 修正: alignmentを指定することでpaddingは不要になりました。
しかしこの方法でやる場合、もともとのleadingのサイズをはみ出した部分(つまりオーバフロー部分)にタップ領域が設定されない。
appBar: AppBar(
leading: Container(
// padding: EdgeInsets.only(left: 40), <- 不要になったコード
alignment: FractionalOffset.centerLeft, // <- 追記したコード
child: OverflowBox(
maxWidth: 110,
child: FlatButton(
child: Text(
"キャンセル",
style: TextStyle(
color: Colors.grey,
fontSize: 14
),
),
),
),
),
)
TitleにStackを使う
上記の方法ではleft paddingなどを追加しないといけないため他の方法を考えた。
個人的にはこっちを推奨したい。
[2022/02/14追記] 現在は leadingWidth
が設定できるのでそちらを推奨
Stack Widget
はFlutterに置いて絶対位置指定などをしたいときに使われる。
Viewを重ねたいときなどに使えるだろう。
今回は Stack widget
の中で Align Widget
を使うことで、親のWidgetに対してそれぞれ位置指定を行う。
下記のコードで上記と同じようにViewが作れる。
title: Stack(
alignment: Alignment.center,
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: ButtonTheme(
padding: EdgeInsets.symmetric(vertical: 8),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
minWidth: 0,
height: 0,
child: FlatButton(
child: Text(
"キャンセル",
style: TextStyle(
color: Colors.grey,
fontSize: 14
),
),
onPressed: () {},
),
),
),
Align(
alignment: Alignment.center,
child: const Text(
"タイトル",
style: TextStyle(
fontSize: 16,
color: Colors.black54,
fontWeight: FontWeight.bold
),
),
),
],
),
automaticallyImplyLeading: false,
Align Widget
は親Viewに対してalignmentを指定することで配置する場所を決定できる。
今回は
キャンセル: Alignment.centerLeft
タイトル : Alignment.center
とする。
ここでポイントはStack Widget自体のAlignmentを
alignment: Alignment.center
と指定することである。
デフォルトではtopStartが設定されているので、上記のようにキャンセル,タイトルを設定してもtopよりの配置になってしまう。
まとめ
上記のような方法でleadingにIcon以外のボタンを設定することができた。
他に何か良い方法があれば教えていただけると幸いです。