简体   繁体   English

SwiftUI LazyVStack 重叠图像

[英]SwiftUI LazyVStack overlapping images

I am trying to display two columns of images in a LazyVStack embedded in a scroll view however the the second row of images partially overlaps the row above.我试图在嵌入在滚动视图中的 LazyVStack 中显示两列图像,但是第二行图像与上面的行部分重叠。 I'm not sure if this is an issue with the LazyVStack itself or an issue with the Photo.swift view.我不确定这是 LazyVStack 本身的问题还是 Photo.swift 视图的问题。

The output looks like this输出看起来像这样在此处输入图片说明 在此处输入图片说明

The two view files两个视图文件

ContentView.swift内容视图.swift

struct ContentView: View {
    @State private var image: Image?
    @State private var showingCustomCamera = false
    @State private var inputImage: UIImage?
    @State private var photos: [UIImage] = []
    
    func addImageToArray() {
        guard let inputImage = inputImage else { return }
        image = Image(uiImage: inputImage)
        
        let ciImage = CIImage(cgImage: inputImage.cgImage!)

        let options = [CIDetectorAccuracy: CIDetectorAccuracyHigh]
        let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: options)!

        let faces = faceDetector.features(in: ciImage)

        if let face = faces.first as? CIFaceFeature {
            print("Found face at \(face.bounds)")

            print(face.faceAngle)
            print(face.hasSmile)
            print(face.leftEyeClosed)
            print(face.rightEyeClosed)
            
            if face.leftEyeClosed {
                print("Left Eye Closed \(face.leftEyePosition)")
            }

            if face.rightEyeClosed {
                print("Right Eye Closed \(face.rightEyePosition)")
            }

            if face.hasSmile {
                print("Person is smiling \(face.mouthPosition)")
            }
        }
        
        photos.append(inputImage)
    }
    
    let columns = [
        GridItem(.flexible(), spacing: 20),
        GridItem(.flexible(), spacing: 20)
    ]
    
    var body: some View {
        NavigationView {
            VStack{
                ScrollView {
                    LazyVGrid(columns: columns, spacing: 20) {
                        AddPhoto(showCamera: $showingCustomCamera)
                        
                        ForEach(photos, id: \.self) { photo in
                            PassportPhoto(img: photo)
                        }
                    }
                    .padding()
                }
                
                HStack {
                    Button(action: {
                        //
                    }, label: {
                        Image(systemName: "printer.fill.and.paper.fill")
                        Text("Print")
                    })
                    .padding()
                    .foregroundColor(.primary)
                    
                    Button(action: {
                        //
                    }, label: {
                        Image(systemName: "externaldrive.fill.badge.icloud")
                        Text("Digital Upload")
                    })
                    .padding()
                    .foregroundColor(.primary)
                }
            }
            .sheet(isPresented: $showingCustomCamera, onDismiss: addImageToArray) {
                CustomCameraView(image: self.$inputImage)
            }
            .navigationTitle("Add Photos")
        }
    }
}

Photo.swift Photo.swift

struct Photo: View {
    var img: UIImage
    @State private var overlay: Bool = false
    
    var body: some View {
        GeometryReader { geometry in
            VStack {
                ZStack(alignment: .top) {
                    Image(uiImage: img)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(width: geometry.size.width, height: geometry.size.width * 1.29, alignment: .top)
                        .clipped()
                        .cornerRadius(10)
                        .onTapGesture {
                            self.overlay.toggle()
                        }
                    
                    if overlay {
                        Template()
                    }
                }
            }
        }
    }
}

Anyone have any idea?任何人有任何想法? I feel like I'm missing something obvious.我觉得我错过了一些明显的东西。

CustomCameraView.swift (as requested) CustomCameraView.swift(根据要求)

import SwiftUI
import AVFoundation
 
struct CustomCameraView: View {
    @Binding var image: UIImage?
    @State var didTapCapture: Bool = false
    @Environment(\.presentationMode) var presentationMode
    
