Flutter:如何将焦点放在自动完成字段上?

Haj*_*cke 3 focus autocomplete flutter

如何将焦点放在自动完成字段上,就像它与标准文本字段一起正常工作一样?

下面的例子可以直接启动。激活编辑焦点文本字段并按预期打开软键盘。激活搜索会在 AppBar 中打开搜索字段,但不会将其聚焦。

真实的页面相当复杂,因此不能选择自动对焦。

/// Flutter code sample for RawAutocomplete
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

void main() => runApp(const AutocompleteExampleApp());

class AutocompleteExampleApp extends StatelessWidget {
  const AutocompleteExampleApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Homepage(),
    );
  }
}

class Homepage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _HomepageState();
}

class _HomepageState extends State<Homepage> {
  bool _editActive = false, _searchActive = false;
  String? _autocompleteSelection;
  String _textValue = '';
  FocusNode _searchNode = FocusNode(debugLabel: 'SearchField'),
      _editNode = FocusNode(debugLabel: 'EditField');
  List<String> _resultList = [];
  TextEditingController _searchController = TextEditingController(),
      _editingController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: _editActive
          ? _buildAppBarEdit()
          : _searchActive
              ? _buildAppBarSearch()
              : _buildAppBar(),
      body: _buildBody(),
    );
  }

  @override
  void dispose() {
    _editingController.dispose();
    _searchController.dispose();
    super.dispose();
  }

  PreferredSizeWidget _buildAppBar() {
    return AppBar(
      title: Text('Focusing Autocomplete Problem'),
      actions: [
        IconButton(
          icon: Icon(Icons.search),
          onPressed: () => setState(() {
            _searchActive = true;
            FocusScope.of(context).requestFocus(_searchNode);
          }),
        ),
        IconButton(
          icon: Icon(Icons.edit),
          onPressed: () => setState(() {
            _editActive = true;
            FocusScope.of(context).requestFocus(_editNode);
          }),
        ),
      ],
    );
  }

  PreferredSizeWidget _buildAppBarEdit() {
    return AppBar(
      title: Text('Editing Mode'),
      actions: [
        IconButton(
          icon: Icon(Icons.done),
          onPressed: () {
            showInfo(context, 'Edit result = "$_textValue"');
            setState(() => _editActive = false);
          },
        ),
        IconButton(
          icon: Icon(Icons.cancel_outlined),
          onPressed: () => setState(() => _editActive = false),
        ),
      ],
    );
  }

  PreferredSizeWidget _buildAppBarSearch() {
    return AppBar(
      title: _buildSearchField(),
      actions: [
        IconButton(
          icon: Icon(Icons.done),
          onPressed: () => _onSearch(),
        ),
        IconButton(
          icon: Icon(Icons.cancel_outlined),
          onPressed: () => setState(() => _searchActive = false),
        ),
      ],
    );
  }

  Widget _buildBody() {
    return Column(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        _editActive
            ? TextField(
                controller: _editingController,
                decoration: InputDecoration(labelText: 'Some Value'),
                focusNode: _editNode,
                onChanged: (v) => _textValue = v,
              )
            : Text(_textValue),
        _resultList.isEmpty
            ? Center(
                child: Text('No results'),
              )
            : Column(
                children: _resultList.map((e) => Text(e)).toList(),
              ),
      ],
    );
  }

  void _onSearch() {
    showInfo(context, 'Searching for "$_autocompleteSelection"');
    setState(() => _searchActive = false);
  }

  static const List<String> _options = <String>[
    'Coca Cola',
    'Cocoribe',
    'Rum',
    'Malibu',
    'Ron Zacapa',
  ];

  Widget _buildSearchField() {
    return RawAutocomplete<String>(
      optionsBuilder: (TextEditingValue textEditingValue) {
        return _options.where((String option) {
          return option.contains(textEditingValue.text.toLowerCase());
        });
      },
      onSelected: (String selection) {
        setState(() {
          _autocompleteSelection = selection;
        });
        _onSearch();
      },
      focusNode: _searchNode,
      textEditingController: _searchController,
      fieldViewBuilder: (BuildContext context,
          TextEditingController textEditingController,
          FocusNode focusNode,
          VoidCallback onFieldSubmitted) {
        return TextField(
          controller: textEditingController,
          decoration: const InputDecoration(
            hintText: '<enter searchtext here>',
          ),
          focusNode: focusNode,
          onSubmitted: (String value) => onFieldSubmitted(),
        );
      },
      optionsViewBuilder: (BuildContext context,
          AutocompleteOnSelected<String> onSelected, Iterable<String> options) {
        return Align(
          alignment: Alignment.topLeft,
          child: Material(
            elevation: 4.0,
            child: SizedBox(
              height: 200.0,
              child: ListView.builder(
                padding: const EdgeInsets.all(8.0),
                itemCount: options.length,
                itemBuilder: (BuildContext context, int index) {
                  final String option = options.elementAt(index);
                  return GestureDetector(
                    onTap: () {
                      onSelected(option);
                    },
                    child: ListTile(
                      title: Text(option),
                    ),
                  );
                },
              ),
            ),
          ),
        );
      },
    );
  }
}

ScaffoldFeatureController<SnackBar, SnackBarClosedReason> showInfo(
    BuildContext context, String message) {
  return ScaffoldMessenger.of(context).showSnackBar(SnackBar(
    action: SnackBarAction(
      label: '<OK>',
      onPressed: () => ScaffoldMessenger.of(context).hideCurrentSnackBar(),
      textColor: Colors.orange,
    ),
    backgroundColor: Colors.green.shade100,
    content: Text(
      message,
//        overflow: TextOverflow.ellipsis,
      softWrap: true,
      style: TextStyle(color: Colors.black),
    ),
    duration: Duration(seconds: 5),
  ));
}
Run Code Online (Sandbox Code Playgroud)

Nei*_*ran 5

由于您已经有一个 FocusNode 变量,只需将其设置为 fieldViewBuilder 的 focusNode 参数即可。

late FocusNode myFocusNode; //Just one way of initializing a focus node. There are also other ways.

Autocomplete<String>( 
    ... // This represent the rest of your code
    fieldViewBuilder: (BuildContext context, TextEditingController controller, FocusNode focusNode, VoidCallback onFieldSubmitted) {
        myFocusNode = focusNode; // Assign your focus node to this builder's focus node
        return ...; // And here, to point out the answer.
    }
)
Run Code Online (Sandbox Code Playgroud)