SwiftUI ForEach循环内指定Cell单独截图功能异常问题求助
SwiftUI ForEach循环中指定Cell截图解决方案
核心问题梳理
- 触发时序错误:点击截图按钮时立即清空了
menuIndex,导致PrintableCells中监听takePic变化的逻辑判断tap.menuIndex == index直接失效,截图代码未执行 - 截图逻辑错误:原有截图方法是重新生成View实例渲染,不是截取当前屏幕已展示的Cell区域,内容和实际显示不一致
- 视图层级错误:半透明遮罩写在ForEach循环内部,点击任意Cell会触发所有Cell生成遮罩,多层叠加导致显示异常
修正后完整可运行代码
import SwiftUI class ScreenShotViewModel: ObservableObject { @Published var openMenu: Bool = false @Published var menuIndex: Int? = nil @Published var takePic: Bool = false } struct Home: View { @StateObject private var tap = ScreenShotViewModel() var body: some View { ZStack { ScrollView { ForEach(1..<21) { index in PrintableCells(index: index) .environmentObject(tap) .onTapGesture { tap.openMenu.toggle() tap.menuIndex = index } } } // 遮罩和按钮移到外部,避免多层叠加 if tap.openMenu { Color.black.opacity(0.75) .ignoresSafeArea() .onTapGesture { tap.openMenu = false tap.menuIndex = nil } if let selectIndex = tap.menuIndex { ScreenShotButton(index: selectIndex) .environmentObject(tap) } } } } } struct PrintableCells: View { @EnvironmentObject var tap: ScreenShotViewModel let index: Int var body: some View { RoundedRectangle(cornerRadius: 20) .fill(Color.blue.opacity(0.5)) .frame(height: 200) .overlay( Text("ScreenShot: \(index)") .font(.title3) .fontWeight(.bold) ) .background( GeometryReader { proxy in Color.clear .onChange(of: tap.takePic) { newVal in guard newVal, tap.menuIndex == index else { return } // 截图当前屏幕对应Cell区域 let image = UIScreen.main.screenShot(in: proxy.frame(in: .global)) print("截取到第\(index)个Cell的截图:\(image)") // 截图完成后再清空状态 tap.takePic = false tap.openMenu = false tap.menuIndex = nil } } ) } } struct ScreenShotButton: View { @EnvironmentObject var tap: ScreenShotViewModel let index: Int var body: some View { ZStack { Button { // 只触发截图,状态清空放到截图完成后执行 tap.takePic.toggle() } label: { VStack { Image(systemName: "camera.viewfinder") Text("SnapShot Cell: \(index)") } } } .padding(15) .background(Color.gray.opacity(0.8)) .cornerRadius(15) .shadow(color: .green, radius: 10, x: 0, y: 0) } } // 新增屏幕指定区域截图方法 extension UIScreen { func screenShot(in rect: CGRect) -> UIImage { guard let window = UIApplication.shared.connectedScenes .filter({$0.activationState == .foregroundActive}) .compactMap({$0 as? UIWindowScene}) .first?.windows .first(where: \.isKeyWindow) else { return UIImage() } UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale) window.drawHierarchy(in: window.bounds, afterScreenUpdates: true) let fullImage = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage() UIGraphicsEndImageContext() // 裁剪指定区域 guard let cgImage = fullImage.cgImage?.cropping(to: rect) else { return UIImage() } return UIImage(cgImage: cgImage, scale: UIScreen.main.scale, orientation: fullImage.imageOrientation) } }
功能验证
点击任意Cell会弹出对应序号的截图按钮,点击按钮后会自动截取当前选中Cell的内容,控制台会打印截图对象,可直接按需存入系统相册或做其他业务处理。
内容的提问来源于stack exchange,提问作者Lian
相关产品推荐
相关产品推荐

