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

Flutter Autocomplete匹配列表不显示问题求助

Hey there! Let's troubleshoot why your Flutter Autocomplete component isn't showing suggestions after fetching data from your API. I've looked through your code and spotted a few key issues that are causing this problem.

What's Going Wrong?

  1. Initializing the Autocomplete Field in build()
    Flutter calls the build() method frequently (like when you call setState, rotate the screen, etc.). Every time it runs, you're creating a new instance of AutoCompleteTextField—this resets the component's state, so it can't pick up the updated users list after your API call.

  2. Static users List
    Making users a static variable breaks Flutter's state management. When you update this list, the widget doesn't recognize the change, even when you call setState().

  3. Missing Loading State Sync
    Your loading state wasn't being updated when the API call starts, and the component wasn't reacting properly to the new users data once it arrived.

Fixed Code for autocompleter.dart

Here's the revised code that fixes these issues:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'user.dart';
import 'dart:convert';
import 'package:autocomplete_textfield/autocomplete_textfield.dart';

class AutoCompleteDemo extends StatefulWidget {
  AutoCompleteDemo() : super();
  final String title = "AutoComplete Demo";

  @override
  _AutoCompleteDemoState createState() => _AutoCompleteDemoState();
}

class _AutoCompleteDemoState extends State<AutoCompleteDemo> {
  AutoCompleteTextField? searchTextField;
  GlobalKey<AutoCompleteTextFieldState<User>> key = GlobalKey();
  List<User> users = []; // Removed static keyword to make it an instance variable
  bool loading = false;

  void getUsers(String name) async {
    // Clear suggestions if input is empty
    if (name.isEmpty) {
      setState(() {
        users = [];
        loading = false;
      });
      return;
    }

    // Show loading state before making API call
    setState(() => loading = true);

    try {
      final response = await http.get(Uri.parse("https://pptndt.com/api/unitsDropDown?name=$name"));
      if (response.statusCode == 200) {
        final fetchedUsers = loadUsers(response.body);
        setState(() {
          users = fetchedUsers;
          loading = false;
        });
        print('Fetched ${users.length} users');
      } else {
        print('Failed to fetch users: Status code ${response.statusCode}');
        setState(() => loading = false);
      }
    } catch (e) {
      print('Error fetching users: $e');
      setState(() => loading = false);
    }
  }

  static List<User> loadUsers(String jsonString) {
    final parsed = json.decode(jsonString).cast<Map<String, dynamic>>();
    return parsed.map<User>((json) => User.fromJson(json)).toList();
  }

  @override
  void initState() {
    super.initState();
    // Initialize the autocomplete field once in initState
    searchTextField = AutoCompleteTextField<User>(
      key: key,
      clearOnSubmit: false,
      suggestions: users,
      style: const TextStyle(color: Colors.black, fontSize: 16.0),
      decoration: const InputDecoration(
        contentPadding: EdgeInsets.fromLTRB(10.0, 30.0, 10.0, 20.0),
        hintText: "Search Name",
        hintStyle: TextStyle(color: Colors.black),
      ),
      textChanged: (query) => getUsers(query),
      itemFilter: (item, query) {
        return item.name.toLowerCase().startsWith(query.toLowerCase());
      },
      itemSorter: (a, b) {
        return a.name.compareTo(b.name);
      },
      itemSubmitted: (item) {
        setState(() {
          searchTextField?.textField.controller.text = item.name;
        });
      },
      itemBuilder: (context, item) {
        return Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              item.name,
              style: const TextStyle(fontSize: 20.0),
            ),
            const SizedBox(width: 10.0),
          ],
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          // Show loading indicator while fetching data
          if (loading) const Padding(
            padding: EdgeInsets.all(8.0),
            child: CircularProgressIndicator(),
          ),
          // Render the pre-initialized autocomplete field
          if (searchTextField != null) searchTextField!,
        ],
      ),
    );
  }
}

Extra Tips to Improve Your Implementation

  • Add Debouncing: To avoid spamming your API with a request for every keystroke, add a small delay before triggering the API call. Here's how:
    Timer? _debounceTimer;
    
    void getUsers(String name) {
      _debounceTimer?.cancel();
      _debounceTimer = Timer(const Duration(milliseconds: 300), () async {
        // Your existing API logic goes here
      });
    }
    
    @override
    void dispose() {
      _debounceTimer?.cancel();
      super.dispose();
    }
    
  • Error UI Feedback: Instead of just printing errors to the console, show a snackbar or error message to the user so they know something went wrong.
  • Null Safety: I added some null safety checks (like AutoCompleteTextField? and searchTextField!) to align with modern Flutter practices.

内容的提问来源于stack exchange,提问作者pri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:18:00