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

Flutter本地JSON搜索栏实现问题:数据无法显示排查

Flutter本地JSON搜索后数据不显示问题排查与修复

以下是你的代码中存在的核心问题及修复方案:

问题点分析

  • 未正确初始化数据源:initState中调用ReadJsonData但未将返回结果赋值给_userDetails,同时FutureBuilder每次build都会重新加载JSON,但同样没把数据存入_userDetails,导致原始数据始终为空。
  • 搜索结果列表数据源错误:搜索结果的ListView使用了_userDetails[index],而非过滤后的_searchResult[index],且未设置itemCount,无法正确渲染搜索结果。
  • UI未触发更新:onSearchTextChanged中修改_searchResult后未调用setState,导致UI不会刷新显示过滤结果。
  • 条件判断逻辑缺陷:当输入搜索文本但无匹配结果时,会显示空列表,没有处理无结果的提示。

修复后的完整代码

import 'dart:convert';

import 'package:falamhymns/models/sawnawk_model.dart';
import 'package:falamhymns/sub_screens/detail_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' as rootBundle;

class SawnawkScreen extends StatefulWidget {
  SawnawkScreen({Key? key}) : super(key: key);

  @override
  State<SawnawkScreen> createState() => _SawnawkScreenState();
}

class _SawnawkScreenState extends State<SawnawkScreen> {
  final TextEditingController controller = TextEditingController();
  List<SawnAwkModel> _searchResult = [];
  List<SawnAwkModel> _userDetails = [];
  bool _isLoading = true;

  @override
  void initState() {
    super.initState();
    _loadJsonData();
  }

  // 加载JSON数据并赋值给_userDetails
  Future<void> _loadJsonData() async {
    final data = await ReadJsonData();
    setState(() {
      _userDetails = data;
      _isLoading = false;
    });
  }

  void onSearchTextChanged(String text) {
    _searchResult.clear();

    if (text.isEmpty) {
      setState(() {});
      return;
    }

    // 遍历原始数据过滤匹配项
    for (final item in _userDetails) {
      if (item.titleFalam.contains(text) || item.titleEnglish.contains(text)) {
        _searchResult.add(item);
      }
    }
    setState(() {}); // 更新UI
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _isLoading
          ? const Center(child: CircularProgressIndicator()) // 加载状态提示
          : Column(
              children: <Widget>[
                Container(
                  color: Colors.blue,
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Card(
                      child: ListTile(
                        leading: const Icon(Icons.search),
                        title: TextField(
                          controller: controller,
                          decoration: const InputDecoration(
                            hintText: 'Search',
                            border: InputBorder.none,
                          ),
                          onChanged: onSearchTextChanged,
                        ),
                        trailing: IconButton(
                          icon: const Icon(Icons.cancel),
                          onPressed: () {
                            controller.clear();
                            onSearchTextChanged('');
                          },
                        ),
                      ),
                    ),
                  ),
                ),
                Expanded(
                  child: controller.text.isNotEmpty
                      ? _searchResult.isNotEmpty
                          ? ListView.builder(
                              itemCount: _searchResult.length,
                              itemBuilder: (context, index) {
                                final item = _searchResult[index];
                                return Card(
                                  elevation: 5,
                                  margin: const EdgeInsets.symmetric(
                                    horizontal: 10,
                                    vertical: 6,
                                  ),
                                  child: InkWell(
                                    onTap: () {
                                      Navigator.push(
                                        context,
                                        MaterialPageRoute(
                                          builder: (context) =>
                                              DetailScreen(item.pageNumber),
                                        ),
                                      );
                                    },
                                    child: Container(
                                      padding: const EdgeInsets.only(bottom: 8),
                                      child: Column(
                                        mainAxisAlignment:
                                            MainAxisAlignment.center,
                                        crossAxisAlignment:
                                            CrossAxisAlignment.center,
                                        children: [
                                          Padding(
                                            padding: const EdgeInsets.all(8),
                                            child: Text(item.titleFalam),
                                          ),
                                          Padding(
                                            padding: const EdgeInsets.all(8),
                                            child: Text(item.titleEnglish),
                                          ),
                                        ],
                                      ),
                                    ),
                                  ),
                                );
                              },
                            )
                          : const Center(child: Text("No results found")) // 无结果提示
                      : ListView.builder(
                          itemCount: _userDetails.length,
                          itemBuilder: (context, index) {
                            final item = _userDetails[index];
                            return Card(
                              child: ListTile(
                                title: Text(item.titleFalam),
                                onTap: () {
                                  Navigator.push(
                                    context,
                                    MaterialPageRoute(
                                      builder: (context) =>
                                          DetailScreen(item.pageNumber),
                                    ),
                                  );
                                },
                              ),
                            );
                          },
                        ),
                ),
              ],
            ),
    );
  }
}

Future<List<SawnAwkModel>> ReadJsonData() async {
  final jsondata = await rootBundle.rootBundle.loadString('data/sawnawk_data.json');
  final list = json.decode(jsondata) as List<dynamic>;
  return list.map((e) => SawnAwkModel.fromJson(e)).toList();
}

关键修复说明

  1. 初始化数据:新增_loadJsonData方法,将JSON加载结果赋值给_userDetails并更新加载状态,避免重复加载。
  2. 修正搜索数据源:搜索结果ListView使用_searchResult作为数据源,并设置itemCount。
  3. 触发UI更新:在onSearchTextChanged中修改_searchResult后调用setState,确保UI刷新。
  4. 完善状态处理:添加加载状态提示和无搜索结果提示,提升用户体验。
  5. 优化代码结构:移除冗余的FutureBuilder,改用状态变量控制加载状态,避免不必要的重复调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:27:18