Put your feet on the ground

主にプログラミングのお話。

Flutterで複数行テキストフォーム&キーボードの上にツールバーを表示

テキスト入力している時に、キーボードに完了ボタンをつけたいなどのあるあるに対応できます。
iOSだとUITextFieldのinputAccessoryViewにUIToolBarを設定すればいいですが、Flutterの場合こうしたらいいのではと実装してみました。

①まず適当に画面を作成します。

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

class MyTextFormView extends StatefulWidget {
  @override
  State createState() {
    return MyTextFormViewState();
  }
}

class MyTextFormViewState extends State {
  @override
  Widget build(BuildContext context) {
    List columnWidget = [
      Expanded(
        child: _scrollableTextField(),
      )
    ];

    return Scaffold(
      appBar: AppBar(
        title: Text('テキスト入力'),
      ),
      body: Container(
        child: Column(
          children: columnWidget,
        ),
      ),
    );
  }

  Widget _scrollableTextField() {
    // ListViewにいれてあげることで、テキストフォームの高さが広がるに応じてスクロールできる
    return ListView(
      children: [
        Container(
          margin: const EdgeInsets.all(10.0),
          decoration: BoxDecoration(
              color: Colors.pink[100],
              border: Border.all(color: Colors.black),
              borderRadius: BorderRadius.all(Radius.circular(5.0))),
          child: TextField(
            decoration: InputDecoration(border: InputBorder.none), //テキストフォーム下の下線
            keyboardType: TextInputType.multiline, 
            maxLines: null,
            textAlign: TextAlign.left,
          ),
        ),
      ],
    );
  }
}

これで複数行テキストフォームができる。

f:id:karmactonics:20180908093031g:plain:w200

このままだとテキスト入力を終えた時に、フォーカスを外すことができないので、ツールバーを追加します。
②まずTextFieldに、フォーカスを管理するインスタンスを設定します。

class MyTextFormViewState extends State {
  FocusNode focusNode = FocusNode(); //追加

  @override
  Widget build(BuildContext context) {
  ...

...
child: TextField(
            decoration:
                InputDecoration(border: InputBorder.none), //テキストフォーム下の下線
            keyboardType: TextInputType.multiline,
            maxLines: null,
            textAlign: TextAlign.left,
            focusNode: this.focusNode, // 追加
          ),
...

これでテキストがフォーカスされているかの判定ができるので、
build()内でツールバーの出し分けができる。

ツールバーを作って…

  Widget _normalToolBar() {
    return Container(
        decoration: BoxDecoration(
            border: BorderDirectional(top: BorderSide(color: Colors.black)),
            color: Colors.grey[200]),
        height: 50.0,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            CupertinoButton(
              child: Text('完了'),
              onPressed: () {
                focusNode.unfocus(); //unfocus()でフォーカスが外れる
              },
            )
          ],
        ));
  }

④build()で生成。

  @override
  Widget build(BuildContext context) {
    List columnWidget = [
      Expanded(
        child: _scrollableTextField(),
      )
    ];

    // 追加 //
    if (focusNode != null && focusNode.hasFocus == true) {
      var toolBar = _normalToolBar();
      columnWidget.add(toolBar);
    }
   //////////

    return Scaffold(
    ...

完成。
f:id:karmactonics:20180908101107g:plain
このアプリの全ソースコードgitHubにアップしました
今回のコードはこちら

もともとはずっとSwiftやObjective-C書いてたんですけど、
FlutterでDart書いてるほうが実は楽しかったりする…笑