Set different activity items for UIActivityViewController Swift
You should take advantage of the UIActivityItemSource
protocol. The activityItems
parameter of the initializer of UIActivityViewController
accepts either an array of data objects or an array of objects that implement the UIActivityItemSource
protocol.
As an example consider an item source like the following.
class MyStringItemSource: NSObject, UIActivityItemSource {
@objc func activityViewControllerPlaceholderItem(activityViewController: UIActivityViewController) -> AnyObject {
return ""
}
@objc func activityViewController(activityViewController: UIActivityViewController, itemForActivityType activityType: String) -> AnyObject? {
if activityType == UIActivityTypeMessage {
return "String for message"
} else if activityType == UIActivityTypeMail {
return "String for mail"
} else if activityType == UIActivityTypePostToTwitter {
return "String for twitter"
} else if activityType == UIActivityTypePostToFacebook {
return "String for facebook"
}
return nil
}
func activityViewController(activityViewController: UIActivityViewController, subjectForActivityType activityType: String?) -> String {
if activityType == UIActivityTypeMessage {
return "Subject for message"
} else if activityType == UIActivityTypeMail {
return "Subject for mail"
} else if activityType == UIActivityTypePostToTwitter {
return "Subject for twitter"
} else if activityType == UIActivityTypePostToFacebook {
return "Subject for facebook"
}
return ""
}
func activityViewController(activityViewController: UIActivityViewController, thumbnailImageForActivityType activityType: String!, suggestedSize size: CGSize) -> UIImage! {
if activityType == UIActivityTypeMessage {
return UIImage(named: "thumbnail-for-message")
} else if activityType == UIActivityTypeMail {
return UIImage(named: "thumbnail-for-mail")
} else if activityType == UIActivityTypePostToTwitter {
return UIImage(named: "thumbnail-for-twitter")
} else if activityType == UIActivityTypePostToFacebook {
return UIImage(named: "thumbnail-for-facebook")
}
return UIImage(named: "some-default-thumbnail")
}
}
The above item source returns different string data objects, subjects and thumbnail images based on the activity type. To use, you just need to pass it into the UIActivityViewController
initializer.
UIActivityViewController(activityItems: [MyStringItemSource()], applicationActivities: nil)
Similarly, you could define a custom MyUrlItemSource
class that returns different URLs based on the selected activity and pass it along in the initializer.
UIActivityViewController(activityItems: [MyStringItemSource(), MyUrlItemSource()], applicationActivities: nil)
All of this is outlined in the official documentation for UIActivityViewController
and UIActivityItemSource
Providing different shared items for each activity with UIActivityViewController
You can provide different data for different activities by creating a class that adopts UIActivityItemSource
protocol and implements the method:
-(id)activityViewController:itemForActivityType:
Then pass the object of your custom class to your UIActivityViewController
in activityItems array with a call -(id)initWithActivityItems:applicationActivities:
From documentation of this method:
... Instead of actual data objects, the objects in this array can be objects that adopt the UIActivityItemSource protocol, such as UIActivityItemProvider objects. ...
Here is a tutorial about how to do that: https://www.albertopasca.it/whiletrue/objective-c-custom-uiactivityviewcontroller-icons-and-text/
Sharing different content based on selected activity - UIActivityController
Just make a subclass of UIActivityItemProvider
and override item
property to give your custom activity items
, i.e.
class CustomActivityItemProvider: UIActivityItemProvider
{
override var item: Any{
switch self.activityType!
{
case UIActivityType.postToFacebook:
return "Hello"
default:
return "Whatever"
}
}
}
Using it:
let activityItem = CustomActivityItemProvider(placeholderItem: "")
let activityViewController = UIActivityViewController(activityItems: [activityItem], applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil)
Also, you can customize only those UIActivityType
, that are exposed by Apple
for use by developers. For UIActivityTypes
refer to: https://developer.apple.com/documentation/uikit/uiactivitytype
UIActivityViewController to add additional types to UIPasteboard for 'copyToPasteboard' action
I've found a solution and my 'paste' process now recognises that there is both 'jsonData' and 'jsonString' on the pasteboard now, as well as attributed string and plain text.
Instead of adding 'self' to the 'items', I had to have 'self' as the ONLY item. Then I can define what items are returned by the protocol function:
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
guard let recipe = recipe else { return nil }
let attrString = someThing.attrString()
switch activityType {
case UIActivity.ActivityType.print:
return SomePrintPageRenderer(someThing)
case UIActivity.ActivityType.copyToPasteboard:
var pasteboardDict: [String:Any] = attrString.pasteables()
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
let jsonData = try? jsonEncoder.encode(someThing)
let jsonString = String(data: jsonData!, encoding: .utf8)
print(jsonString!)
if jsonData != nil {
pasteboardDict["jsonData"] = jsonData
if jsonString != nil {
pasteboardDict["jsonString"] = jsonString
}
}
return pasteboardDict
default:
return attrString
}
}
Note that I had to also explicitly handle the inclusion of the various plain and attributed string pasteboard types which I still require. (This has been done with a custom NSAttributedString extension with the function 'pasteables()' which returns a Dictionary of pasteable versions of the attributed string.)
IOS/Objective-C: UIActivityViewController: Customize for different Activity Types
You need to pass an instance or instances of your class that implements UIActivityItemSource
when creating a UIActivityViewController
with initWithActivityItems:applicationActivities:
- see the documentation here. A view controller is probably not a good choice for this, I'd instead make dedicated objects to do this. Ultimately your code could look something like:
MySourceClass *mySource = [MySourceClass new];
NSArray *activityItems = @[mySource];
UIActivityViewController *activityViewController =
[[UIActivityViewController alloc] initWithActivityItems:activityItems
applicationActivities:nil];
Related Topics
Info.Plist Utility Error: "Info.Plist Couldn't Be Opened Because There Is No Such File"
How to Use Uiviewcontrolleranimatedtransitioning with Uinavigationcontroller
Getting a Thumbnail of a *.Mov Video iOS
Push/Pop View Controller with Navigation Bar from View Controller Without Navigation Bar
Can't Import Embedded Framework with Xcode 6 Gm
Archs[@]: Unbound Variable in Xcode 12
Uislider Setmaximumtracktintcolor in iOS 7.1
Could Not Attach to Pid:"####" Unable to Attach
How to Import Existing Objective C Classes in Swift
How to Play Movie with a Url Using a Custom Nsurlprotocol
Sqlite Database on Phonegap/iOS - More Than 5Mb Possible
How to Efficiently Find Cgrects for Visible Words in Uitextview
Playing Video Inline in Ionic/Phonegap (Webkit-Playsinline Not Working)
How to Create a Bold Uifont from a Regular Uifont
Add a Done Button Within a Pop-Up Datepickerview in Swift
Completely Disable Firebase/Analytics to Stop Console Spam on App Startup