flutterのTextFieldに削除アイコンを付ける

Flutter_icon Flutter
この記事は約9分で読めます。

この記事は、以下の方を対象に書いています。

  • TextFieldをカスタマイズしたい
  • TextFieldに削除用のアイコンをつけたい

実現したいこと

今回は、TextFieldをカスタマイズしていきます。

TextFieldに値が入っているときに削除アイコンを表示し、押すと値が消えるようにしてみます。

sample-1
実現したいこと

事前準備

まずは、flutterのプロジェクトを作成して、きれいにする作業からです。

プロジェクトを起動出来たら、main.dartを以下のようにきれいにしましょう。

import 'package:flutter/material.dart';

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: TextField(),
      ),
    );
  }
}

フォルダ分け

早速、カスタイズ用のファイルを作成しますが、その前にフォルダ分けをしておきましょう。

フォルダ分けは、プロジェクトの規模によって決めますが、

個人的にはいつも決まった構成にしています。

sample-2
フォルダ構成

ClearableTextFieldの作成

いよいよ、本番です。

値の削除(クリア)が可能なカスタムテキストフィールドを作成していきます。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class ClearableTextField extends StatefulWidget {
  final String label;
  TextEditingController controller;

  // 呼び出すときに値をセットする
  ClearableTextField({
    Key? key,
    required this.label,
    required this.controller,
  }) : super(key: key);

  @override
  State<ClearableTextField> createState() => _ClearableTextFieldState();
}

class _ClearableTextFieldState extends State<ClearableTextField> {
  @override
  void dispose() {
    widget.controller.dispose();
    super.dispose();
  }

  void _clearText() {
    // 値の削除
    widget.controller.clear();
    // これが一番重要(削除した後にロード)
    setState(() {
      /// 再ロード用
    });
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      // 位置調整
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
      child: TextField(
       // これも重要(テキストが変化したときにロード)
        onChanged: (newValue) {
          setState(() {
            /// 再ロード用
          });
        },
        // 呼び出し時にセットしたテキスト編集用コントローラー
        controller: widget.controller,
        // テキストフィールドのデコレーション
        decoration: InputDecoration(
          // 呼び出し時にセットしたラベル
          labelText: widget.label,
          // 枠線の設定
          border: const OutlineInputBorder(),
          // 3項演算子で値が入ってる、入っていないときの処理を分岐
          suffixIcon: widget.controller.text.isNotEmpty
              ? IconButton(icon: const Icon(Icons.clear, color: Colors.red,), onPressed: _clearText)
              : null,
        ),
      ),
    );
  }
}

カスタムテキストフィールドの呼び出し

カスタムテキストフィールドは作りましたが、

肝心の呼び出しをしていないので、最後に呼び出して終了になります。

そして、呼び出す際にコントローラーやラベルを渡します

今回はmain.dartを以下のように編集します。

import 'package:blog_sample/widgets/custom_text_field/ClearableTextField.dart';
import 'package:flutter/material.dart';

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  // 編集用コントローラーの定義
  TextEditingController _textEditingController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        // カスタムテキストフィールドの呼び出し
        child: ClearableTextField(controller: _textEditingController, label: 'サンプル',),
      ),
    );
  }
}

重要ポイント

今回のポイントをいくつか紹介します。

値の受け渡し

わざわざファイルを分けて、カスタムウィジェットを作成するということは、

再利用する可能性があり、値は汎用的であることがベストということです。

つまり、呼び出すときに受け渡す値を動的にすれば、汎用性は高くなります。

今回は、コントローラーとラベルを渡しています。

※コントローラーはあまり重要ではないですが、テキストフィールドをたくさん持っている場合は意味があります。今回は解説を省きます)

他にも、パディングの値を渡したり、アイコンを渡したり、汎用性を高める要素はいくつもあります。

今回紹介したコードを参考に自分だけのカスタムウィジェットを作ってみてください。

値を受け渡すためのコードは以下の通りです。

ClearableTextField -> 5 ~ 13行目(widget.変数名で使用できます)

main.dart -> 45行目(コントローラーの定義は35行目)

setStateで再ロード

ClearableTextFieldでsetStateを2か所使っています。

一度、この2つをコメントアウトして挙動を確かめてみてください。

setStateは、UIを再ロード(再描画)するためのメソッドです。

状態の変化を伝えることで、それに対応するビルドメソッドが呼び出され画面が更新されます。

今回は、テキストの変更時とテキストの削除後にsetStateで状態の更新をしています。

最後に

ここまで読んでいただき、ありがとうございます。

カスタムウィジェットを作れるようになったら、もっとflutterを好きになれるので、

どんどんチャレンジして自分だけのカスタムウィジェットを作ってみてください!

コメント

タイトルとURLをコピーしました