【Flutter】横丸でグラデーションのあるボタンを作った

したかったこと

現在の携わっているFlutterのプロジェクトは、もともとデザイン中心のテンプレートからアプリ開発を行っている。ボタンが横丸かつ微妙にグラデーション掛かってて、おしゃれで、デザイン的には気に入っている。ただ、内部的にはContainerをGestureDetectorでラップしているため、ボタンを無効にする、というボタン特有の行為ができない。そこで、デザインをそのままで、ボタンと機能するコードにしたかった。

ここでの単語

  • 横丸:ボタンの横が完全に丸っこいこと
  • 角丸:ボタンの角がちょっと丸っこいこと

問題点

横丸ボタンの設定とグラデーションの設定を実施すると、横丸の設定(StadiumBorder)がなくなってしまう。横丸ボタンとグラデーションボタンを参考に、両方の設定が入っているつもりのソースを書いたが、横丸にはならなかった。

横丸ボタン

ElevatedButton(
  style: ElevatedButton.styleFrom(
    shape: const StadiumBorder(),
  ),
),

グラデーションボタン

ElevatedButton(
  child: Container(
    decoration: BoxDecoration(
      gradient: LinearGradient(
        colors: [Color(0xfffec230), Color(0xfff9a825)],
      ),
    ),
  ),
),

角丸でグラデーションのあるボタンの候補1

Container(
    height: 20,
    width: 150,
    decoration: BoxDecoration(
      gradient: LinearGradient(
        colors: [Color(0xfffec230), Color(0xfff9a825)],
      ),
    ),
    child: ElevatedButton(
        onPressed: () {},
        style: ElevatedButton.styleFrom(
          backgroundColor: Colors.transparent,
          shadowColor: Colors.transparent,
          shape: const StadiumBorder(),
        ),
        child: Text('ABC')))

角丸でグラデーションのあるボタンの候補2

ElevatedButton(
      onPressed: () {},
      style: ElevatedButton.styleFrom(
        backgroundColor: Colors.transparent,
        shadowColor: Colors.transparent,
        shape: const StadiumBorder(),
      ),
      child: Container(
          height: 20,
          width: 150,
          decoration: BoxDecoration(
            gradient: LinearGradient(
              colors: [Color(0xfffec230), Color(0xfff9a825)],
            ),
          ),
          child: Text('ABC')),
    ),

解決策

横丸の設定を使うのではなく、最大限に角丸な設定にした。StadiumBorder()の設定を使うのではなく、BorderRadius.circular(height/2)で、ボタンの高さの半分 角丸なボタンにした。

完成コード

class MyElevatedButton extends StatelessWidget {
  final BorderRadiusGeometry? borderRadius;
  final Gradient gradient;
  final VoidCallback? onPressed;
  final String message;
  final double height = 67.0;

  const MyElevatedButton({
    Key? key,
    required this.onPressed,
    required this.message,
    this.gradient =
        const LinearGradient(colors: [Color(0xfffec230), Color(0xfff9a825)]),
    this.borderRadius,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final borderRadius = BorderRadius.circular(height / 2.0);
    return Container(
      width: double.infinity,
      height: height,
      margin: const EdgeInsets.symmetric(
        horizontal: 10,
        vertical: 10,
      ),
      decoration: BoxDecoration(
        gradient: gradient,
        borderRadius: borderRadius,
      ),
      child: ElevatedButton(
        onPressed: onPressed,
        style: ElevatedButton.styleFrom(
          backgroundColor: Colors.transparent,
          shadowColor: Colors.transparent,
          shape: RoundedRectangleBorder(borderRadius: borderRadius),
        ),
        child: Text(
          message,
          style: const TextStyle(
            fontSize: 17,
            fontWeight: FontWeight.normal,
          ),
        ),
      ),
    );
  }
}

全ソース

githubのソース

参考

[Flutter]コピペで使える!ボタンのデザイン16種類をまとめました

How to make Elevated Button with Gradient background?