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

带分区的UITableView基于标题数组实现搜索栏是否可行?

当然可行!我来帮你实现这个搜索功能

你当前把每个字母分区的数据存在单独数组里的写法,确实会给搜索带来一些麻烦,但通过数据模型化和搜索状态管理就能轻松解决。下面是一步步的实现方案:


第一步:重构数据结构,用模型统一管理

先把分散的titoliA、artistaA这类数组,换成一个更易维护的结构体和分组数据源:

// 定义歌曲模型,把标题和艺术家绑定在一起
struct Song {
    let title: String
    let artist: String
}

// 替换原来所有分散的数组,改成「分区标题+对应歌曲列表」的统一结构
let groupedSongs: [(sectionTitle: String, songs: [Song])] = [
    ("A", [Song(title: "A标题1", artist: "A艺术家1"), Song(title: "A标题2", artist: "A艺术家2")]),
    ("B", [Song(title: "B标题1", artist: "B艺术家1")]),
    // 这里补充你剩下的18个分区的数据...
    ("Z", [Song(title: "Z标题1", artist: "Z艺术家1")])
]

// 用于存储搜索过滤后的结果,初始和原数据一致
var filteredGroupedSongs: [(sectionTitle: String, songs: [Song])] = []

这种结构能让我们统一处理所有分区的数据,不用再写一大堆switch case。


第二步:配置搜索控制器,实现搜索逻辑

让你的ViewController遵循UISearchResultsUpdating协议,然后在viewDidLoad里完成搜索控制器的配置:

class TableViewController: UITableViewController, UISearchResultsUpdating {
    
    // ... 保留你原有的其他属性 ...
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 初始化过滤数据源
        filteredGroupedSongs = groupedSongs
        
        // 配置搜索控制器
        searchController.searchResultsUpdater = self
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.placeholder = "搜索歌曲标题"
        navigationItem.searchController = searchController
        definesPresentationContext = true
    }
    
    // 搜索文本变化时自动触发的方法
    func updateSearchResults(for searchController: UISearchController) {
        guard let searchText = searchController.searchBar.text?.lowercased(), !searchText.isEmpty else {
            // 搜索框为空时,恢复显示全部数据
            filteredGroupedSongs = groupedSongs
            tableView.reloadData()
            return
        }
        
        // 1. 把所有分区的歌曲合并成一个数组
        let allSongs = groupedSongs.flatMap { $0.songs }
        // 2. 过滤出标题包含搜索文本的歌曲(忽略大小写)
        let filteredSongs = allSongs.filter { $0.title.lowercased().contains(searchText) }
        
        // 3. 把过滤后的歌曲重新按首字母分组(和原结构保持一致)
        let groupedFiltered = Dictionary(grouping: filteredSongs) { song -> String in
            String(song.title.prefix(1)).uppercased()
        }
        // 4. 转换成有序数组,保持字母顺序
        filteredGroupedSongs = groupedFiltered.sorted { $0.key < $1.key }.map { ($0.key, $0.value) }
        
        // 更新表格
        tableView.reloadData()
    }
    
    // ... 其他方法 ...
}

如果不想在搜索结果里保留分区结构,直接显示所有匹配的歌曲,你可以把filteredGroupedSongs改成[Song]类型,然后调整后续的数据源方法即可。


第三步:修改表格数据源,适配搜索状态

现在所有数据都通过filteredGroupedSongs来提供,原来的switch case可以全部替换:

override func numberOfSections(in tableView: UITableView) -> Int {
    return filteredGroupedSongs.count
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return filteredGroupedSongs[section].sectionTitle
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return filteredGroupedSongs[section].songs.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cellaCustom") as! Cella
    let song = filteredGroupedSongs[indexPath.section].songs[indexPath.row]
    cell.lbl_titolo.text = song.title
    cell.lbl_artista.text = song.artist
    return cell
}

第四步:调整跳转逻辑,适配搜索状态

原来的分区和行索引在搜索状态下会失效,建议直接传递选中的Song对象:

首先在TextView_Controller里添加接收属性:

class TextView_Controller: UIViewController {
    var receivedSong: Song?
    // ... 保留你原有的其他属性 ...
}

然后修改跳转相关的方法:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let selectedSong = filteredGroupedSongs[indexPath.section].songs[indexPath.row]
    performSegue(withIdentifier: "segue_testo", sender: selectedSong)
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "segue_testo" {
        let secondVC = segue.destination as! TextView_Controller
        secondVC.receivedSong = sender as? Song
        
        // 如果仍需要原分区和行的索引,可以遍历原数据查找:
        // if let song = sender as? Song {
        //     for (sectionIndex, group) in groupedSongs.enumerated() {
        //         if let rowIndex = group.songs.firstIndex(where: { $0.title == song.title && $0.artist == song.artist }) {
        //             secondVC.recivedCategoria = sectionIndex
        //             secondVC.recivedRow = rowIndex
        //             break
        //         }
        //     }
        // }
    }
}

这样不管是正常状态还是搜索状态,都能正确传递选中的歌曲信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:08:07