#ios #swiftui
Вопрос:
У меня есть приложение, которое делает снимок представления, а затем снимок используется в качестве изображения, которое пользователь может нарисовать поверх. Я следовал этому руководству, чтобы получить функциональность рисования.
Все работает отлично, однако, если я попытаюсь сделать снимок изображения с рисунком сверху, оно сохранит его в фотоальбоме как просто изображение (без рисунка). Я хочу использовать кнопку для сохранения снимка изображения с недавно добавленным рисунком. Как видно из кода, я попытался использовать ZStack в представлении, которое я снимаю, однако у меня ничего не вышло.
Я думаю, что мне нужно что-то обновить в окне обновления, но я не уверен, что именно. Приведенный ниже минимальный воспроизводимый пример будет построен с учетом этой проблемы. Я ценю любые идеи.
Спасибо!
Просмотр содержимого
import SwiftUI
struct ContentView: View {
@State private var snapshotImage: UIImage? = nil
var imageView: some View {
Image("Test")
//EmptyView() <- Uncomment and comment out the line above to just use an empty View as an image
}
var imageDrawingView: some View {
ZStack {
if let image = snapshotImage {
Image(uiImage: image)
CanvasViewWrapper()
}
}
}
var body: some View {
if snapshotImage != nil {
VStack {
ZStack {
imageDrawingView
}
Button("Save Image") {
let imageWithDrawing = imageDrawingView.snapshot()
UIImageWriteToSavedPhotosAlbum(imageWithDrawing, nil, nil, nil) // Save to photos
}
}
} else {
VStack {
imageView
Button("Take ScreenShot") {
self.snapshotImage = imageView.snapshot()
}
}
}
}
}
extension View {
func snapshot() -> UIImage {
let controller = UIHostingController(rootView: self)
let view = controller.view
let targetSize = controller.view.intrinsicContentSize
view?.bounds = CGRect(origin: .zero, size: targetSize)
view?.backgroundColor = .clear
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
}
}
}
CanvasView
import Foundation
import UIKit
class CanvasView: UIView {
override func draw(_ rect: CGRect){
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
paths.forEach { path in
switch(path.type) {
case .move:
context.move(to: path.point)
break
case .line:
context.addLine(to: path.point)
break
}
}
context.setLineWidth(10)
context.setLineCap(.round)
context.strokePath()
}
@Published var paths = [Path]()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: self) else { return }
paths.append(Path(type: .move, point: point))
setNeedsDisplay()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: self) else { return }
paths.append(Path(type: .line, point: point))
setNeedsDisplay()
}
}
struct Path {
let type: PathType
let point: CGPoint
init(type: PathType, point: CGPoint) {
self.type = type
self.point = point
}
enum PathType {
case move
case line
}
}
Оберточная бумага CanvasViewWrapper
import SwiftUI
struct CanvasViewWrapper : UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
return CanvasView()
}
func updateUIView(_ uiView: UIView, context: Context) {
uiView.backgroundColor = .clear
}
}
Апп
import SwiftUI
@main
struct StackMinimalApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Ответ №1:
Сделайте снимок UIImageView или UIView с помощью этого расширения
extension UIView {
func asImage() -> UIImage {
if #available(iOS 10.0, *) {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
} else {
UIGraphicsBeginImageContext(self.frame.size)
self.layer.render(in:UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return UIImage(cgImage: image!.cgImage!)
}
}
func asImages() -> UIImage {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}
Воспользуйся
let image = someView.asImage()
он вернет вам UIView с рисунком в виде изображения, а затем сохранит это изображение в вашей библиотеке.
сохранить
func saveImage(image: UIImage) -> Bool {
guard let data = UIImageJPEGRepresentation(image, 1) ?? UIImagePNGRepresentation(image) else {
return false
}
guard let directory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) as NSURL else {
return false
}
do {
try data.write(to: directory.appendingPathComponent("fileName.png")!)
return true
} catch {
print(error.localizedDescription)
return false
}
}
использовать
let success = saveImage(image: UIImage(named: "image.png")!)
Получите Изображение
func getSavedImage(named: String) -> UIImage? {
if let dir = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
return UIImage(contentsOfFile: URL(fileURLWithPath: dir.absoluteString).appendingPathComponent(named).path)
}
return nil
}
использовать
if let image = getSavedImage(named: "fileName") {
// do something with image
}