    var body: some View {
        VStack(alignment: .center) {
            CustomCameraRepresentable(image: self.$image, didTapCapture: $didTapCapture)
                .overlay(Template(),alignment: .center)
                .overlay(
                    CaptureButtonView().onTapGesture {
                        self.didTapCapture = true
                    }
                    , alignment: .bottom)
                .overlay(
                    Button(action: {
                        presentationMode.wrappedValue.dismiss()
                    }, label: {
                        Image(systemName: "multiply")
                            .scaleEffect(2)
                            .padding(20)
                            .onTapGesture {
                                presentationMode.wrappedValue.dismiss()
                            }
                    })
                    .foregroundColor(.white)
                    .padding()
                    , alignment: .topTrailing)
        }
    }
    
}


struct CustomCameraRepresentable: UIViewControllerRepresentable {
    
    @Environment(\.presentationMode) var presentationMode
    @Binding var image: UIImage?
    @Binding var didTapCapture: Bool
    
    func makeUIViewController(context: Context) -> CustomCameraController {
        let controller = CustomCameraController()
        controller.delegate = context.coordinator
        return controller
    }
    
    func updateUIViewController(_ cameraViewController: CustomCameraController, context: Context) {
        
        if(self.didTapCapture) {
            cameraViewController.didTapRecord()
        }
    }
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UINavigationControllerDelegate, AVCapturePhotoCaptureDelegate {
        let parent: CustomCameraRepresentable
        
        init(_ parent: CustomCameraRepresentable) {
            self.parent = parent
        }
        
        func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
            
            parent.didTapCapture = false
            
            if let imageData = photo.fileDataRepresentation() {
                parent.image = UIImage(data: imageData)
            }
            parent.presentationMode.wrappedValue.dismiss()
        }
    }
}

class CustomCameraController: UIViewController {
    
    var image: UIImage?
    
    var captureSession = AVCaptureSession()
    var backCamera: AVCaptureDevice?
    var frontCamera: AVCaptureDevice?
    var currentCamera: AVCaptureDevice?
    var photoOutput: AVCapturePhotoOutput?
    var cameraPreviewLayer: AVCaptureVideoPreviewLayer?
    
    //DELEGATE
    var delegate: AVCapturePhotoCaptureDelegate?
    
    func didTapRecord() {
        
        let settings = AVCapturePhotoSettings()
        photoOutput?.capturePhoto(with: settings, delegate: delegate!)
        
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setup()
    }
    func setup() {
        setupCaptureSession()
        setupDevice()
        setupInputOutput()
        setupPreviewLayer()
        startRunningCaptureSession()
    }
    func setupCaptureSession() {
        captureSession.sessionPreset = AVCaptureSession.Preset.photo
    }
    
    func setupDevice() {
        let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera],
                                                                      mediaType: AVMediaType.video,
                                                                      position: AVCaptureDevice.Position.unspecified)
        for device in deviceDiscoverySession.devices {
            
            switch device.position {
            case AVCaptureDevice.Position.front:
                self.frontCamera = device
            case AVCaptureDevice.Position.back:
                self.backCamera = device
            default:
                break
            }
        }
        
        self.currentCamera = self.backCamera
    }
    
    
    func setupInputOutput() {
        do {
            
            let captureDeviceInput = try AVCaptureDeviceInput(device: currentCamera!)
            captureSession.addInput(captureDeviceInput)
            photoOutput = AVCapturePhotoOutput()
            photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
            captureSession.addOutput(photoOutput!)
            
        } catch {
            print(error)
        }
        
    }
    func setupPreviewLayer()
    {
        let rect = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.width * 1.29)
        
        self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
        self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
        self.cameraPreviewLayer?.frame = rect
        self.view.layer.insertSublayer(cameraPreviewLayer!, at: 0)
        
    }
    func startRunningCaptureSession(){
        captureSession.startRunning()
    }
}


