使用 UIActivityViewController 发布,但避免裁剪?

Posting with UIActivityViewController, but avoiding cropping?

假设您构建了一张在不同设备上全屏显示的图像。然后,您可以使用 UIActivityViewController post 以正常方式 - 例如 - Instagram。

用户点击您的分享按钮,它会弹出通常的 iOS-sharing-thingy,

并且您可以 post 到 Instagram(当然假设用户是 Instagram 用户)。不用担心。

但通常图片在 Instagram 上会被裁剪 - 您会丢失一些顶部和底部。

真的有解决办法吗?

请注意,确实 - 假设您在 iPhone 上打开普通的照片应用程序,而在 Instagram 上打开 "share" 和 post ... 你输了一点顶部和底部!

当用户单击此 Instagram 图标时...

事实上,我有没有办法返回,了解用户的选择,并使图像大小合适?

有没有办法将选择的图像(各种尺寸)传递给 UIActivityViewController?

这是怎么回事,这似乎是一个基本的失败?

注意 - 我完全知道在进入 iOS-share-thingy 之前,我可以自己询问用户 "What size image would you like me to make?"

注意 - 我知道在某些情况下可以 post "directly" 在应用程序中说 Instagram,而无需使用 Apple 的共享系统;不过这很蹩脚。

为了节省任何人的打字时间,这里有一些干净的代码可以调出 iOS-共享系统...

    @IBAction func userClickedOurShareButton()
        {
        let s:[AnyObject] = [buildImage()]
        let ac = CleanerActivity(activityItems:s, applicationActivities:nil)

        ac.popoverPresentationController?.sourceView = view
        // needed so that iPads won't crash. sarcasm: thanks Apple

        ac.excludedActivityTypes = [UIActivityType.assignToContact,
            UIActivityType.saveToCameraRoll,
            UIActivityType.addToReadingList,
            UIActivityType.copyToPasteboard ]

        // consider UIActivityTypeMessage also

        if #available(iOS 9.0, *) {
                ac.excludedActivityTypes?.append(UIActivityType.openInIBooks)
            } else {
                // Fallback on earlier versions
            }

        self.present(ac, animated:false, completion:nil)
        }


class CleanerActivity: UIActivityViewController {

    func _shouldExcludeActivityType(_ activity: UIActivity) -> Bool {
        let activityTypesToExclude = [
            "com.apple.reminders.RemindersEditorExtension",
            "com.apple.mobilenotes.SharingExtension",
            "com.google.Drive.ShareExtension",
            "com.apple.mobileslideshow.StreamShareService"
        ]

        if let actType = activity.activityType {
            if activityTypesToExclude.contains(actType.rawValue) {
                return true
            }
            else if super.excludedActivityTypes != nil {
                return super.excludedActivityTypes!.contains(actType)
            }
        }
        return false
    }

免责声明:此解决方案涉及将 Instagram 的扩展标识符硬编码到您的应用程序中,这可能会也可能不会通过应用程序审查,并且将来可能会崩溃。尝试风险自负!

Apple 为此提供了一种称为 UIActivityItemProvider 的机制。您可以将覆盖 itemForActivityTypeUIActivityItemProvider 的子类传递给 return,而不是将图像传递给您的 UIActivityViewController,一个基于 activity 选择的类型的适当图像用户。

Apple 为许多常见的 activity 类型提供常量,但尚未包括 Instagram。您可以通过检查 activity 类型的原始值是否为 com.burbn.instagram.shareextension 来识别 Instagram。如果 Instagram 更改其扩展程序的 ID,这将中断。

这里有一个 UIActivityItemProvider 为 Instagram 提供不同的图像:

class DynamicImageProvider: UIActivityItemProvider {

    let instagramImage: UIImage
    let defaultImage: UIImage

    init(instagramImage: UIImage, defaultImage: UIImage) {
        self.instagramImage = instagramImage
        self.defaultImage = defaultImage
        super.init(placeholderItem: defaultImage)
    }

    override func activityViewController(_ activityViewController: UIActivityViewController,
                                         itemForActivityType activityType: UIActivityType) -> Any? {
        if activityType.rawValue == "com.burbn.instagram.shareextension" {
            return instagramImage
        }
        else {
            return defaultImage
        }
    }
}

然后更改 IBAction 的前两行:

let imageProvider = DynamicImageProvider(instagramImage:buildInstagramImage(), defaultImage:buildImage())
let ac = CleanerActivity(activityItems:[imageProvider], applicationActivities:nil)