SwiftUI预览宏:如何为预览提供私有State属性lookAroundScene的值
SwiftUI预览中设置私有@State属性
lookAroundScene的方案 问题说明
Xcode 15起SwiftUI引入预览宏,我基于MapKit做了个简易应用,但不知道怎么给视图里的私有@State属性lookAroundScene赋值,希望预览能正常显示对应的场景图。以下是我的代码:
struct LocationDetailsView: View { @Binding var mapSelection: MKMapItem? @Binding var show: Bool @State private var lookAroundScene: MKLookAroundScene? @Binding var getDirections: Bool var body: some View { VStack { HStack { VStack(alignment: .leading) { Text(mapSelection?.placemark.name ?? "") .font(.title2) .fontWeight(.semibold) Text(mapSelection?.placemark.title ?? "") .font(.footnote) .foregroundStyle(.gray) .lineLimit(2) .padding(.trailing) } Spacer() Button { show.toggle() mapSelection = nil } label: { Image(systemName: "xmark.circle.fill") .resizable() .frame(width: 24, height: 24) .foregroundStyle(.gray, Color(.systemGray5)) } } .padding(.init(top: 40, leading: 20, bottom: 0, trailing: 20)) if let scene = lookAroundScene { LookAroundPreview(initialScene: scene) .frame(height: 200) .cornerRadius(12) .padding() } else { ContentUnavailableView("No preview available", systemImage: "eye.slash") } HStack(spacing: 24) { Button { if let mapSelection { mapSelection.openInMaps() } } label: { Text("Open in Maps") .font(.headline) .foregroundColor(.white) .frame(width: 170, height: 48) .background(.green) .cornerRadius(12) } Button { getDirections = true show = false } label: { Text("Get Directions") .font(.headline) .foregroundColor(.white) .frame(width: 170, height: 48) .background(.blue) .cornerRadius(12) } } .padding(.horizontal) } .onAppear { print("DEBUG: Did call on appear") fetchLookAroundPreview() } .onChange(of: mapSelection) { oldValue, newValue in print("DEBUG: Did call on change") fetchLookAroundPreview() } .padding() } } extension LocationDetailsView { func fetchLookAroundPreview() { if let mapSelection { lookAroundScene = nil Task { let request = MKLookAroundSceneRequest(mapItem: mapSelection) lookAroundScene = try? await request.scene print("DEBUG: lookAroundScene \(lookAroundScene)") } } } } #Preview { LocationDetailsView( mapSelection: .constant(MKMapItem.forCurrentLocation()), show: .constant(true) , getDirections: .constant(false) ) }
解决建议
1. 添加预览专用初始化器
因为lookAroundScene是私有@State,外部无法直接修改,给视图添加一个仅在Debug模式下生效的初始化器,用于预览时传入场景值:
在LocationDetailsView结构体中添加:
#if DEBUG init(mapSelection: Binding<MKMapItem?>, show: Binding<Bool>, getDirections: Binding<Bool>, previewScene: MKLookAroundScene?) { self._mapSelection = mapSelection self._show = show self._getDirections = getDirections self._lookAroundScene = State(initialValue: previewScene) } #endif
2. 优化预览代码
原预览用MKMapItem.forCurrentLocation()可能无法在预览环境获取有效位置,建议替换为固定测试地点,同时通过包装视图异步加载场景:
#Preview { struct PreviewContainer: View { @State private var previewScene: MKLookAroundScene? // 使用北京天安门坐标作为测试地点,确保能获取到LookAround场景 private let testMapItem = MKMapItem(placemark: MKPlacemark(coordinate: CLLocationCoordinate2D(latitude: 39.9042, longitude: 116.4074))) var body: some View { if let scene = previewScene { LocationDetailsView( mapSelection: .constant(testMapItem), show: .constant(true), getDirections: .constant(false), previewScene: scene ) } else { ProgressView() .onAppear { Task { let request = MKLookAroundSceneRequest(mapItem: testMapItem) previewScene = try? await request.scene } } } } } return PreviewContainer() }
3. 临时调整权限(不推荐)
如果只是临时测试,可以暂时去掉lookAroundScene的private修饰符,直接在预览中通过$lookAroundScene绑定赋值,但测试完成后记得恢复私有权限,避免破坏封装性。
效果展示
根据上述方案修改后,预览可以正常显示场景图:
内容的提问来源于stack exchange,提问作者Zhou Haibo
相关产品推荐
相关产品推荐

