UIActivityViewControllerのHeaderをカスタマイズする
はじめに
UIActivityViewControllerのHeaderのサブタイトル部分に独自の説明文を入れたいと考えているそこのあなた!現在(iOS15では)実現不可能です😭
サブタイトルに何かしらの文字が入ってるありますが、あればURLを渡した時のメタデータが入ります。
じゃーどこまでカスタマイズできるかというと独自のアイコン画像とタイトルの文字を入れることだけです。
文字と画像どうやって入れるのか
標準で渡せる形でTextとUIImageを渡すとどうなるかというとこれでは機能しません。
let items: [Any] = ["リンクをコピーしました", UIImage(named: "sample")]
let activityVC = UIActivityViewController(activityItems: items, applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = self.view
activityVC.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.size.width,
y: self.view.bounds.size.height / 2.0,
width: 1.0,
height: 1.0)
self.present(activityVC, animated: true, completion: nil)
画像のように表示されません、これはString > URL > Data(UIImage等)という関係せいがあるからだそうです。
ただこちらも公式ドキュメントの引用ではなく記事を書いた方の検証結果とのことなのでOSが変わった時にAppleによって勝手に変えられる可能性も考慮すべきだと思います。
タイトルとアイコン両方出す
両方出すにはiOS13からUIActivityItemSourceに追加された以下のメソッドの中でアイコンに使用する画像とタイトルを設定する必要があります。
func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata?
結果
コード
CustomShareItem
UIActivityItemSourceに準拠したクラスを作成してLPLinkMetadataを返します。このメソッド自体iOS13からできたもので13以下で実現できるのかは不明
import LinkPresentation
class CustomShareItem: NSObject, UIActivityItemSource {
private let metadata: LPLinkMetadata
init(metadata: LPLinkMetadata) {
self.metadata = metadata
}
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return ""
}
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
return activityViewControllerPlaceholderItem(activityViewController)
}
func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
return metadata
}
}
AssetExtractor
URLで画像を渡す必要があるのでAssetsにある画像のURLを取得する必要があるんですが便利なメソッドが転がってなので使わせていただきました。
感謝🙏
class AssetExtractor {
static func createLocalUrl(forImageNamed name: String) -> URL? {
let fileManager = FileManager.default
let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0]
let url = cacheDirectory.appendingPathComponent("\(name).png")
guard fileManager.fileExists(atPath: url.path) else {
guard
let image = UIImage(named: name),
let data = image.pngData()
else { return nil }
fileManager.createFile(atPath: url.path, contents: data, attributes: nil)
return url
}
return url
}
}
呼び出しもと
class ViewController: UIViewController {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
let metadata = LPLinkMetadata()
metadata.title = "タイトルタイトルタイトル"
metadata.iconProvider = NSItemProvider(contentsOf: AssetExtractor.createLocalUrl(forImageNamed: "sample"))
let activityVC = UIActivityViewController(activityItems: [CustomShareItem(metadata: metadata)], applicationActivities: nil)
present(activityVC, animated: true, completion: nil)
}
}
参考文献
Embedding and Sharing Visually Rich Links
Xcod11&iOS13のUIActivityViewControllerのプレビュー画面の挙動が実装方法によって異なる