0

我正在使用Flutter Typeahead来使用谷歌地图位置自动完成功能。一切正常,除了我无法让 textField 显示所选的建议文本。我将 设置TextEditingController.text为一些有效的文本,它只是在 TextField 中不显示任何内容:

viewModel.typeAheadController.text =
                              suggestion.structuredFormatting.mainText;

当我TextEditingController在选择选项时设置了文本值时,为什么选定的建议文本不会显示在 TextField 中?

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:google_maps_webservice/places.dart';
import 'package:reactive_forms/reactive_forms.dart';
import 'package:flutter/widgets.dart';
import 'package:vepo/fonts.gen.dart';
import 'package:vepo/src/domain/entities/establishment/establishment_domain_entity.dart';
import 'package:vepo/src/presentation/widgets/purely_display_widgets/text/caption_widget.dart';
import 'establishments_autocomplete_field_view_model.dart';

class VpEstablishmentsAutocompleteField
    extends ReactiveFormField<EstablishmentDomainEntity> {
  VpEstablishmentsAutocompleteField(
      {@required String formControlName,
      this.context,
      this.label,
      this.hint,
      bool hasFocus = false,
      this.onFocusChange,
      Map<String, String> Function(AbstractControl<dynamic>) validationMessages,
      this.key})
      : super(
            key: key,
            formControlName: formControlName,
            validationMessages: validationMessages,
            showErrors: (control) => control.invalid,
            builder: (ReactiveFormFieldState<EstablishmentDomainEntity> field) {
              final viewModel = ProviderContainer()
                  .read<EstablishmentsAutocompleteFieldViewModel>(
                      establishmentsAutocompleteViewModelProvider);
              return FocusScope(
                  child: Focus(
                      onFocusChange: (isFocused) {
                        hasFocus = isFocused;
                        if (onFocusChange != null) {
                          onFocusChange(isFocused);
                        }
                        field.setState(() {});
                      },
                      child: TypeAheadFormField<Prediction>(
                        textFieldConfiguration: TextFieldConfiguration(
                          controller: viewModel.typeAheadController,
                          autofocus: true,
                          decoration: InputDecoration(
                              errorMaxLines: 3,
                              suffixIconConstraints: const BoxConstraints(
                                minWidth: 2,
                                minHeight: 2,
                              ),
                              suffixIcon: ReactiveStatusListenableBuilder(
                                formControlName: formControlName,
                                builder: (context, control, child) {
                                  return control.pending
                                      ? Container(
                                          width: 90,
                                          height: 60,
                                          child: Stack(children: [
                                            Positioned(
                                              top: 10,
                                              right: 15,
                                              child: CircularProgressIndicator(
                                                  backgroundColor:
                                                      Theme.of(context)
                                                          .primaryColorDark),
                                            )
                                          ]))
                                      : Container(width: 0);
                                },
                              ),
                              alignLabelWithHint: true,
                              labelStyle: TextStyle(
                                  height: 0,
                                  fontSize: hasFocus ? 24 : 18.0,
                                  color: Theme.of(context).primaryColor),
                              hintText: hint,
                              labelText: label,
                              counterText: ''),
                        ),
                        suggestionsCallback: (pattern) async {
                          return await viewModel.fetchSuggestions(
                              pattern, context);
                        },
                        suggestionsBoxDecoration: SuggestionsBoxDecoration(
                          elevation: 20,
                          color: Theme.of(context).scaffoldBackgroundColor,
                          borderRadius: const BorderRadius.all(
                            Radius.circular(10.0),
                          ),
                        ),
                        itemBuilder: (context, suggestion) {
                          return ListTile(
                            leading: FaIcon(FontAwesomeIcons.storeAlt,
                                size: 25,
                                color: Theme.of(context).primaryColor),
                            title: RichText(
                              text: TextSpan(
                                text: viewModel.getBoldText(
                                    suggestion.structuredFormatting.mainText,
                                    suggestion.structuredFormatting
                                        .mainTextMatchedSubstrings.first),
                                style: TextStyle(
                                    fontSize: 20,
                                    fontFamily: FontFamily.hind,
                                    fontWeight: FontWeight.bold,
                                    color: Theme.of(context).primaryColorDark),
                                children: <TextSpan>[
                                  TextSpan(
                                      text: suggestion
                                          .structuredFormatting.mainText
                                          .substring(suggestion
                                              .structuredFormatting
                                              .mainTextMatchedSubstrings
                                              .first
                                              .length as int),
                                      style: const TextStyle(
                                          fontWeight: FontWeight.w200,
                                          color: Colors.black54))
                                ],
                              ),
                            ),
                            subtitle: VpCaption(
                              text:
                                  suggestion.structuredFormatting.secondaryText,
                              color: Colors.black54,
                              fontSize: 17,
                              overflow: TextOverflow.visible,
                            ),
                          );
                        },
                        onSuggestionSelected: (suggestion) {
                          viewModel.typeAheadController.text =
                              suggestion.structuredFormatting.mainText;
                          viewModel.typeAheadController.value =
                              TextEditingValue(
                                  text:
                                      suggestion.structuredFormatting.mainText);
                          final x = EstablishmentDomainEntity(
                              placeId: suggestion.placeId);

                          field.didChange(x);
                          field.control.markAsTouched();
                          field.control.markAsDirty();
                        },
                      )));
            });
  final Key key;
  final BuildContext context;
  final String label;
  final String hint;
  bool hasFocus;
  final void Function(bool) onFocusChange;
  @override
  ReactiveFormFieldState<EstablishmentDomainEntity> createState() =>
      ReactiveFormFieldState<EstablishmentDomainEntity>();
}
4

