👨‍💻

Enumを使ってTapするとemojiを切り替える

2024/01/30に公開

Dart3.0のEnum + Switchを使ってみる

時々Xでお見かけするSandroさんというマニアックなロジックを作る人のコードを見て、再現できないかな〜とやってるんですけど、今回もやってみました。

タップすると絵文字の背景に色がつく!
https://youtube.com/shorts/WT-ma4TYWnY?feature=share

Enumとsealed classどっちがいいのかという議論をしているようです。

In some cases enum are better than sealed classes
✅ Less verbose
✅ Easier to read and use
.values to get list of enum

💡ダーツチップ💡

場合によっては、enum の方がシールされたクラス🎯

✅よりも優れています。
✅読みやすく使いやすくなりました
✅ enum のリストを取得する .values

Enumがこれで絵文字の切り替えに使います。

enum Emoji {
  smile,
  rocket,
  dart;

  
  String toString() => switch (this) {
        Emoji.smile => "😀",
        Emoji.rocket => "🚀",
        Emoji.dart => "🎯",
      };
}

sealed classがこれですね。最近使うの流行ってますけど、Enumの方が良い場合もあるよと言ってるんだと思います。Kotlinにもsealed classあって、Enumみたいな使い方しますね。

sealed class Emoji {}

class Smile extends Emoji {
  
  String toString() => "😀";
}

class Rocket extends Emoji {
  
  String toString() => "🚀";
}

class Dart extends Emoji {
  
  String toString() => "🎯";
}

絵文字を切り替えるボタンのコンポーネントを作成して、これをmapメソッドでWidget側に表示して使います。InkWellを使ってTapするイベントが起きると、emojiの背景に色が付きます。

class EmojiButton extends StatelessWidget {
  const EmojiButton(
      {super.key,
      required this.selected,
      required this.emoji,
      required this.onPressed});

  final bool selected;
  final Emoji emoji;
  final void Function(Emoji) onPressed;

  
  Widget build(BuildContext context) {
    return Material(
      color: selected
          ? Theme.of(context).colorScheme.primary
          : Theme.of(context).colorScheme.surface,
      shape: const CircleBorder(),
      child: InkWell(
        onTap: () => onPressed(emoji),
        child: Padding(
          padding: const EdgeInsets.all(8),
          child: Text(emoji.toString()),
        ),
      ),
    );
  }
}

このように、mapメソッドを使ってView側に生成する。意味間違ってるかもだけど。setStateを使って画面を更新して、emojiの背景に色がつく仕組みになってます。

Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: Emoji.values
	  .map((e) => EmojiButton(
		selected: e == selectedEmoji,
		emoji: e,
		onPressed: (emoji) => setState(() {
		  selectedEmoji = emoji;
		}),
	      ))
	  .toList(),
    ),

全体のコードはこちら:

import 'package:flutter/material.dart';

enum Emoji {
  smile,
  rocket,
  dart;

  
  String toString() => switch (this) {
        Emoji.smile => "😀",
        Emoji.rocket => "🚀",
        Emoji.dart => "🎯",
      };
}

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Emoji selectedEmoji = Emoji.smile;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: Emoji.values
                  .map((e) => EmojiButton(
                        selected: e == selectedEmoji, // 修正
                        emoji: e,
                        onPressed: (emoji) => setState(() {
                          selectedEmoji = emoji; // 修正
                        }),
                      ))
                  .toList(),
            ),
          ],
        ),
      ),
    );
  }
}

class EmojiButton extends StatelessWidget {
  const EmojiButton(
      {super.key,
      required this.selected,
      required this.emoji,
      required this.onPressed});

  final bool selected;
  final Emoji emoji;
  final void Function(Emoji) onPressed;

  
  Widget build(BuildContext context) {
    return Material(
      color: selected
          ? Theme.of(context).colorScheme.primary
          : Theme.of(context).colorScheme.surface,
      shape: const CircleBorder(),
      child: InkWell(
        onTap: () => onPressed(emoji),
        child: Padding(
          padding: const EdgeInsets.all(8),
          child: Text(emoji.toString()),
        ),
      ),
    );
  }
}

最後に

Sandroさんは、日本語も話せるらしくて以前🌸サクラの話題でトークしたことあります笑
いつもマニアックなロジック書いてるのみて、気になるのがあったら真似して書いてますね。
Xにはコードを書くアイディアが紹介されていることあるから見てみると、わ〜って驚く面白いコードがありますね。再現するのは難しいですが💦

Discussion