[UIKit] UIActivityViewController での イメージプレビューを指定する方法

UIKit

UIActivityViewController で表示されるアイテムのプレビューを指定する方法を説明します。

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Big Sur 11.4
  • Xcode 13 beta
  • iOS 15 beta
MEMO
とくに、iOS15 の新機能は使っていません

UIActivityViewController

いわゆる ”共有ボタン”を押すと表示される View と その ViewController です。

カスタマイズするというよりは、システムが用意してくれている UIActivityViewController に、必要な情報を渡して使用するという形になります。

プレビュー

ここでは、ActivityView の左上に表示されるものを プレビューと呼んでいます。

Preview in UIActivityViewController
Preview in UIActivityViewController

UIImage を渡した時に 表示されるプレビュー

UIActivityViewController に 共有したいデータを渡すと、UIActivityViewController 側の判断でプレビューが表示されます。

UIImage をデータとして渡した時には、このプレビューにはアプリのアイコンが表示されます。

アプリアイコンで良いケースもあると思いますが、共有する画像自体を表示したいというケースもあるはずです。

そのようなケースへの対応方法を説明していきます。

UIActivityItemSource

いろいろと調べましたが、UIImage を渡して、渡した イメージをプレビューとして表示させる方法はないようです。

方法としては、UIImage をそのまま渡さずに、UIActivityItemSource 経由で UIImage を渡すようにすることで、プレビューに使用されるイメージを指定することが可能になります。

直接 UIImage を UIActivityViewController に渡す

以下のコードは、UIImage を、そのまま activityItem として渡しています。


    let image = UIImage(...)
    let vc = UIActivityViewController(activityItems: [image], applicationActivities: nil)

UIImage を渡すという目的は達成できますが、プレビュー表示は、アプリアイコンになってしまいます。(プレビューはアプリアイコンですが、シェアされるイメージデータは、渡した UIImage になります)

UIActivityItemSource 経由で UIImage を UIActivityViewController に渡す

UIActivityItemSource をサブクラス化して使う必要があるので、ひと手間かかります。

以下のコードは、UIImage を UIActivityItemSource のサブクラスで wrap してから activityItem として渡しています。


    let image = UIImage(...)
    let shareImage = ShareImage(image)
    let vc = UIActivityViewController(activityItems: [shareImage], applicationActivities: nil)

ラップするために UIActivityItemSource をサブクラス化した ShareImage は、以下のように定義しています。


public final class ShareImage: NSObject, UIActivityItemSource {
    private let item: UIImage?
    private let itemURL: URL?
    public init(_ item: UIImage?) {
        self.item = item
        // (1)
        if let data = item?.jpegData(compressionQuality: 1.0) {
            let saveDir = FileManager.default.temporaryDirectory.appendingPathComponent("shareimage.jpg")
            try? data.write(to: saveDir)
            self.itemURL = saveDir
        } else {
            self.itemURL = nil
        }
    }
    public func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        return item as Any
    }
    public func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
        return activityViewControllerPlaceholderItem(activityViewController)
    }
    
    public func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
        let metadata = LPLinkMetadata()
        // (2)
        // metadata.title = "title"
        if let url = itemURL {
            // (3)
            metadata.iconProvider = NSItemProvider.init(contentsOf: url)
        }
        return metadata
    }
}
コード解説
  1. 渡された UIImage をファイル保存します(ここでは、テンポラリディレクトリに保存しています)
  2. 必要であれば、表示される説明テキストも設定できます
  3. ローカルに保存したイメージファイルの URL を渡すことで、プレビューに表示させることができます。
MEMO
データとして UIImage を持っているので、一旦ファイルに書き出す作業が 煩わしいですが、現時点では、この手法しか無いようです。

まとめ:UIActivityViewController での イメージプレビューを指定する方法

UIActivityViewController での イメージプレビューを指定する方法
  • UIActivityItemSource を継承したクラスで、プレビュー向け URL を用意する
  • LPLinkMetadata を使用して、プレビューを指定する

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です