Search code examples
formsfluttertags

How to enable Flutter user to enter tags into a FormBuilderTextField (Flutter Form Builder package)?


I'm building a form using the flutter_form_builder package (link to package on pub.dev) and would like to enable the user to enter tags into a FormBuilderTextField, mimicking StackOverflow's UI for entering tags (screenshot below).

screenshot of StackOverflow's UI for entering tags

Simple FormBuilderTextField, for reference:

FormBuilderTextField(
                      attribute: 'sampleAttribute',
                      decoration: InputDecoration(
                        labelText: "  Separate items,  with,  commas",
                        labelStyle: TextStyle(
                          fontSize: 12.0,
                          fontStyle: FontStyle.italic,
                        ),
                      ),
                    ),

This "Flutter - allow user enter hashtags" StackOverflow question was helpful, but doesn't really address this.


Solution

  • I tested many options and settled on the material_tag_editor 0.0.6 Flutter package.

    Here's a screenshot from an iPhone simulator before any tags are entered:

    screenshot with no tags entered

    And here's a screenshot with two tags entered (using the comma as a delimiter), while in the middle of typing a 3rd tag:

    screenshot while entering 3rd tag

    Here's the code:

    body: SingleChildScrollView(
        child: Container(
          child: Builder(
            builder: (context) => FormBuilder(
              // was "builder: (context) => Form("
              key: _formbuilderKey,
              initialValue: {
                'date': DateTime.now(),
              },
              child: Padding(
                padding: const EdgeInsets.all(14.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    SizedBox(
                      height: 12.0,
                    ),
                    RichText(
                      text: TextSpan(
                        style: TextStyle(
                          color: Colors.blue,
                        ),
                        children: <TextSpan>[
                          TextSpan(
                            text:
                                'In just a few words, what are 3 positive things about dogs?', // was 'What are 3 good or positive things about the house, property or neighborhood?', //  [ 1 ​]
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 16.0,
                            ),
                          ),
                          TextSpan(
                            text: '  (optional)',
                            style: TextStyle(
                              fontWeight: FontWeight.normal,
                              fontStyle: FontStyle.italic,
                              fontSize: 14.0,
                              color: Colors.black54,
                            ), // was 'misleading or inaccurate?',
                          ),
                        ],
                      ),
                    ),
                    // BEGIN code from material_tag_editor
                    Padding(
                      padding: const EdgeInsets.only(top: 16.0),
                      child: TagEditor(
                        length: somethingHere.length,
                        delimiters: [
                          ','
                        ], // was delimiters: [',', ' '],  Also tried "return" ('\u2386',)
                        hasAddButton: true,
                        textInputAction: TextInputAction
                            .next, // moves user from one field to the next!!!!
                        autofocus: false,
                        maxLines: 1,
                        // focusedBorder: OutlineInputBorder(
                        //   borderSide: BorderSide(color: Colors.lightBlue),
                        //   borderRadius: BorderRadius.circular(20.0),
                        // ),
                        inputDecoration: const InputDecoration(
                          // below was "border: InputBorder.none,"
                          isDense: true,
                          border: OutlineInputBorder(
                            borderRadius: const BorderRadius.all(
                              const Radius.circular(20.0),
                            ),
                          ),
                          focusedBorder: OutlineInputBorder(
                            borderSide: BorderSide(color: Colors.lightBlue),
                            borderRadius: const BorderRadius.all(
                              const Radius.circular(20.0),
                            ),
                            // above is per https://github.com/flutter/flutter/issues/5191
                          ),
                          labelText: 'separate,  with,  commas',
                          labelStyle: TextStyle(
                            fontStyle: FontStyle.italic,
                            backgroundColor:
                                Color(0x65dffd02), // was Color(0xffDDFDFC),
                            color: Colors.black87, // was Color(0xffD82E6D),
                            fontSize: 14,
                          ),
                        ),
                        onTagChanged: (newValue) {
                          setState(() {
                            somethingHere.add(newValue);
                          });
                        },
                        tagBuilder: (context, index) => _Chip(
                          index: index,
                          label: somethingHere[index],
                          onDeleted: onDelete,
                        ),
                      ),
                    ),
                    // END code from material_tag_editor