![enter image description here](https://istack.dev59.com/g6ySY.gif)
这里是代码:
import SwiftUI
struct ImageCropView: View {
@Environment(\.presentationMode) var pm
@State var imageWidth:CGFloat = 0
@State var imageHeight:CGFloat = 0
@Binding var image : UIImage
@State var dotSize:CGFloat = 13
var dotColor = Color.init(white: 1).opacity(0.9)
@State var center:CGFloat = 0
@State var activeOffset:CGSize = CGSize(width: 0, height: 0)
@State var finalOffset:CGSize = CGSize(width: 0, height: 0)
@State var rectActiveOffset:CGSize = CGSize(width: 0, height: 0)
@State var rectFinalOffset:CGSize = CGSize(width: 0, height: 0)
@State var activeRectSize : CGSize = CGSize(width: 200, height: 200)
@State var finalRectSize : CGSize = CGSize(width: 200, height: 200)
var body: some View {
ZStack {
Image(uiImage: image)
.resizable()
.scaledToFit()
.overlay(GeometryReader{geo -> AnyView in
DispatchQueue.main.async{
self.imageWidth = geo.size.width
self.imageHeight = geo.size.height
}
return AnyView(EmptyView())
})
Text("Crop")
.padding(6)
.foregroundColor(.white)
.background(Capsule().fill(Color.blue))
.offset(y: -250)
.onTapGesture {
let cgImage: CGImage = image.cgImage!
let scaler = CGFloat(cgImage.width)/imageWidth
if let cImage = cgImage.cropping(to: CGRect(x: getCropStartCord().x * scaler, y: getCropStartCord().y * scaler, width: activeRectSize.width * scaler, height: activeRectSize.height * scaler)){
image = UIImage(cgImage: cImage)
}
pm.wrappedValue.dismiss()
}
Rectangle()
.stroke(lineWidth: 1)
.foregroundColor(.white)
.offset(x: rectActiveOffset.width, y: rectActiveOffset.height)
.frame(width: activeRectSize.width, height: activeRectSize.height)
Rectangle()
.stroke(lineWidth: 1)
.foregroundColor(.white)
.background(Color.green.opacity(0.3))
.offset(x: rectActiveOffset.width, y: rectActiveOffset.height)
.frame(width: activeRectSize.width, height: activeRectSize.height)
.gesture(
DragGesture()
.onChanged{drag in
let workingOffset = CGSize(
width: rectFinalOffset.width + drag.translation.width,
height: rectFinalOffset.height + drag.translation.height
)
self.rectActiveOffset.width = workingOffset.width
self.rectActiveOffset.height = workingOffset.height
activeOffset.width = rectActiveOffset.width - activeRectSize.width / 2
activeOffset.height = rectActiveOffset.height - activeRectSize.height / 2
}
.onEnded{drag in
self.rectFinalOffset = rectActiveOffset
self.finalOffset = activeOffset
}
)
Image(systemName: "arrow.up.left.and.arrow.down.right")
.font(.system(size: 12))
.background(Circle().frame(width: 20, height: 20).foregroundColor(dotColor))
.frame(width: dotSize, height: dotSize)
.foregroundColor(.black)
.offset(x: activeOffset.width, y: activeOffset.height)
.gesture(
DragGesture()
.onChanged{drag in
let workingOffset = CGSize(
width: finalOffset.width + drag.translation.width,
height: finalOffset.height + drag.translation.height
)
let changeInXOffset = finalOffset.width - workingOffset.width
let changeInYOffset = finalOffset.height - workingOffset.height
if finalRectSize.width + changeInXOffset > 40 && finalRectSize.height + changeInYOffset > 40{
self.activeOffset.width = workingOffset.width
self.activeOffset.height = workingOffset.height
activeRectSize.width = finalRectSize.width + changeInXOffset
activeRectSize.height = finalRectSize.height + changeInYOffset
rectActiveOffset.width = rectFinalOffset.width - changeInXOffset / 2
rectActiveOffset.height = rectFinalOffset.height - changeInYOffset / 2
}
}
.onEnded{drag in
self.finalOffset = activeOffset
finalRectSize = activeRectSize
rectFinalOffset = rectActiveOffset
}
)
}
.onAppear {
activeOffset.width = rectActiveOffset.width - activeRectSize.width / 2
activeOffset.height = rectActiveOffset.height - activeRectSize.height / 2
finalOffset = activeOffset
}
}
func getCropStartCord() -> CGPoint{
var cropPoint : CGPoint = CGPoint(x: 0, y: 0)
cropPoint.x = imageWidth / 2 - (activeRectSize.width / 2 - rectActiveOffset.width )
cropPoint.y = imageHeight / 2 - (activeRectSize.height / 2 - rectActiveOffset.height )
return cropPoint
}
}
struct TestCrop : View{
@State var imageWidth:CGFloat = 0
@State var imageHeight:CGFloat = 0
@State var image:UIImage
@State var showCropper : Bool = false
var body: some View{
VStack{
Text("Open Cropper")
.font(.system(size: 17, weight: .medium))
.padding(.horizontal, 15)
.padding(.vertical, 10)
.foregroundColor(.white)
.background(Capsule().fill(Color.blue))
.onTapGesture {
showCropper = true
}
Image(uiImage: image)
.resizable()
.scaledToFit()
}
.sheet(isPresented: $showCropper) {
} content: {
ImageCropView(image: $image)
}
}
}
struct TestViewFinder_Previews: PreviewProvider {
static var originalImage = UIImage(named: "food")
static var previews: some View {
TestCrop(image: originalImage ?? UIImage())
}
}