如何让 Flutter 用户将标签输入 FormBuilderTextField(Flutter Form Builder 包)?
How to enable Flutter user to enter tags into a FormBuilderTextField (Flutter Form Builder package)?
我正在使用 flutter_form_builder 包 (link to package on pub.dev) 构建表单,并希望允许用户将标签输入 FormBuilderTextField,模仿 Whosebug 的 UI 输入标签(下面的屏幕截图)。
简单的FormBuilderTextField,供参考:
FormBuilderTextField(
attribute: 'sampleAttribute',
decoration: InputDecoration(
labelText: " Separate items, with, commas",
labelStyle: TextStyle(
fontSize: 12.0,
fontStyle: FontStyle.italic,
),
),
),
这个 Whosebug 问题很有帮助,但并没有真正解决这个问题。
如果您只有一个带行的容器以及一个 'tag_view' 小部件怎么办?
容器会像 Whosebug 一样有边框。该行是可滚动的并且有多个项目:
用户添加的每个标签和一个输入字段。每次用户接受标签时,您都会将其添加到标签列表中。
为此,您只需要一个带有包含不同 TagView 的小部件列表的行,并且在右边总是有一个 TextField
既然你似乎知道 flutter,我就不用代码来回答这个问题,而且粘贴在这里的代码也很长,但我就是这样做的。
推荐的标签会很容易处理,您只需将它们全部放在一个堆栈中,然后在顶部放置一个视图列表,其中包含推荐的标签以及您想要的任何视图
考虑使用 FormBuilderChipsInput 实现此功能。
我测试了很多选项并选择了 material_tag_editor 0.0.6 Flutter package。
这是 iPhone 模拟器 在 输入任何标签之前的屏幕截图:
这是输入了两个标签(使用逗号作为分隔符)的屏幕截图,同时正在输入第三个标签:
代码如下:
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
您可以使用 textfield_tags flutter 包在您的 Flutter 应用中实现此功能。请参阅以下示例:
import 'package:flutter/material.dart';
import 'package:textfield_tags/textfield_tags.dart';
void main() {
runApp( MaterialApp(
home: Home()
));
}
class Home extends StatefulWidget {
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<String> tags = ["flutter", "fluttercampus"]; //initial tags
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Enable Tag Input in TextField"),
backgroundColor: Colors.redAccent,
),
body: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
child: Column(
children:[
TextFieldTags(
textSeparators: [
" ", //seperate with space
',' //sepearate with comma as well
],
initialTags: tags,
onTag: (tag){
print(tag);
//this will give tag when entered new single tag
tags.add(tag);
},
onDelete: (tag){
print(tag);
//this will give single tag on delete
tags.remove(tag);
},
validator: (tag){
//add validation for tags
if(tag.length < 3){
return "Enter tag up to 3 characters.";
}
return null;
},
tagsStyler: TagsStyler( //styling tag style
tagTextStyle: TextStyle(fontWeight: FontWeight.normal),
tagDecoration: BoxDecoration(color: Colors.blue[100], borderRadius: BorderRadius.circular(0.0), ),
tagCancelIcon: Icon(Icons.cancel, size: 18.0, color: Colors.blue[900]),
tagPadding: EdgeInsets.all(6.0)
),
textFieldStyler: TextFieldStyler( //styling tag text field
textFieldBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2)
)
),
),
ElevatedButton(
onPressed: (){
print(tags);
//pint list of tags int the TextField
},
child: Text("Print Entered Tags")
)
]
),
)
);
}
}
此代码的输出:
我正在使用 flutter_form_builder 包 (link to package on pub.dev) 构建表单,并希望允许用户将标签输入 FormBuilderTextField,模仿 Whosebug 的 UI 输入标签(下面的屏幕截图)。
简单的FormBuilderTextField,供参考:
FormBuilderTextField(
attribute: 'sampleAttribute',
decoration: InputDecoration(
labelText: " Separate items, with, commas",
labelStyle: TextStyle(
fontSize: 12.0,
fontStyle: FontStyle.italic,
),
),
),
这个
如果您只有一个带行的容器以及一个 'tag_view' 小部件怎么办?
容器会像 Whosebug 一样有边框。该行是可滚动的并且有多个项目:
用户添加的每个标签和一个输入字段。每次用户接受标签时,您都会将其添加到标签列表中。
为此,您只需要一个带有包含不同 TagView 的小部件列表的行,并且在右边总是有一个 TextField
既然你似乎知道 flutter,我就不用代码来回答这个问题,而且粘贴在这里的代码也很长,但我就是这样做的。
推荐的标签会很容易处理,您只需将它们全部放在一个堆栈中,然后在顶部放置一个视图列表,其中包含推荐的标签以及您想要的任何视图
考虑使用 FormBuilderChipsInput 实现此功能。
我测试了很多选项并选择了 material_tag_editor 0.0.6 Flutter package。
这是 iPhone 模拟器 在 输入任何标签之前的屏幕截图:
这是输入了两个标签(使用逗号作为分隔符)的屏幕截图,同时正在输入第三个标签:
代码如下:
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
您可以使用 textfield_tags flutter 包在您的 Flutter 应用中实现此功能。请参阅以下示例:
import 'package:flutter/material.dart';
import 'package:textfield_tags/textfield_tags.dart';
void main() {
runApp( MaterialApp(
home: Home()
));
}
class Home extends StatefulWidget {
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<String> tags = ["flutter", "fluttercampus"]; //initial tags
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Enable Tag Input in TextField"),
backgroundColor: Colors.redAccent,
),
body: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
child: Column(
children:[
TextFieldTags(
textSeparators: [
" ", //seperate with space
',' //sepearate with comma as well
],
initialTags: tags,
onTag: (tag){
print(tag);
//this will give tag when entered new single tag
tags.add(tag);
},
onDelete: (tag){
print(tag);
//this will give single tag on delete
tags.remove(tag);
},
validator: (tag){
//add validation for tags
if(tag.length < 3){
return "Enter tag up to 3 characters.";
}
return null;
},
tagsStyler: TagsStyler( //styling tag style
tagTextStyle: TextStyle(fontWeight: FontWeight.normal),
tagDecoration: BoxDecoration(color: Colors.blue[100], borderRadius: BorderRadius.circular(0.0), ),
tagCancelIcon: Icon(Icons.cancel, size: 18.0, color: Colors.blue[900]),
tagPadding: EdgeInsets.all(6.0)
),
textFieldStyler: TextFieldStyler( //styling tag text field
textFieldBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2)
)
),
),
ElevatedButton(
onPressed: (){
print(tags);
//pint list of tags int the TextField
},
child: Text("Print Entered Tags")
)
]
),
)
);
}
}
此代码的输出: