SwiftUI LazyVStack 重叠图像
Posted
技术标签:
【中文标题】SwiftUI LazyVStack 重叠图像【英文标题】:SwiftUI LazyVStack overlapping images 【发布时间】:2021-06-20 02:23:32 【问题描述】:我试图在嵌入滚动视图的 LazyVStack 中显示两列图像,但是第二行图像与上面的行部分重叠。我不确定这是 LazyVStack 本身的问题还是 Photo.swift 视图的问题。
输出看起来像这样
两个视图文件
ContentView.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")
照片.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()
有人知道吗?我觉得我错过了一些明显的东西。
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
【问题讨论】:
你能显示 CustomCameraView 的代码吗? @aheze 我已经添加了 可能是“网格”没有得到正确的“AddPhoto(...)”大小。 “AddPhoto(showCamera: $showingCustomCamera)”是否返回有界大小的视图?例如,尝试类似于 PassportPhoto/Photo 尺寸的东西:“frame(maxWidth: geometry.size.width, maxHeight: geometry.size.width * 1.29)”" @workingdog 即使我完全删除 AddPhoto 并让它显示一组图像,它的行为也是一样的。 【参考方案1】:你不应该在ScrollView
中使用GeometryReader
,它会给你造成各种各样的混乱。而是在 VStack
下方的顶层定义它,并将 proxy
向下传递到 Photo 视图以设置 Frame。
检查下面的代码-:
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()
//
【讨论】:
以上是关于SwiftUI LazyVStack 重叠图像的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 匹配几何 + LazyVStack = 崩溃