带分区的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
相关产品推荐
相关产品推荐

