0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

カラーピッカーと色プレビュー付きのTextFormFieldを実装する

Posted at

colorpicker_textfield_demo.gif

カラーピッカー&色プレビュー付きのTextFormFieldを実装する。

機能

実装する機能は以下の通り。

  • カラーピッカー(flutter_colorpickerを使用)
  • テキストフィールドにARGBの16進表記の文字列を表示
  • 選択またはテキスト入力した色のプレビュー
  • 入力値のバリデーション(16進数8桁)
  • 入力値が8桁未満の場合Fでパディング

パッケージのインストール

flutter_colorpickerをインストールする。

flutter pub add flutter_colorpicker

ソースコード(全文)

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';

class ColorPickerTextField extends StatefulWidget {
  const ColorPickerTextField(
      {super.key,
      required this.textFieldGrobalKey,
      this.title,
      this.helperText})
      : initColor = const Color(0xffffffff),
        width = 200,
        previewIcon = const Icon(Icons.circle),
        colorPickerIcon = const Icon(Icons.color_lens);
  final GlobalKey<FormFieldState<String>> textFieldGrobalKey;
  final String? title;
  final String? helperText;
  final Color initColor;
  final double width;
  final Icon previewIcon;
  final Icon colorPickerIcon;

  @override
  State<ColorPickerTextField> createState() => _ColorPickerTextFieldState();
}

class _ColorPickerTextFieldState extends State<ColorPickerTextField> {
  late Color pickerColor;
  late Color currentColor;
  final _controller = TextEditingController();

  @override
  void initState() {
    pickerColor = widget.initColor;
    currentColor = widget.initColor;
    _controller.text = currentColor.toHexString();
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SizedBox(
          width: widget.width,
          child: TextFormField(
            // initialValue は使用せずinitStateで初期化
            key: widget.textFieldGrobalKey,
            controller: _controller,
            inputFormatters: [
              FilteringTextInputFormatter.allow(
                  RegExp(r'[0-9a-fA-F]')) // 数字およびa-f,A-Fのみ入力可能
            ],
            validator: (String? value) {
              if (value == null || value.isEmpty) return '値を入力してください。';
              if (value.length != 8) {
                return '8桁(ARGB)で指定してください。';
              }
              // 入力桁と入力文字の制限ですべてチェックできるはずなので不要かも
              if (value.toColor() == null) return '有効な入力値ではありません。';

              return null;
            },
            maxLength: 8,
            decoration: InputDecoration(
                counterText: '',
                // 左端の色プレビュー
                prefixIcon: widget.previewIcon,
                prefixIconColor: _controller.text.toColor(),
                // 右端のカラーピッカー起動ボタン
                suffixIcon: IconButton(
                    onPressed: () => showDialog(
                          context: context,
                          builder: (context) => AlertDialog(
                            content: SingleChildScrollView(
                              child: ColorPicker(
                                pickerColor: pickerColor,
                                onColorChanged: changeColor,
                              ),
                            ),
                            actions: <Widget>[
                              ElevatedButton(
                                child: const Text('決定'),
                                onPressed: () {
                                  setState(() {
                                    currentColor = pickerColor;
                                    _controller.text =
                                        currentColor.toHexString();
                                  });
                                  Navigator.of(context).pop();
                                },
                              ),
                            ],
                          ),
                        ),
                    icon: widget.colorPickerIcon),
                // その他外観
                border: const OutlineInputBorder(),
                labelText: widget.title,
                helperText: widget.helperText,
                helperMaxLines: 3),
            // テキスト直打ちしたときの処理
            onChanged: (text) => setState(() {
              currentColor = text.toColor() ?? const Color(0xffffffff);
              pickerColor = currentColor;
            }),
            // 桁数が足りない場合Fでパディングする
            onFieldSubmitted: (value) =>
                _controller.text = _controller.text.padLeft(8, 'F'),
            onEditingComplete: () =>
                _controller.text = _controller.text.padLeft(8, 'F'),
            onTapOutside: (event) =>
                _controller.text = _controller.text.padLeft(8, 'F'),
          ),
        )
      ],
    );
  }

  void changeColor(Color color) {
    setState(() => pickerColor = color);
  }
}

カラーピッカーのダイアログ起動ボタンはsuffixIcon、プレビューはprefixIconに指定する。
また、TextFormFieldでmaxLengthを指定している場合、何も指定しないと右下に入力字数がn/8の形式で表示されてしまうため、不要ならcounterTextを空文字列にすれば表示されなくなる。
呼び出し側でTextFormFieldの入力値を取得するためには、呼び出し側で生成したGlobalKey<FormFieldState<String>>を渡してあげる必要があるので注意。

ソースコード及び使用例

ソースコード

https://github.com/esuno/colorpicker_textfield

使用例

https://github.com/esuno/colorpicker_textfield/blob/main/example/lib/main.dart

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?