【Flutter】ボタンを非活性化させたいのに見た目が変わらない時の原因

## はじめに

ButtonのonPressに条件によってnullを渡して非活性にさせたいことがあると思います。
本来はnullを渡すとボタンがタップできなくなるのに加えて見た目も透明度が落ちて薄暗い状態になります。
しかし、何故かいくらnullを渡しても見た目が変わらない事象に遭遇しました。
その解決方法を解説します。

### 記事の対象者

- ボタンを非活性にさせたいのに見た目が変わらない事でお困りの方

### 記事を執筆時点での筆者の環境

```
[✓] Flutter (Channel stable, 3.22.1, on macOS 14.3.1 23D60 darwin-arm64, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.3)
[✓] VS Code (version 1.89.1)
```

## 1. 原因

`ButtonStyle`で`backgroundColor`や`foregroundColor`を`WidgetStateProperty.all`で指定してしまった事が原因でした。
つまり、どんな状態でも同じ色になるように設定してしまいました。

```dart

ButtonStyle createBadPrimaryButtonStyle(BuildContext context) {
  final colorScheme = Theme.of(context).colorScheme;
  return ButtonStyle(
    fixedSize: WidgetStateProperty.all(const Size.fromHeight(48)),
    backgroundColor: WidgetStateProperty.all(colorScheme.primary),
    foregroundColor: WidgetStateProperty.all(colorScheme.onPrimary),
    textStyle: WidgetStateProperty.all(
      Theme.of(context)
          .textTheme
          .labelLarge!
          .copyWith(fontWeight: FontWeight.w600),
    ),
  );
}

```

:::note
`WidgetStateProperty`はflutter3.22.1から導入されたクラスです。
それ以前は`MaterialStateProperty`クラスでした。
ここはflutter3.22.1を入れると警告が出ますが、`⌘ + .`でReplace with 'WidgetStateProperty'
を選択して入れ替えるだけで大丈夫です。

![スクリーンショット 2024-06-05 23.05.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058346/498c6d1d-e0f1-b3bf-31a2-bfc4976d4a99.png)

:::

## 2. 解決策

非活性の場合とそうではない場合でそれぞれの状態を指定すれば解決できます。

```dart

ButtonStyle createPrimaryButtonStyle(BuildContext context) {
  final colorScheme = Theme.of(context).colorScheme;
  return ButtonStyle(
    // ボタンの高さを48に固定
    fixedSize: WidgetStateProperty.all(const Size.fromHeight(48)),
    // NOTE: スタイルを自作すると、ディセーブルの時の値を手動で設定する必要がある
    backgroundColor: WidgetStateProperty.resolveWith<Color>(
      (Set<WidgetState> states) {
        if (states.contains(WidgetState.disabled)) {
          return colorScheme.primary.withOpacity(0.7);
        }
        return colorScheme.primary;
      },
    ),
    // NOTE: スタイルを自作すると、ディセーブルの時の値を手動で設定する必要がある
    foregroundColor: WidgetStateProperty.resolveWith<Color>(
      (Set<WidgetState> states) {
        if (states.contains(WidgetState.disabled)) {
          return colorScheme.onPrimary.withOpacity(0.7);
        }
        return colorScheme.onPrimary;
      },
    ),
    textStyle: WidgetStateProperty.all(
      Theme.of(context)
          .textTheme
          .labelLarge!
          .copyWith(fontWeight: FontWeight.w600),
    ),
  );
}

```

## 3. サンプル


### コード

```dart

void main() {
  runApp(const MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text('全部にnullを渡して非活性にしています'),
              // gapというパッケージ使ってます
              const Gap(20),
              const ElevatedButton(
                onPressed: null,
                child: Text('デフォルトのボタン'),
              ),
              const Gap(20),
              ElevatedButton(
                onPressed: null,
                style: createPrimaryButtonStyle(context),
                child: const Text('非活性部分もちゃんと定義したボタン'),
              ),
              const Gap(20),
              ElevatedButton(
                onPressed: null,
                style: createBadPrimaryButtonStyle(context),
                child: const Text('非活性部分は定義していないボタン'),
              ),
            ],
          ),
        ),
      ),
    );
  }
} 

```
:::note
`createPrimaryButtonStyle`と`createBadPrimaryButtonStyle`はグローバル定義しています。
ここでの掲載は省略しています。
:::

### スクリーンショット

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058346/7a50fc28-9a3c-de8b-3659-c943f1781153.png">


## 終わりに

言われてみれば確かに.allでしていたな、と思う事でしたが当初は分からず小一時間悩んでいました😰
同じ悩みに遭遇されている方の一助となれば幸いです。

## 参考記事

https://stackoverflow.com/questions/64995163/how-to-i-change-the-disabled-color-of-an-elevatedbutton