From 2d4c80e08488174ebcfff5d8526e923530b16319 Mon Sep 17 00:00:00 2001 From: mh <729263080@qq.com> Date: Thu, 6 Nov 2025 15:53:46 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=92=E8=89=B2=E8=AE=BE=E7=BD=AE=E5=A4=84?= =?UTF-8?q?=E7=90=86sound=E4=B8=AD=E7=9A=84=E6=95=B0=E6=8D=AE=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E4=BF=9D=E5=AD=98=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Cell/VoiceActorContainerCell.swift | 39 ++++++++-- .../Setting/View/ChatSettingSwipeView.swift | 71 +++++++++++++++++-- 2 files changed, 97 insertions(+), 13 deletions(-) diff --git a/Visual_Novel_iOS/Src/Modules/Chat/Setting/Cell/VoiceActorContainerCell.swift b/Visual_Novel_iOS/Src/Modules/Chat/Setting/Cell/VoiceActorContainerCell.swift index 53e2f12..92b6199 100644 --- a/Visual_Novel_iOS/Src/Modules/Chat/Setting/Cell/VoiceActorContainerCell.swift +++ b/Visual_Novel_iOS/Src/Modules/Chat/Setting/Cell/VoiceActorContainerCell.swift @@ -39,13 +39,19 @@ class VoiceActorContainerCell: UITableViewCell, CellConfigurable { private var filteredItems: [VoiceActorItem] = [] private var selectedItemId: String? private var tableViewHeightConstraint: Constraint? + private var currentFilterType: VoiceActorFilterView.FilterType = .all var selectedItemChanged: ((VoiceActorItem) -> Void)? // 选中项改变回调 + var filterTypeChanged: ((VoiceActorFilterView.FilterType) -> Void)? // 筛选器改变回调 // MARK: - 筛选器视图 private lazy var filterView: VoiceActorFilterView = { let view = VoiceActorFilterView() view.filterChanged = { [weak self] filterType in - self?.filterItems(by: filterType) + guard let self = self else { return } + self.currentFilterType = filterType + self.filterItems(by: filterType) + // 通知外部筛选器改变 + self.filterTypeChanged?(filterType) } return view }() @@ -89,7 +95,7 @@ class VoiceActorContainerCell: UITableViewCell, CellConfigurable { filterView.snp.makeConstraints { make in make.left.right.equalToSuperview().inset(20) make.top.equalToSuperview().offset(2.5) - make.height.equalTo(50) + make.height.equalTo(50).priority(.required) // 确保高度固定,不会被压缩 } tableView.snp.makeConstraints { make in @@ -109,7 +115,24 @@ class VoiceActorContainerCell: UITableViewCell, CellConfigurable { selectedItemId = selected.id } - filterItems(by: .all) + // 使用当前筛选器状态(默认为 .all) + // 注意:这里不设置 filterView,因为状态会在 restoreFilterType 中恢复 + filterItems(by: currentFilterType) + } + + // 恢复筛选器类型(用于恢复状态) + func restoreFilterType(_ filterType: VoiceActorFilterView.FilterType) { + currentFilterType = filterType + // 先设置筛选器视图的状态,确保 UI 正确 + filterView.selectedFilter = filterType + filterView.updateButtonStates() + // 然后筛选 items + filterItems(by: filterType) + } + + // 获取当前筛选器类型 + func getCurrentFilterType() -> VoiceActorFilterView.FilterType { + return currentFilterType } private func filterItems(by filterType: VoiceActorFilterView.FilterType) { @@ -138,7 +161,7 @@ class VoiceActorContainerCell: UITableViewCell, CellConfigurable { private func updateTableViewHeight() { let rowHeight: CGFloat = 80 let maxRows: CGFloat = 5.5 - let displayCount = min(CGFloat(filteredItems.count), maxRows) + let displayCount = min(CGFloat(allItems.count), maxRows) let height = displayCount * rowHeight tableViewHeightConstraint?.update(offset: height) @@ -176,8 +199,10 @@ extension VoiceActorContainerCell: UITableViewDataSource, UITableViewDelegate { tableView.reloadData() - // 通知外部选中项改变 - selectedItemChanged?(item) + // 通知外部选中项改变(传递完整的 item,包含更新后的选中状态) + if let updatedItem = allItems.first(where: { $0.id == item.id }) { + selectedItemChanged?(updatedItem) + } } // func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) { @@ -333,7 +358,7 @@ class VoiceActorFilterView: UIView { filterChanged?(selectedFilter) } - private func updateButtonStates() { + func updateButtonStates() { let buttons = [allButton, maleButton, femaleButton] let filters: [FilterType] = [.all, .male, .female] diff --git a/Visual_Novel_iOS/Src/Modules/Chat/Setting/View/ChatSettingSwipeView.swift b/Visual_Novel_iOS/Src/Modules/Chat/Setting/View/ChatSettingSwipeView.swift index 4b99f70..3ce98ea 100644 --- a/Visual_Novel_iOS/Src/Modules/Chat/Setting/View/ChatSettingSwipeView.swift +++ b/Visual_Novel_iOS/Src/Modules/Chat/Setting/View/ChatSettingSwipeView.swift @@ -18,6 +18,9 @@ class ChatSettingSwipeView: CLContainer { // 展开状态管理:section -> rowIndex -> isExpanded private var expandedStates: [Int: [Int: Bool]] = [:] + // Voice Actor 状态管理:section -> rowIndex -> (items, filterType) + private var voiceActorStates: [Int: [Int: (items: [VoiceActorItem], filterType: VoiceActorFilterView.FilterType)]] = [:] + override init(frame: CGRect) { super.init(frame: frame) @@ -203,17 +206,43 @@ extension ChatSettingSwipeView: UITableViewDelegate, UITableViewDataSource { expandedStates[indexPath.section, default: [:]][indexPath.row] = !isExpanded if !isExpanded { - // 展开:插入 VoiceActorRow - let actorRow = VoiceActorRow(items: voiceActorItems) + // 展开:使用保存的状态(如果有),否则使用原始状态 + let savedState = voiceActorStates[indexPath.section]?[indexPath.row] + let itemsToUse = savedState?.items ?? voiceActorItems + let filterTypeToUse = savedState?.filterType ?? .all + + // 如果没有保存的状态,初始化保存状态 + if savedState == nil { + voiceActorStates[indexPath.section, default: [:]][indexPath.row] = (items: voiceActorItems, filterType: .all) + } + + let actorRow = VoiceActorRow(items: itemsToUse) rows[indexPath.section].insert(actorRow, at: indexPath.row + 1) let insertIndexPath = IndexPath(row: indexPath.row + 1, section: indexPath.section) tableView.performBatchUpdates({ tableView.insertRows(at: [insertIndexPath], with: .fade) tableView.reloadRows(at: [indexPath], with: .none) - }, completion: nil) + }, completion: { [weak self] _ in + // 在 cell 完全布局后,设置筛选器状态 + DispatchQueue.main.async { + if let cell = self?.tableView.cellForRow(at: insertIndexPath) as? VoiceActorContainerCell { + cell.restoreFilterType(filterTypeToUse) + } + } + }) } else { - // 折叠 + // 折叠:保存当前状态 + if indexPath.row + 1 < rows[indexPath.section].count, + let actorRow = rows[indexPath.section][indexPath.row + 1] as? VoiceActorRow, + let cell = tableView.cellForRow(at: IndexPath(row: indexPath.row + 1, section: indexPath.section)) as? VoiceActorContainerCell { + // 获取当前筛选器状态 + let currentFilterType = cell.getCurrentFilterType() + // 保存状态 + voiceActorStates[indexPath.section, default: [:]][indexPath.row] = (items: actorRow.items, filterType: currentFilterType) + } + + // 删除行 if indexPath.row + 1 < rows[indexPath.section].count, rows[indexPath.section][indexPath.row + 1] is VoiceActorRow { rows[indexPath.section].remove(at: indexPath.row + 1) @@ -347,9 +376,33 @@ extension ChatSettingSwipeView: UITableViewDelegate, UITableViewDataSource { let cell = tableView.dequeueReusableCell(withIdentifier: "VoiceActorContainerCell", for: indexPath) as! VoiceActorContainerCell cell.selectionStyle = .none - // 设置选中回调,更新父cell头像 + // 设置选中回调,更新父cell头像和保存状态 cell.selectedItemChanged = { [weak self] item in - self?.updateVoiceActorAvatar(item, at: indexPath.section, rowIndex: indexPath.row - 1) + guard let self = self else { return } + self.updateVoiceActorAvatar(item, at: indexPath.section, rowIndex: indexPath.row - 1) + // 更新保存的状态 + if var savedState = self.voiceActorStates[indexPath.section]?[indexPath.row - 1] { + savedState.items = savedState.items.map { var i = $0; i.isSelected = (i.id == item.id); return i } + self.voiceActorStates[indexPath.section]?[indexPath.row - 1] = savedState + } + // 同时更新当前 VoiceActorRow 的 items + if var actorRow = self.rows[indexPath.section][indexPath.row] as? VoiceActorRow { + actorRow = VoiceActorRow(items: actorRow.items.map { var i = $0; i.isSelected = (i.id == item.id); return i }) + self.rows[indexPath.section][indexPath.row] = actorRow + } + } + + // 设置筛选器改变回调,保存筛选器状态 + cell.filterTypeChanged = { [weak self] filterType in + guard let self = self else { return } + // 获取当前的 VoiceActorRow items + if let actorRow = self.rows[indexPath.section][indexPath.row] as? VoiceActorRow { + // 更新或创建保存的状态 + var savedState = self.voiceActorStates[indexPath.section]?[indexPath.row - 1] ?? (items: actorRow.items, filterType: .all) + savedState.filterType = filterType + savedState.items = actorRow.items // 确保 items 是最新的 + self.voiceActorStates[indexPath.section, default: [:]][indexPath.row - 1] = savedState + } } cell.configure(with: actorRow) @@ -467,6 +520,12 @@ extension ChatSettingSwipeView: UITableViewDelegate, UITableViewDataSource { voiceActorItems: voiceActorItems ) rows[section][rowIndex] = updatedRow + + // 同时更新保存的状态 + if var savedState = voiceActorStates[section]?[rowIndex] { + savedState.items = voiceActorItems + voiceActorStates[section]?[rowIndex] = savedState + } } // 刷新父cell以更新头像