🧪

base classの使用例

に公開

なかなか思いつかない?

Dart3.0から追加された base class。使い道がわからない。Flutterで使うならWidtgetだと思うが。

base classは継承して使うにはfinalをつけます。つけないとエラーが出てしまう。最近副業でスナックバーをコンポーネント化して汎用性の高いものにしたいと言われた。

そういえばエラー用しか作ってない。こちらがサンプル。ベースクラスを作成して継承してロジックを持たせる。これでメッセージ出すだけのスナックバーとエラー用のスナックバーを作れる。

import 'package:flutter/material.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom SnackBar Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Custom SnackBar Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                CustomSnackBar.showNormal(
                  context: context,
                  message: 'This is a normal message',
                );
              },
              child: const Text('Show Normal SnackBar'),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                CustomSnackBar.showError(
                  context: context,
                  message: 'This is an error message',
                );
              },
              child: const Text('Show Error SnackBar'),
            ),
          ],
        ),
      ),
    );
  }
}

enum SnackBarType { normal, error }

base class BaseCustomSnackBar {

  const BaseCustomSnackBar({
    required this.message,
    required this.type,
  });
  final String message;
  final SnackBarType type;

  Color get backgroundColor => type == SnackBarType.normal
      ? Colors.blue.shade900
      : Colors.red.shade900;

  Color get textColor => Colors.white;

  IconData get icon => type == SnackBarType.normal
      ? Icons.info_outline
      : Icons.error_outline;

  SnackBar build() {
    return SnackBar(
      content: Row(
        children: [
          Icon(icon, color: textColor),
          const SizedBox(width: 8),
          Expanded(
            child: Text(
              message,
              style: TextStyle(color: textColor),
            ),
          ),
        ],
      ),
      backgroundColor: backgroundColor,
      behavior: SnackBarBehavior.floating,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(8),
      ),
    );
  }
}

final class CustomSnackBar extends BaseCustomSnackBar {
  const CustomSnackBar({
    required super.message,
    required super.type,
  });

  static void showNormal({
    required BuildContext context,
    required String message,
  }) {
    _show(context: context, message: message, type: SnackBarType.normal);
  }

  static void showError({
    required BuildContext context,
    required String message,
  }) {
    _show(context: context, message: message, type: SnackBarType.error);
  }

  static void _show({
    required BuildContext context,
    required String message,
    required SnackBarType type,
  }) {
    final snackBar = CustomSnackBar(message: message, type: type).build();
    ScaffoldMessenger.of(context).showSnackBar(snackBar);
  }
}

実行結果

ボタンのコンポーネントだとこんな感じか。いつもはこんな書き方しませんが、使えそうだったら試してみたい。

import 'package:flutter/material.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Button Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Custom Button Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            PrimaryButton(
              onPressed: () {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: const Text('Primary button pressed!'),
                    backgroundColor: Colors.blue,
                    behavior: SnackBarBehavior.floating,
                  ),
                );
              },
              child: const Text('Primary Button'),
            ),
            const SizedBox(height: 20),
            SecondaryButton(
              onPressed: () {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: const Text('Secondary button pressed!'),
                    backgroundColor: Colors.red,
                    behavior: SnackBarBehavior.floating,
                    action: SnackBarAction(
                      label: 'OK',
                      textColor: Colors.white,
                      onPressed: () {},
                    ),
                  ),
                );
              },
              child: const Text('Secondary Button'),
            ),
          ],
        ),
      ),
    );
  }
}

base class BaseButton extends StatelessWidget {

  const BaseButton({
    required this.onPressed, required this.child, required this.backgroundColor, required this.textColor, super.key,
  });
  final VoidCallback? onPressed;
  final Widget child;
  final Color backgroundColor;
  final Color textColor;

  
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      style: ElevatedButton.styleFrom(
        backgroundColor: backgroundColor,
        foregroundColor: textColor,
        padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(8),
        ),
      ),
      child: child,
    );
  }
}

final class PrimaryButton extends BaseButton {
  const PrimaryButton({
    required super.onPressed, required super.child, super.key,
  }) : super(
          backgroundColor: Colors.blue,
          textColor: Colors.white,
        );
}

final class SecondaryButton extends BaseButton {
  const SecondaryButton({
    required super.onPressed, required super.child, super.key,
  }) : super(
          backgroundColor: Colors.red,
          textColor: Colors.white,
        );
}

最後に

Flutter3, Dart3.0新しい機能が気がついたら出ている。毎日勉強していないと追いつけません💦
最近は汎用的はWidgetを作れいだろうかと仲間と研究中🧪

Discussion