You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Web自定义搜索组件选中搜索结果需点击两次问题求助

问题根因

  • 每次页面触发build时,FutureBuilder都会重新执行loadData()方法生成新的Future实例,没有对已加载的搜索结果做缓存。你给TextEditingController加了全局监听,每次文本变化/输入框失焦都会触发setState重建页面,导致搜索结果区域频繁销毁重建。
  • 输入完成后输入框处于获焦状态,第一次点击结果项时系统会优先触发输入框失焦逻辑,失焦立即触发setState重建页面,原本渲染的结果项被销毁,对应的onTap事件直接丢失,第二次点击时没有重建逻辑打断,才能正常触发点击事件。

修复方案

  1. 新增变量缓存搜索请求的Future实例,仅在输入文本实际变化时才重新发起搜索请求,避免每次build都重复加载
  2. 优化监听逻辑,同时点击结果项时优先清除输入框焦点,避免失焦触发不必要的重建

修复后完整代码

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: SearchView(),
  ));
}

class SearchView extends StatefulWidget {
  @override
  State<SearchView> createState() => _SearchViewState();
}

class _SearchViewState extends State<SearchView> {
  String searchResult = '';
  final textController = TextEditingController();
  final List<String> data = ['Result 1', 'Result 2', 'Result 3', 'Result 4'];
  // 新增变量缓存搜索Future实例
  Future<List<String>>? _searchFuture;

  Future<List<String>> loadData() {
    return Future.delayed(const Duration(seconds: 1), () {
      if (textController.text.trim().isNotEmpty) {
        return data;
      } else {
        return [];
      }
    });
  }

  @override
  void initState() {
    super.initState();
    textController.addListener(_onTextChanged);
  }

  void _onTextChanged() {
    print('text changed');
    // 仅在文本变化时更新搜索Future,无意义的全局setState
    setState(() {
      _searchFuture = loadData();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Brand'),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            TextFormField(
              controller: textController,
            ),
            FutureBuilder(
              // 绑定缓存的Future实例,不会每次build都重新生成
              future: _searchFuture,
              builder:
                  (BuildContext context, AsyncSnapshot<List<String>> snapshot) {
                if (snapshot.connectionState == ConnectionState.done &&
                    snapshot.hasData) {
                  print("future build");
                  return Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                      for (String result in snapshot.data!)
                        InkWell(
                          onTap: () {
                            print('Clicked');
                            // 点击时先清除焦点,避免失焦触发重建导致事件丢失
                            FocusScope.of(context).unfocus();
                            setState(() {
                              textController.clear();
                              searchResult = result;
                            });
                          },
                          child: Padding(
                            padding: const EdgeInsets.all(16.0),
                            child: Text(result),
                          ),
                        ),
                    ],
                  );
                } else if(snapshot.connectionState == ConnectionState.waiting){
                  return const CircularProgressIndicator();
                }else{
                  return const SizedBox.shrink();
                }
              },
            ),
            Text('Search result is $searchResult'),
          ],
        ),
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者rosh-dev851

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 08:15:03