struct CaptureButtonView: View {
    @State private var animationAmount: CGFloat = 1
    var body: some View {
        Image(systemName: "camera").font(.largeTitle)
            .padding(30)
            .background(Color.red)
            .foregroundColor(.white)
            .clipShape(Circle())
            .overlay(
                Circle()
                    .stroke(Color.red)
                    .scaleEffect(animationAmount)
                    .opacity(Double(2 - animationAmount))
                    .animation(Animation.easeOut(duration: 1)
                        .repeatForever(autoreverses: false))
        )
            .padding(.bottom)
            .onAppear
            {
                self.animationAmount = 2
        }
    }
}

You shouldn't use GeometryReader from within the ScrollView , it will create all sort of mess for you.你不应该在ScrollView使用GeometryReader ,它会给你带来各种各样的混乱。 Instead define it at top level just under VStack , and pass the proxy down to Photo view to set Frame.而是在VStack下的顶层定义它,并将proxy向下传递到Photo视图以设置 Frame。

Check the code below-:检查下面的代码-:

import SwiftUI


struct Test1: View {
    @State private var image: Image?
    @State private var showingCustomCamera = false
    @State private var inputImage: UIImage?
    @State private var photos: [UIImage] = []
    
    func addImageToArray() {
        guard let inputImage = inputImage else { return }
        image = Image(uiImage: inputImage)
        
        let ciImage = CIImage(cgImage: inputImage.cgImage!)
        
        let options = [CIDetectorAccuracy: CIDetectorAccuracyHigh]
        let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: options)!
        
        let faces = faceDetector.features(in: ciImage)
        
        if let face = faces.first as? CIFaceFeature {
            print("Found face at \(face.bounds)")
            
            print(face.faceAngle)
            print(face.hasSmile)
            print(face.leftEyeClosed)
            print(face.rightEyeClosed)
            
            if face.leftEyeClosed {
                print("Left Eye Closed \(face.leftEyePosition)")
            }
            
            if face.rightEyeClosed {
                print("Right Eye Closed \(face.rightEyePosition)")
            }
            
            if face.hasSmile {
                print("Person is smiling \(face.mouthPosition)")
            }
        }
        
        photos.append(inputImage)
    }
    
    let columns =
        [GridItem(.flexible(),spacing: 20),
         GridItem(.flexible(),spacing: 20)]
    
    
    var body: some View {
        NavigationView {
            VStack{
                GeometryReader { geometry in
                    ScrollView {
                        LazyVGrid(columns: columns, spacing: 20) {
                            // AddPhoto(showCamera: $showingCustomCamera) // Uncomment in your case
                            
                            
                            ForEach(0..<50, id: \.self) { photo in
                                Photo(img: "ABC", proxy: geometry) // Pass photo as you were doing
                                
                            }
                        }
                        .padding()
                    }
                }
                
                HStack {
                    Button(action: {
                        //
                    }, label: {
                        Image(systemName: "printer.fill.and.paper.fill")
                        Text("Print")
                    })
                    .padding()
                    .foregroundColor(.primary)
                    
                    Button(action: {
                        //
                    }, label: {
                        Image(systemName: "externaldrive.fill.badge.icloud")
                        Text("Digital Upload")
                    })
                    .padding()
                    .foregroundColor(.primary)
                }
            }
            .sheet(isPresented: $showingCustomCamera, onDismiss: addImageToArray) {
                // CustomCameraView(image: self.$inputImage)
            }
            .navigationTitle("Add Photos")
        }
    }
}

struct Photo: View {
    var img: String
    var proxy:GeometryProxy
    @State private var overlay: Bool = false
    
    var body: some View {
        //  GeometryReader { geometry in
        VStack {
            ZStack(alignment: .top) {
                Image(img)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    // .frame(width: 170, height: 200)
                    .frame(width: proxy.size.width * 0.4, height: proxy.size.width * 0.5, alignment: .top)
                    .clipped()
                    .cornerRadius(10)
                    .onTapGesture {
                        self.overlay.toggle()
                    }
                
                if overlay {
                    // Template()
                }
            }
        }
        //}
    }
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM