0

我正在构建一个包含联系人姓名和电话号码字段的表单。用户将能够从以前保存的联系人列表中选择(点击)联系人,这应该在各自的字段中显示姓名和电话号码。

为了实现这一点,我使用 Flutter_Form_Builder Package version: 3.14.0 中的 TypeAheadFormField 来构建我的表单。

我在默认的 TypeAheadFormField 控制器中成功地从本地数据库分配了 _nameController。但是我不能从我点击到 FormBuilderTextField 的同一选择中分配 _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),
                      ],
                    ),
                  ),
                  Container(
                    width: MediaQuery.of(context).size.width * 0.5,
                    margin: EdgeInsets.symmetric(horizontal: 15),
                    child: FormBuilderTextField(
                      attribute: 'phone_number',
                      controller: _inputContactPhoneController,
                      textAlign: TextAlign.start,
                      keyboardType: TextInputType.number,
                      decoration: InputDecoration(
                          prefixIcon: Icon(
                        Icons.phone_android,
                        size: 22,
                      )),
                      onChanged: (val) {
                        setState(() {
                          _customer.mobile = val;
                          _formKey.currentState.fields['phone_number'].currentState
                              .validate();
                        });
                      },
                      validators: [
                        FormBuilderValidators.required(),
                        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,
        where: '${Customer.colId}=?', whereArgs: [id]);
  }
}
4

1 回答 1

1

您从中获得的价值onSuggestionSelected是客户。使用该值更新_mobileController.text.

onSuggestionSelected: (customer) {
       if (customer != null) {
          setState(() {
             _mobileController.text = customer.mobile;
          });
       }
    }
于 2020-11-12T23:50:35.230 回答