问题描述
我正在建立一个包含联系人姓名和电话号码字段的表单。用户将能够从以前保存的联系人列表中选择(点击)联系人,这将在其各自的字段中显示姓名和电话号码。
要实现此目的,我使用的是Flutter_Form_Builder软件包版本:3.14.0中的TypeAheadFormField来构建表单。
我在默认的TypeAheadFormField控制器中成功从本地数据库分配了_nameController。 但是我无法通过选择与FormFormerTextField相同的选项来分配_mobileController。
我设法通过TypeAheadFormField获得“名称”值,但是每次我从建议中切换选择时, _mobileController.text在FormBuilderTextField上未更新
我的代码如下:
import 'package:myApp/customer.dart';
import 'package:myApp/db_helper.dart';
import 'package:Flutter/material.dart';
import 'package:Flutter_form_builder/Flutter_form_builder.dart';
class MyForm extends StatefulWidget {
@override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
DatabaseHelper _dbHelper;
Customer _customer = Customer();
List<Customer> _customerList = [];
final _formKey = GlobalKey<FormBuilderState>();
final _cfKey = GlobalKey<FormBuilderState>();
final _nameController = TextEditingController();
final _inputContactNameController = TextEditingController();
final _inputContactPhoneController = TextEditingController();
var _mobileController = TextEditingController();
@override
void initState() {
super.initState();
_refreshBikeSellerList();
setState(() {
_dbHelper = DatabaseHelper.instance;
});
_mobileController = TextEditingController();
_mobileController.addListener(() {
setState(() {});
});
}
@override
void dispose() {
_mobileController.dispose();
_nameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
child: FormBuilder(
key: _formKey,child: Column(
children: [
FormBuilderTypeAhead(
attribute: 'contact_person',initialValue: _customer,controller: _nameController,onChanged: (val) {},itemBuilder: (context,Customer _customer) {
return ListTile(
title: Text(_customer.name),subtitle: Text(_customer.mobile),);
},selectionToTextTransformer: (Customer c) => c.name,suggestionsCallback: (query) {
if (query.isNotEmpty) {
var lowercaseQuery = query.toLowerCase();
return _customerList.where((_customer) {
return _customer.name
.toLowerCase()
.contains(lowercaseQuery);
}).toList(growable: false)
..sort((a,b) => a.name
.toLowerCase()
.indexOf(lowercaseQuery)
.compareto(
b.name.toLowerCase().indexOf(lowercaseQuery)));
} else {
return _customerList;
}
},textFieldConfiguration: TextFieldConfiguration(
autofocus: true,style: DefaultTextStyle.of(context).style.copyWith(
fontSize: 17,letterSpacing: 1.2,color: Colors.black,fontWeight: FontWeight.w300,),// controller: guessMotor1,onSuggestionSelected: (val) {
if (val != null) {
return _customerList.map((_customer) {
setState(() {
_mobileController.text = _customer.mobile;
});
}).toList();
} else {
return _customerList;
}
},FormBuilderTextField(
controller: _mobileController,attribute: 'mobile',readOnly: true,style: TextStyle(fontSize: 17),decoration: Inputdecoration(
hintText: 'mobile',SizedBox(height: 40),Container(
child: RaisedButton(
onpressed: () async {
await manageContact(context);
},child: Text('Manage Contact'),],);
}
manageContact(BuildContext context) async {
showDialog(
context: context,builder: (context) => AlertDialog(
title: Text(
'Manage Contact',textAlign: TextAlign.center,titleTextStyle: TextStyle(
fontWeight: FontWeight.w500,fontSize: 17,color: Colors.black45,letterSpacing: 0.8),shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),content: FormBuilder(
key: _cfKey,child: Column(
mainAxisSize: MainAxisSize.min,children: [
// SizedBox(height: 10),InkResponse(
onTap: () {},child: CircleAvatar(
radius: 30,child: Icon(
Icons.person_add,color: Colors.grey[100],backgroundColor: Colors.grey[500],SizedBox(height: 10),Container(
width: MediaQuery.of(context).size.width * 0.5,margin: EdgeInsets.symmetric(horizontal: 15),child: FormBuilderTextField(
maxLength: 20,controller: _inputContactNameController,textAlign: TextAlign.start,keyboardType: TextInputType.text,textCapitalization: TextCapitalization.words,attribute: 'contact_person',decoration: Inputdecoration(
prefixIcon: Icon(
Icons.person_outline,size: 22,)),onChanged: (val) {
setState(() {
_customer.name = val;
_formKey
.currentState.fields['contact_person'].currentState
.validate();
});
},autovalidateMode: AutovalidateMode.always,validators: [
FormBuilderValidators.required(),FormBuilderValidators.maxLength(20),FormBuilderValidators.minLength(2),child: FormBuilderTextField(
attribute: 'phone_number',controller: _inputContactPhoneController,keyboardType: TextInputType.number,decoration: Inputdecoration(
prefixIcon: Icon(
Icons.phone_android,onChanged: (val) {
setState(() {
_customer.mobile = val;
_formKey.currentState.fields['phone_number'].currentState
.validate();
});
},FormBuilderValidators.numeric(),valueTransformer: (text) {
return text == null ? null : num.tryParse(text);
},SizedBox(height: 20),Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,children: [
RaisedButton(
color: Colors.white,child: Text('Cancel'),onpressed: () {
Navigator.of(context).pop();
}),RaisedButton(
color: Colors.grey[400],child: Text(
'Save',style: TextStyle(color: Colors.white),onpressed: () async {
try {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
if (_customer.id == null)
await _dbHelper.insertBikeContact(_customer);
else
await _dbHelper.updateCustomer(_customer);
_refreshBikeSellerList();
_formKey.currentState.reset();
_inputContactNameController.clear();
_inputContactPhoneController.clear();
Navigator.of(context).pop();
}
} catch (e) {
print(e);
}
},)
],);
}
_refreshBikeSellerList() async {
List<Customer> x = await _dbHelper.getCustomer();
setState(() {
_customerList = x;
});
}
}
我点击时有没有可能更新_mobileController的方法?
任何帮助将不胜感激。 预先谢谢你。
已编辑:
我保存客户数据的类:
class Customer {
int id;
String name;
String mobile;
static const tblCustomer = 'Customer';
static const colId = 'id';
static const colName = 'name';
static const colMobile = 'mobile';
Customer({
this.id,this.name,this.mobile,});
Map<String,dynamic> toMap() {
var map = <String,dynamic>{colName: name,colMobile: mobile};
if (id != null) map[colId] = id;
return map;
}
Customer.fromMap(Map<String,dynamic> map) {
id = map[colId];
name = map[colName];
mobile = map[colMobile];
}
@override
bool operator ==(Object other) =>
identical(this,other) ||
other is Customer &&
runtimeType == other.runtimeType &&
name == other.name;
@override
int get hashCode => name.hashCode;
@override
String toString() {
return name;
}
}
这是我的数据库:
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import 'customer.dart';
class DatabaseHelper {
static const _databaseVersion = 1;
static const _databaseName = 'Kiloin.db';
DatabaseHelper._();
static final DatabaseHelper instance = DatabaseHelper._();
Database _database;
Future<Database> get database async {
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}
_initDatabase() async {
Directory dataDirectory = await getApplicationDocumentsDirectory();
String dbPath = join(dataDirectory.path,_databaseName);
return await openDatabase(
dbPath,version: _databaseVersion,onCreate: _onCreateDB,);
}
_onCreateDB(Database db,int version) async {
await db.execute('''
CREATE TABLE ${Customer.tblCustomer}(
${Customer.colId} INTEGER PRIMARY KEY AUTOINCREMENT,${Customer.colName} TEXT NOT NULL,${Customer.colMobile} TEXT NOT NULL
)
''');
}
Future<int> insertBikeContact(Customer customer) async {
Database db = await database;
return await db.insert(Customer.tblCustomer,customer.toMap());
}
Future<List<Customer>> getCustomer() async {
Database db = await database;
List<Map> contact = await db.query(Customer.tblCustomer);
return contact.length == 0
? []
: contact.map((e) => Customer.fromMap(e)).toList();
}
Future<int> updateCustomer(Customer customer) async {
Database db = await database;
return await db.update(Customer.tblCustomer,customer.toMap(),where: '${Customer.colId}=?',whereArgs: [customer.id]);
}
Future<int> deleteContact(int id) async {
Database db = await database;
return await db.delete(Customer.tblCustomer,whereArgs: [id]);
}
}
解决方法
您从onSuggestionSelected
获得的价值就是客户。使用该值来更新_mobileController.text
。
onSuggestionSelected: (customer) {
if (customer != null) {
setState(() {
_mobileController.text = customer.mobile;
});
}
}