【Flutter】TextButton・OutlinedButton・ElevatedButtonの使い分けを考えた

Flutteを始めた頃ずっと分からなかったElevatedButtonとTextButtonの使い分け。

正直今でもそこまでピンとは来ていないのですが、調べてみることにしました。

## 公式ドキュメントを読もう

まずは公式ドキュメントを読んでみましょう。全文英語ですが頑張ります。


https://docs.flutter.dev/release/breaking-changes/buttons


僕は3ヶ月前からFlutterを始めたので知らなかったのですが、どうやら最近ボタンのウィジェットが新しく作り替えられたようですね。

いろんな技術記事に出てくるRaisedButtonを実際に使ってみると「使わないでください！」みたいな警告がでてくるのはこのためだったようです。

公式ドキュメントでは色々とボタンの使い方を説明してくれてはいますが、どちらかというと旧ボタンを使用していた人が新ボタンに移行する部分に焦点をあてているようです。

そのためいまいちそれぞれのボタンの使い分けについては記載されていないようでした。
（もしかすると僕の英語力が終わっているせいで見つけられなかっただけかもしれませんが、、）

というわけで次にそれぞれのボタンのドキュメントを読んでいくことにしました。

## ElevatedButton


https://api.flutter.dev/flutter/material/ElevatedButton-class.html


ドキュメントからElevatedButtonの大きな特徴としては

 - elevated(＝高さ)のあるボタンである
 - 縦と横の長さを与えることができる
 - ボタンの中にウィジェットを配置できる

があるようです。

まとめると縦と横の長さを与えることができて、かつボタンの中に好きな要素を置くことができるボタンのようですね。

個人的には1番よく使うボタンで、何ならほぼ全てのボタンをこれで作ってしまっています。

ただ公式的にはちゃんと使い分けてほしいようで

```
Avoid using elevated buttons on already-elevated content such as dialogs or cards.

（訳：ダイアログやカードのようなすでに高さのあるコンテンツの上には使うのを避けるべき）
```

との記載もありました。

ただElevatedButtonの1番の特徴とも言える高さがあるように見せるための影は一応消すことができます。


https://www.choge-blog.com/programming/flutterelevatedbutton-shadow-remove


ただこの方法だとタップした時に影が出てきてしまうので、気になる場合は影の色を背景色と合わせるなどしなければいけず、影なしでElevatedButtonを使うのはちょっと面倒だなという感じですね。。

## TextButton


https://api.flutter.dev/flutter/material/TextButton-class.html


ドキュメントから特徴としては
　
 - paddingでボタンの寸法を決定する
 - 枠線を持たない
 - 高さを持たない（影がつかない）

があるようです。

縦横の長さを直接指定するElevatedButtonとは違い、子要素からのpaddingでボタンの縦横を指定するところが大きな特徴かなと思います。

ボタンの中のテキストが状態によって変わるけど、ボタンの見た目（padding）自体は変えたくない！という時にはこのボタンを使う必要があるということですね。

またTextButtonについても丁寧に使用すべき場所が書かれていて

```
Use text buttons on toolbars, in dialogs, or inline with other content
（訳：ツールバーやダイアログ、またはインラインコンテンツで使用すべき）

Avoid using text buttons where they would blend in with other content, for example in the middle of lists.
（訳：リストの真ん中の要素など、他のコンテンツと混ざってしまうような場所で使用するべきでない）
```
ということらしいです。なるほど。


## OutlinedButton

最後にOutlinedButtonです。公式ドキュメントはこちらです。


https://api.flutter.dev/flutter/material/OutlinedButton-class.html


```
A Material Design "Outlined Button"; essentially a TextButton with an outlined border.
（訳：Outlined Buttonは本質的にはTextButtonに枠線を追加したものです）
```
どうやらTextButtonとほぼ同じらしいです。使ったことなかったけど君そういう感じだったんだね。


## 結論

結論それぞれの使い分けは下記のような感じかなと思っております。

### ElevatedButton

 - ボタンの縦横を固定値もしくは％値で決めたい時
 - 高さ（影）をつけたい時


### TextButton

 - ボタンの縦横をpaddingで指定したい時
 - 外枠がいらない時
 - 影をつけたくない時

### OutlinedButton

 - ボタンの縦横をpaddingで指定したい時
 - 外枠がほしい時
 - 影をつけたくない時

ここまで調べておいてなんですが、結局はそれぞれのボタンの名前の通り

 - 高さがある時はElevatedButton
 - 文字だけの時はTextButton
 - 外枠が欲しい時はOutlinedButton

という何とも分かりやすい結果になりました。（そりゃそうか）

まあただ個人的にはやはり縦横値を指定できないTextButtonとOutlineButtonは使いづらくて好みではないんですよね。。。

タップした時の影を何とかするのは面倒でも、タップしていない時の影は簡単に消せるので、現在参画しているプロジェクトではほぼ１００％の確率でElevatedButtonを使っています。

##### それぞれのデフォルトの見た目

```dart
ElevatedButton(onPressed: () {}, child: const Text("ElevatedButton")),
TextButton(onPressed: () {}, child: const Text("TextButton")),
OutlinedButton(onPressed: () {}, child: const Text("OutlinedButton")),
```

![aaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724713/dcb56fb7-e0c0-0268-99c7-14935929f513.png)



##### ElevatedButtonで他2つのボタンを再現

```dart
ElevatedButton(onPressed: () {}, child: const Text("ElevatedButton")),
ElevatedButton(
    onPressed: () {},
    style: ElevatedButton.styleFrom(
        primary: Colors.transparent, elevation: 0),
    child: const Text(
      "ElevatedButton",
      style: TextStyle(color: Colors.green),
    )),
ElevatedButton(
    onPressed: () {},
    style: ElevatedButton.styleFrom(
        primary: Colors.transparent,
        elevation: 0,
        side: BorderSide(color: Colors.grey.shade400)),
    child: const Text(
      "ElevatedButton",
      style: TextStyle(color: Colors.green),
    )),
```
![スクリーンショット-2022-07-16-19.56.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724713/e59a3606-0fd2-8794-5b82-04984d8ba091.png)

ね、タップ時の動き以外ElevatedButtonで全部再現できるんすよ。

というわけで色々調べた結果結局TextButtonとOutlinedButtonの活躍のさせ方が分からなかったのですが、もし上記以外にもこんな明らかな違いがあるよ！という部分があれば教えてもらえると嬉しいなと思います。


ありがとうございました！