2 回答 2

1

你的TextEditingController初始化了吗?此代码对我来说很好,并在选择选项时更新。

final TextEditingController _typeAheadController = TextEditingController();


...


                Container(
                    width: constraints.maxWidth * 0.80,
                    height: 50,
                    decoration: BoxDecoration(
                        color: Color.fromRGBO(245, 245, 245, 1),
                        borderRadius: BorderRadius.all(Radius.circular(50))),
                    child: Padding(
                      padding: EdgeInsets.only(left: 20),
                      child: TypeAheadField(
                          hideOnEmpty: true,
                          textFieldConfiguration: TextFieldConfiguration(
                            autofocus: false,
                            controller: _typeAheadController,
                            decoration: InputDecoration(
                              border: InputBorder.none,
                              hintText: 'Enter your city',
                              hintStyle: TextStyle(
                                  fontFamily: 'Metropolis-SemiBold',
                                  color: Color.fromRGBO(197, 197, 197, 1)),
                            ),
                          ),
                          suggestionsCallback: (pattern) async {
                            var x = await FunctionsService()
                                .getRegionSuggestion(pattern);
                            locationCodes = x[1];
                            suggestionList = x[0];
                            return x[0];
                          },
                          itemBuilder: (context, suggestion) {
                            return ListTile(
                              title: Text(suggestion),
                            );
                          },
                          onSuggestionSelected: (suggestion) {
                            setState(() {
                              _typeAheadController.text = suggestion;
                              publicLocation = suggestion.toString();
                              locationSelected = true;
                            });
                          }),
                    ),
                  ),
于 2021-03-03T04:51:17.643 回答
0

这是一个非常具体的场景,因为我使用了这么多包。

我需要为reactive_forms创建一个自定义控件值访问器,因为我的表单值是一个复杂对象 ( EstablishmentDomainEntity),而不是字符串:

import 'package:reactive_forms/reactive_forms.dart';
import 'package:vepo/src/domain/entities/establishment/establishment_domain_entity.dart';

/// Represents a control value accessor that convert between data types
/// [EstablishmentDomainEntity] and [String].
class EstablishmentValueAccessor
    extends ControlValueAccessor<EstablishmentDomainEntity, String> {
  @override
  String modelToViewValue(EstablishmentDomainEntity modelValue) {
    return modelValue == null ? '' : modelValue.name;
  }

  @override
  EstablishmentDomainEntity viewToModelValue(String viewValue) {
    return (viewValue == '' || viewValue == null)
        ? null
        : EstablishmentDomainEntity(name: viewValue);
  }
}

然后在我的自定义小部件构造函数中,我必须传入值访问器:

class VpEstablishmentsAutocompleteField
    extends ReactiveFormField<EstablishmentDomainEntity> {
  VpEstablishmentsAutocompleteField(
      {@required String formControlName,
      this.key})
      : super(
            key: key,
            formControlName: formControlName,
            valueAccessor: EstablishmentValueAccessor(),

然后在我的TypeAheadFormField onSuggestionSelected, 调用field.didChange并手动设置 TypeAheadFormField TextEditingController.text

            onSuggestionSelected: (suggestion) {
              viewModel.typeAheadController.text =
                  suggestion.structuredFormatting.mainText;
              final x = EstablishmentDomainEntity(
                  placeId: suggestion.placeId,
                  name: suggestion.structuredFormatting.mainText);
              field.didChange(x);
            },
于 2021-03-03T08:04:25.520 回答