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

Flutter:如何在CustomSearchDelegate中访问Song类的songTitle变量?

解决Flutter搜索栏无法访问Song类songTitle的问题

你遇到的核心问题是将List<Widget>传入搜索代理后,编译器仅能识别元素为通用Widget类型,而Widget类并没有songTitle属性。你把歌曲数据和UI组件绑定在一起,导致搜索逻辑无法直接访问数据字段。

解决方案:分离数据模型与UI组件

正确的做法是将歌曲数据与展示它的Widget解耦,让搜索逻辑只处理纯数据,UI组件负责渲染。

1. 创建独立的歌曲数据模型

定义一个纯数据类存储歌曲信息,与UI完全分离:

class SongData {
  final String songTitle;
  const SongData({required this.songTitle});
}

2. 修改Recordings中的歌曲列表

将原来的List<Widget>替换为List<SongData>,存储纯数据:

class Recordings extends StatelessWidget {
  Recordings({Key? key, required this.title}) : super(key: key);
  final String title;
  // 存储纯数据而非Widget
  final List<SongData> songs = [
    const SongData(songTitle: "September"),
    const SongData(songTitle: "Don't Stop Me Now"),
    const SongData(songTitle: "Let It Go"),
    const SongData(songTitle: "Smoke on the Water"),
    const SongData(songTitle: "Don't Kill My Vibe"),
    const SongData(songTitle: "Mamma Mia"),
    const SongData(songTitle: "4'33"),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
        actions: [
          IconButton(
              onPressed: () {
                // 传入数据列表而非Widget列表
                showSearch(context: context, delegate: CustomSearchDelegate(searchTerms: songs));
              },
              icon: const Icon(Icons.search)),
        ],
      ),
      body: Container(
        color: Colors.grey[600],
        child: Center(
          child: ListView(
            // 将数据转换为对应的UI组件
            children: songs.map((songData) => Song(songData: songData)).toList(),
          ),
        ),
      ),
    );
  }
}

3. 更新Song Widget以接收数据模型

让Song Widget接收SongData对象,从数据中提取标题:

class Song extends StatelessWidget {
  const Song({Key? key, required this.songData}) : super(key: key);
  final SongData songData;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(10),
      child: Container(
        alignment: Alignment.center,
        color: Colors.lightBlue[300],
        child: Text(
          songData.songTitle,
          style: const TextStyle(color: Colors.black),
        ),
      ),
    );
  }
}

4. 修改CustomSearchDelegate处理数据模型

现在搜索代理接收List<SongData>,可直接访问songTitle属性:

class CustomSearchDelegate extends SearchDelegate {
  CustomSearchDelegate({required this.searchTerms});
  final List<SongData> searchTerms;

  @override
  List<Widget> buildActions(BuildContext context) {
    return [
      IconButton(
        onPressed: () {
          query = "";
        },
        icon: const Icon(Icons.clear),
      ),
    ];
  }

  @override
  Widget buildLeading(BuildContext context) {
    return IconButton(
      onPressed: () {
        close(context, null);
      },
      icon: const Icon(Icons.arrow_back),
    );
  }

  @override
  Widget buildResults(BuildContext context) {
    List<SongData> matchQuery = [];
    for (var song in searchTerms) {
      // 直接访问songTitle进行搜索匹配
      if (song.songTitle.toLowerCase().contains(query.toLowerCase())) {
        matchQuery.add(song);
      }
    }
    return ListView.builder(
      itemCount: matchQuery.length,
      itemBuilder: ((context, index) {
        var result = matchQuery[index];
        // 使用Song Widget渲染搜索结果
        return Song(songData: result);
      }),
    );
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    List<SongData> matchQuery = [];
    for (var song in searchTerms) {
      if (song.songTitle.toLowerCase().contains(query.toLowerCase())) {
        matchQuery.add(song);
      }
    }
    return ListView.builder(
      itemCount: matchQuery.length,
      itemBuilder: ((context, index) {
        var result = matchQuery[index];
        return Song(songData: result);
      }),
    );
  }
}

额外优化建议

  • 若后续从数据库获取数据,可直接扩展SongData添加歌手名、时长等属性,无需修改UI组件
  • 提取重复的搜索匹配逻辑为单独方法,减少代码冗余:
List<SongData> _getMatchingSongs() {
  return searchTerms.where((song) => 
    song.songTitle.toLowerCase().contains(query.toLowerCase())
  ).toList();
}

之后在buildResults和buildSuggestions中直接调用该方法即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:10:03