SwiftUI exporting or sharing files

后端 未结 5 692
再見小時候
再見小時候 2021-01-12 21:53

I\'m wondering if there is a good way export or share a file through SwiftUI. There doesn\'t seem to be a way to wrap a UIActivityViewController and present it directly. I\'

5条回答
  •  再見小時候
    2021-01-12 22:18

    EDIT: Removed all code and references to UIButton.

    Thanks to @Matteo_Pacini for his answer to this question for showing us this technique. As with his answer (and comment), (1) this is rough around the edges and (2) I'm not sure this is how Apple wants us to use UIViewControllerRepresentable and I really hope they provide a better SwiftUI ("SwiftierUI"?) replacement in a future beta.

    I put in a lot of work in UIKit because I want this to look good on an iPad, where a sourceView is needed for the popover. The real trick is to display a (SwiftUI) View that gets the UIActivityViewController in the view hierarchy and trigger present from UIKit.

    My needs were to present a single image to share, so things are targeted in that direction. Let's say you have an image, stored as a @State variable - in my example the image is called vermont.jpg and yes, things are hard-coded for that.

    First, create a UIKit class of type `UIViewController to present the share popover:

    class ActivityViewController : UIViewController {
    
        var uiImage:UIImage!
    
        @objc func shareImage() {
            let vc = UIActivityViewController(activityItems: [uiImage!], applicationActivities: [])
            vc.excludedActivityTypes =  [
                UIActivity.ActivityType.postToWeibo,
                UIActivity.ActivityType.assignToContact,
                UIActivity.ActivityType.addToReadingList,
                UIActivity.ActivityType.postToVimeo,
                UIActivity.ActivityType.postToTencentWeibo
            ]
            present(vc,
                    animated: true,
                    completion: nil)
            vc.popoverPresentationController?.sourceView = self.view
        }
    }
    

    The main things are;

    • You need a "wrapper" UIViewController to be able to present things.
    • You need var uiImage:UIImage! to set the activityItems.

    Next up, wrap this into a UIViewControllerRepresentable:

    struct SwiftUIActivityViewController : UIViewControllerRepresentable {
    
        let activityViewController = ActivityViewController()
    
        func makeUIViewController(context: Context) -> ActivityViewController {
            activityViewController
        }
        func updateUIViewController(_ uiViewController: ActivityViewController, context: Context) {
            //
        }
        func shareImage(uiImage: UIImage) {
            activityViewController.uiImage = uiImage
            activityViewController.shareImage()
        }
    }
    

    The only two things of note are:

    • Instantiating ActivityViewController to return it up to ContentView
    • Creating shareImage(uiImage:UIImage) to call it.

    Finally, you have ContentView:

    struct ContentView : View {
        let activityViewController = SwiftUIActivityViewController()
        @State var uiImage = UIImage(named: "vermont.jpg")
        var body: some View {
            VStack {
                Button(action: {
                    self.activityViewController.shareImage(uiImage: self.uiImage!)
                }) {
                    ZStack {
                        Image(systemName:"square.and.arrow.up").renderingMode(.original).font(Font.title.weight(.regular))
                        activityViewController
                    }
            }.frame(width: 60, height: 60).border(Color.black, width: 2, cornerRadius: 2)
                Divider()
                Image(uiImage: uiImage!)
            }
        }
    }
    

    Note that there's some hard-coding and (ugh) force-unwrapping of uiImage, along with an unnecessary use of @State. These are there because I plan to use `UIImagePickerController next to tie this all together.

    The things of note here:

    • Instantiating SwiftUIActivityViewController, and using shareImage as the Button action.
    • Using it to also be button display. Don't forget, even a UIViewControllerRepresentable is really just considered a SwiftUI View!

    Change the name of the image to one you have in your project, and this should work. You'll get a centered 60x60 button with the image below it.

提交回复
热议问题