如何在visionOS中自定义悬停效果区域
自定义SwiftUI按钮的悬停效果区域
在WWDC23的《为空间用户界面设计》视频约13:00处,Apple指出设计lock-up组件时需定义自定义区域以显示悬停效果,帮助用户识别完整交互元素,并保持组件间间距。参考Music App示例,我在应用中用LazyVGrid展示Button,已采用.plain按钮样式隐藏边框背景并保留悬停效果,但当前悬停效果为椭圆形,希望改为带额外内边距的圆角矩形,且悬停效果间保持4pt间距。尝试使用.contentShape(.hoverEffect, .rect(cornerRadius: 50).inset(by: -10))未生效,相关代码如下:
Button(action: tapAction) { VStack { Color.clear .background(.regularMaterial) .aspectRatio(1, contentMode: .fit) .clipShape(.rect(cornerRadius: 10)) HStack(spacing: 0) { VStack(alignment: .leading, spacing: 0) { Text("Line one") Text("Line two") .foregroundStyle(.secondary) } Spacer() MarkWateredButton(action: markWateredAction) } } .contentShape(.hoverEffect, .rect(cornerRadius: 50).inset(by: -10)) // FIXME: Doesn't do anything } .buttonStyle(.plain)
解决方案
问题核心是.contentShape的作用层级和参数设置错误,调整以下几点即可实现需求:
- 调整
.contentShape的绑定层级:将.contentShape从内部VStack移到Button本身,因为Button是交互触发容器,悬停效果的区域需要绑定到整个Button组件。 - 修正形状参数:使用合适的圆角值(比如和内部视图一致的
10),通过负数inset扩展悬停区域的内边距,数值可根据UI需求调整。 - 设置LazyVGrid间距:在LazyVGrid的
GridItem和容器本身设置spacing: 4,确保组件间悬停效果保持4pt间距。
修改后的完整代码示例:
// 配置LazyVGrid的间距 LazyVGrid(columns: [GridItem(.flexible(), spacing: 4)], spacing: 4) { Button(action: tapAction) { VStack { Color.clear .background(.regularMaterial) .aspectRatio(1, contentMode: .fit) .clipShape(.rect(cornerRadius: 10)) HStack(spacing: 0) { VStack(alignment: .leading, spacing: 0) { Text("Line one") Text("Line two") .foregroundStyle(.secondary) } Spacer() MarkWateredButton(action: markWateredAction) } } } .buttonStyle(.plain) .contentShape(.hoverEffect, .rect(cornerRadius: 10).inset(by: -8)) // 绑定到Button层级 }
补充说明
- 若需要更精细的区域控制,可以自定义
Shape类型,或者结合.padding与基础形状来定义悬停范围。 - 悬停效果的圆角值可根据设计需求自由调整,无需和内部视图圆角完全一致。
内容的提问来源于stack exchange,提问作者Jordan H
相关产品推荐
相关产品推荐

