首页 > 解决方案 > 应用程序终止时未保存图像列表的 SwiftUI 拖放重新排序

问题描述

我正在尝试为水平列表中显示的自定义图像实现拖放功能。问题是当我用拖放重新排序图像时,我想将它保存到应用程序的文档目录中,并在应用程序再次打开时获取它。我被卡住了,不知道如何实现它,如果你知道如何实现它,请帮助,谢谢,非常感谢

这是代码:

struct CustomImage: Identifiable, Equatable, Hashable {
    var id: Int
    var image: UIImage
}

struct ContentView: View {
    @State private var selected = -1
    @ObservedObject var viewModel: ViewModel = ViewModel()
    

    var body: some View {
        ZStack {
            Color.gray.opacity(0.2)
                .ignoresSafeArea()

            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 4) {
                    ForEach(viewModel.images) { image in
                        Image(uiImage: image.image)
                            .resizable()
                            .aspectRatio(contentMode: .fill)
                            .frame(width: 100, height: 150)
                            .overlay(
                                Rectangle()
                                    .stroke(selected == image.id ? Color.white : .clear, lineWidth: 5)
                                    .animation(.spring())
                            )
                            .padding(5)
                            .onTapGesture {
                                selected = image.id
                            }
                            .onDrag({
                                // Setting Current Page
                                selected = 0

                                return NSItemProvider(object: image.image)
                            })
                            .onDrop(of: [.image], delegate: DropViewDelegate(page: CustomImage(id: image.id, image: image.image), viewModel: viewModel))
                    }
                }
                .padding(.leading, 8)
            }
        }
    }
}

struct DropViewDelegate: DropDelegate {
    var page: CustomImage
    var viewModel: ViewModel
    
    func performDrop(info: DropInfo) -> Bool {
         viewModel.currentPage = nil
        return true
    }
    
    // When User Dragged Into New Page
    func dropEntered(info: DropInfo) {
        if viewModel.currentPage == nil {
            viewModel.currentPage = page
        }
        
        // Getting From and To Index
        
        // From Index
        let fromIndex = viewModel.images.firstIndex { (page) -> Bool in
            return page.id == viewModel.currentPage?.id
        } ?? 0
        
        // To Index
        let toIndex = viewModel.images.firstIndex { (page) -> Bool in
            return page.id == self.page.id
        } ?? 0
        
        // Safe check if both are not same
        if fromIndex != toIndex {
            // Animation
            withAnimation(.default) {
                // Swapping Data
                let fromPage = viewModel.images[fromIndex]
                viewModel.images[fromIndex] = viewModel.images[toIndex]
                viewModel.images[toIndex] = fromPage
                viewModel.renameImage(from: "\(fromIndex)", to: "\(toIndex)")
            }
        }
        
//        print("From Index - \(fromIndex)")
//        print("To Index - \(toIndex)")
    }
    
    // Setting Action as Move
    func dropUpdated(info: DropInfo) -> DropProposal? {
        return DropProposal(operation: .move)
    }
}

class ViewModel: ObservableObject {
    @State var images: [CustomImage] = [
        CustomImage(id: 1, image: UIImage(systemName: "command")!),
        CustomImage(id: 2, image: UIImage(systemName: "option")!),
        CustomImage(id: 3, image: UIImage(systemName: "delete.right")!),
        CustomImage(id: 4, image: UIImage(systemName: "shift")!),
        CustomImage(id: 5, image: UIImage(systemName: "globe")!),
    ]
    
    @Published var currentPage: CustomImage?
    
    func getSavedImage(url: URL) -> UIImage? {
        UIImage(contentsOfFile: url.path)
    }
    
    func loadImageFromDocumentDirectory(nameOfImage: String, storyName: String) -> UIImage? {
        let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
        let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
        let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
        guard let dirPath = paths.first else { return nil }
        let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("ProjectImages/\(nameOfImage)")
        print("Image URL --- \(imageURL)")
        guard let image = UIImage(contentsOfFile: imageURL.path) else { return nil }
        
        return image
    }
    
    func renameImage(from: String, to: String) {
        let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
        let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
        let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
        guard let dirPath = paths.first else { return }
        let originPath = URL(fileURLWithPath: dirPath).appendingPathComponent("ProjectImages/\(from)")
        let destitationPath = URL(fileURLWithPath: dirPath).appendingPathComponent("ProjectImages/\(to)")
        
        do {
            try FileManager.default.moveItem(at: originPath, to: destitationPath)
            try FileManager.default.moveItem(at: destitationPath, to: originPath)
        } catch {
            print("Reordering in storage error - \(error)")
        }
    }
    
    func numberOfImages(in name: String) -> Int {
        var number = 0
        let fileManager = FileManager.default
        let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
        let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
        let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
        
        if let dirPath = paths.first {
            let imageURLDir = URL(fileURLWithPath: dirPath).appendingPathComponent("ProjectImages/\(name)")

            do {
                let fileURLs = try fileManager.contentsOfDirectory(at: imageURLDir, includingPropertiesForKeys: nil)
                number = fileURLs.count
                
            } catch {
                print(error.localizedDescription)
                return 0
            }
        }
        return number
    }
    
    @discardableResult
    func loadRegularImagesFromAlbum() -> [UIImage] {

        var images: [UIImage] = []
        let fileManager = FileManager.default
        let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
        let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
        let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
        
        if let dirPath = paths.first {
            let imageURLDir = URL(fileURLWithPath: dirPath).appendingPathComponent("ProjectImages")

            do {
                let fileURLs = try fileManager.contentsOfDirectory(at: imageURLDir, includingPropertiesForKeys: nil)
                
                for imageURL in fileURLs {
                    if let image = getSavedImage(url: imageURL), !fileManager.fileExists(atPath: imageURL.absoluteString) {
                        images.append(image)
                    }
                }
                
            } catch {
                print(error.localizedDescription)
            }
        }
        return images
    }
    
    func getDirectoryPath() -> NSURL {
        let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("ProjectImages")
        let url = NSURL(string: path)

        return url!
    }


    func saveImageDocumentDirectory(image: UIImage, imageName: String) {
        let fileManager = FileManager.default
        let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("ProjectImages")
        if !fileManager.fileExists(atPath: path) {
            try! fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
        }
        let url = NSURL(string: path)
        let imagePath = url!.appendingPathComponent(imageName)
        let urlString: String = imagePath!.absoluteString
        let imageData = image.jpegData(compressionQuality: 0.5)
        //let imageData = UIImagePNGRepresentation(image)
        fileManager.createFile(atPath: urlString as String, contents: imageData, attributes: nil)
        print("Image is saved lo file")
        print("Image name is \(imageName)")
        print("Path is - \(path)")
    }
}

标签: swiftui

解决方案


推荐阅读