SwiftUI时区选择组件单选异常:如何实现单个元素勾选
问题:点击任意时区项时,所有项的收藏状态同时切换
原代码实现
主视图结构
struct TimeZoneView: View { @State private var favorite = false @State private var timezone: String = "" private var timeZoneIdentifiers = TimeZone.knownTimeZoneIdentifiers var body: some View { ZStack { Color.white .ignoresSafeArea() ScrollView(showsIndicators: false, content: { VStack(spacing: 25) { selection Spacer() } }) } } }
视图组件函数
func createSelection( title: String, clicked: (() -> Void)?, favorite: Bool ) -> some View { VStack { Button(action: { clicked?() }, label: { VStack(spacing: 10) { VStack { HStack { Text(title) .font(.custom(.semiBold, size: 16)) .foregroundColor(.theme.appBlack) Spacer() if favorite { Image.app.addPurple .resizable() .frame(width: 16,height: 16) } } .padding(20) } .overlay( RoundedRectangle(cornerRadius: 10) .stroke(Color.theme.grayProfileText, lineWidth: 0.5) ) .padding([.leading,.trailing], 20) } }) } }
列表遍历视图
var selection: some View { VStack(spacing: 10) { ForEach(timeZoneIdentifiers, id: \.self) { zone in let temp = zone.components(separatedBy: "/") if temp.count >= 2 { let cityName = temp[1].replacingOccurrences(of: "_", with: " ") createSelection(title: zone, clicked: { timezone = cityName favorite.toggle() }, favorite: favorite) } } } }
问题现象
点击任意时区项时,所有项的收藏图标都会同步切换,无法单独标记某一个时区为收藏状态。
问题原因
当前使用单个@State private var favorite = false变量控制所有时区项的收藏状态,所有列表项都绑定同一个布尔值,因此点击任意项触发favorite.toggle()时,所有项的favorite参数都会同步变化。
解决方案
需要为每个时区单独维护收藏状态,改用**Set
修改后的完整代码
struct TimeZoneView: View { // 用Set存储已收藏的时区ID,每个时区独立管理状态 @State private var favoriteTimeZones: Set<String> = [] @State private var timezone: String = "" private var timeZoneIdentifiers = TimeZone.knownTimeZoneIdentifiers var body: some View { ZStack { Color.white .ignoresSafeArea() ScrollView(showsIndicators: false, content: { VStack(spacing: 25) { selection Spacer() } }) } } func createSelection( title: String, timezoneId: String, clicked: (() -> Void)?, isFavorite: Bool ) -> some View { VStack { Button(action: { clicked?() // 切换当前时区的收藏状态 if isFavorite { favoriteTimeZones.remove(timezoneId) } else { favoriteTimeZones.insert(timezoneId) } }, label: { VStack(spacing: 10) { VStack { HStack { Text(title) .font(.custom(.semiBold, size: 16)) .foregroundColor(.theme.appBlack) Spacer() if isFavorite { Image.app.addPurple .resizable() .frame(width: 16,height: 16) } } .padding(20) } .overlay( RoundedRectangle(cornerRadius: 10) .stroke(Color.theme.grayProfileText, lineWidth: 0.5) ) .padding([.leading,.trailing], 20) } }) } } var selection: some View { VStack(spacing: 10) { ForEach(timeZoneIdentifiers, id: \.self) { zone in let temp = zone.components(separatedBy: "/") if temp.count >= 2 { let cityName = temp[1].replacingOccurrences(of: "_", with: " ") // 检查当前时区是否在收藏Set中 let isFavorite = favoriteTimeZones.contains(zone) createSelection(title: zone, timezoneId: zone, clicked: { timezone = cityName }, isFavorite: isFavorite) } } } } }
关键修改点
- 将单个
favorite布尔变量替换为favoriteTimeZones: Set<String>,存储所有已收藏的时区ID - 在
createSelection中新增timezoneId参数,用于标识当前操作的时区 - 点击按钮时,根据当前时区是否在收藏Set中,执行添加/移除操作
- 每个列表项的收藏状态通过
favoriteTimeZones.contains(zone)单独判断,实现独立控制
内容的提问来源于stack exchange,提问作者Oleksandr
相关产品推荐
相关产品推荐

