SwiftUI中如何将父视图onHover事件传递给子视图?
解决SwiftUI中父视图Hover事件传递给子视图的问题
问题场景
我有两个独立视图(Checkbox和Card),各自带有onHover监听器。当Card内部包含Checkbox时,希望父视图的hover事件能传递给子视图——目前只有直接悬停在Checkbox上时,它的hover事件才会触发。同时不想使用Binding,因为Checkbox作为独立视图使用时不需要绑定值。
原代码如下:
struct Checkbox: View { @State private var isHovered = false var body: some View { Circle() .background(isHovered ? .red : .blue) .onHover { isHovered in self.isHovered = isHovered } } } struct Card: View { @State private var isHovered = false var body: some View { HStack { Text("Label") Checkbox() } .onHover(perform: { isHovered in self.isHovered = isHovered }) .background(isHovered ? .red : .blue) } }
解决方案一:可选参数传递状态
给Checkbox添加一个可选的外部hover状态参数,默认使用自身的@State变量,兼顾独立使用和被包含时的需求:
struct Checkbox: View { // 可选外部hover状态,默认nil时使用内部状态 var externalHovered: Bool? = nil @State private var internalHovered = false // 合并内部与外部的hover状态 private var isHovered: Bool { externalHovered ?? internalHovered } var body: some View { Circle() .background(isHovered ? .red : .blue) .onHover { isHovered in internalHovered = isHovered } } } struct Card: View { @State private var isHovered = false var body: some View { HStack { Text("Label") // 将父视图的hover状态传递给子视图 Checkbox(externalHovered: isHovered) } .onHover(perform: { isHovered in self.isHovered = isHovered }) .background(isHovered ? .red : .blue) } }
说明
Checkbox独立使用时,externalHovered保持默认nil,完全依赖自身的internalHovered状态,无需额外配置。- 被
Card包含时,传递父视图的isHovered状态,实现父视图hover时子视图同步响应。
解决方案二:环境变量传递(适合复杂层级)
如果视图层级较深,使用环境变量可以避免逐个传递参数的繁琐:
// 自定义环境键 private struct ParentHoveredKey: EnvironmentKey { static let defaultValue: Bool = false } // 扩展环境值,添加父视图hover状态属性 extension EnvironmentValues { var parentHovered: Bool { get { self[ParentHoveredKey.self] } set { self[ParentHoveredKey.self] = newValue } } } struct Checkbox: View { @State private var internalHovered = false // 读取环境中的父视图hover状态 @Environment(\.parentHovered) private var parentHovered private var isHovered: Bool { parentHovered || internalHovered } var body: some View { Circle() .background(isHovered ? .red : .blue) .onHover { isHovered in internalHovered = isHovered } } } struct Card: View { @State private var isHovered = false var body: some View { HStack { Text("Label") Checkbox() } .onHover(perform: { isHovered in self.isHovered = isHovered }) .background(isHovered ? .red : .blue) // 设置环境中的父视图hover状态 .environment(\.parentHovered, isHovered) } }
说明
- 通过自定义环境键,
Card将自身的hover状态注入环境,所有子视图都可以读取该状态。 Checkbox合并自身内部hover状态与环境中的父视图状态,实现同步响应。
内容的提问来源于stack exchange,提问作者JaSHin
相关产品推荐
相关产品推荐

