💡

【Flutter】光っているボタンを作成した

2023/09/08に公開

はじめに

https://mobbin.com/browse/ios/apps
こちらのサイトで見つけた、以下の画像のような光っているようにみえるボタンをFlutterで作ってみました。

環境

flutter --version
Flutter 3.10.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision f92f44110e (3 months ago) • 2023-06-01 18:17:33 -0500
Engine • revision 2a3401c9bb
Tools • Dart 3.0.3 • DevTools 2.23.1

実装

光っているように見えるだけのボタン

まずは、光っているように見えるだけのボタンを作成しました。

import 'package:flutter/material.dart';

class CircleShineButton extends StatelessWidget {
  const CircleShineButton({
    Key? key,
    required this.onTap,
    this.icon = Icons.add,
    this.size = 60,
    this.color = Colors.white,
    this.backgroundColor = Colors.black,
  }) : super(key: key);

  final Function onTap;
  final IconData icon;
  final double size;
  final Color color;
  final Color backgroundColor;

  
  Widget build(BuildContext context) {
    final blurRadius = useState(8.0);
    return InkWell(
      onTap: () {
        onTap;
      },
      child: Material(
        shape: CircleBorder(
          side: BorderSide(
            color: color,
          ),
        ),
        color: Colors.transparent,
        child: Container(
          width: size,
          height: size,
          decoration: ShapeDecoration(
            shadows: [
              BoxShadow(
                color: color,
                offset: const Offset(0, 0),
                blurRadius: 10,
              ),
              BoxShadow(
                color: backgroundColor,
                offset: const Offset(0, 0),
                blurRadius: 10,
              ),
            ],
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.all(
                Radius.circular(size / 2),
              ),
            ),
          ),
          child: Icon(
            icon,
            color: color,
            size: size / 2,
            shadows: [
              BoxShadow(
                color: color,
                offset: const Offset(0, 0),
                blurRadius: 10,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Materialの子要素のContainerの影を二つ重ねることで、真ん中がくり抜かれたように描画できています。

 shadows: [
              BoxShadow(
                color: color,
                offset: const Offset(0, 0),
                blurRadius: 10,
              ),
              BoxShadow(
                color: backgroundColor,
                offset: const Offset(0, 0),
                blurRadius: 10,
              ),
            ],

また、Materialを追加しているのは、円を線で描画したかったためです。

   child: Material(
        shape: CircleBorder(
          side: BorderSide(
            color: color,
          ),
        ),
	...

タップ時に光が広がるようにする。

blurRadiusの値を変数にして、ボタンダウン時に値を増やすことにする。

  • useStateを使いたいのでHookWidgetに変更しています。
- class CircleShineButton extends StatelessWidget {
+ class CircleShineButton extends HookWidget {//変更
+    final blurRadius = useState(8.0);//追加
  • アイコンの方もblurRadius.valueに変更します。
-                blurRadius: 10,
+                blurRadius: blurRadius.value,

最後に、InkWellのプロパティのonTapDownを追加して、onTap時に値を戻すようにする。

      onTap: () {
+        blurRadius.value = 8.0;//追加
        onTap;
      },
+      onTapDown: (details) {
+        blurRadius.value = 10.0;
+      },//追加

これで完成。

コード全体

circle_shine_button.dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

class CircleShineButton extends HookWidget {
  const CircleShineButton({
    Key? key,
    required this.onTap,
    this.icon = Icons.add,
    this.size = 60,
    this.color = Colors.white,
    this.backgroundColor = Colors.black,
  }) : super(key: key);

  final Function onTap;
  final IconData icon;
  final double size;
  final Color color;
  final Color backgroundColor;

  
  Widget build(BuildContext context) {
    final blurRadius = useState(8.0);
    return InkWell(
      onTap: () {
        blurRadius.value = 8.0;
        onTap;
      },
      onTapDown: (details) {
        blurRadius.value = 10.0;
      },
      child: Material(
        shape: CircleBorder(
          side: BorderSide(
            color: color,
          ),
        ),
        color: Colors.transparent,
        child: Container(
          width: size,
          height: size,
          decoration: ShapeDecoration(
            shadows: [
              BoxShadow(
                color: color,
                offset: const Offset(0, 0),
                blurRadius: blurRadius.value,
              ),
              BoxShadow(
                color: backgroundColor,
                offset: const Offset(0, 0),
                blurRadius: 10,
              ),
            ],
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.all(
                Radius.circular(size / 2),
              ),
            ),
          ),
          child: Icon(
            icon,
            color: color,
            size: size / 2,
            shadows: [
              BoxShadow(
                color: color,
                offset: const Offset(0, 0),
                blurRadius: blurRadius.value,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

最後に

今回作ったボタンを使うことで、UIが少しリッチになると思います。ぜひご参考ください。

ここまでご覧いただきありがとうございました。

Discussion