I'd like to provide different content to the different services in a UIActivityIndicatorView. For example, an HTML string for email, standard string for Facebook/Twitter, and an image for Copy. All of this happens within a single popover window.
I don't think this is possible. As I was playing around with all of the involved classes, I notices that the services that appear in the activity view change as the content type I provided it changed. In other words, when I provided a string, set A of services appeared. When I provided an image, set B of services appeared.
Next I tried adding both string and image thinking that possibly it would provide different content, however this just adds both the string and image to the services (for example an email is created with a string, then the image below).
Here is how I am providing string values (which are html links):
-(void)shareButtonTouchUpInside:(SMActionToolbarViewController*)sender{
// Reposition anchor view for UIPopoverController to point at
[self repositionAnchorViewToButtonFrame:self.actionToolbarViewController.shareButtonFrame];
// Asynch download of image
[SMUtility downloadAsset:self.selectedAsset completion:^(UIImage *image) {
// Create image source
SMActivitySource *activityImageSource = [[SMActivitySource alloc]initWithImage:image];
// Create string source
NSString *assetsString = [SMUtility assetsString:[NSArray arrayWithObject:self.selectedAsset]];
SMActivitySource *activityStringSource = [[SMActivitySource alloc]initWithString:assetsString];
// Present UIActiviyViewController within an UIPopoverController
NSArray *items = [#[activityImageSource, activityStringSource]mutableCopy];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc]initWithActivityItems:items applicationActivities:nil];
[activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed){
// TODO: Populate mixpanel data
[SMMixPanel eventSharePhotoMethod:#"Unknown"];
}];
self.buttonPopoverController = [[UIPopoverController alloc] initWithContentViewController:activityViewController];
[self.buttonPopoverController presentPopoverFromRect:self.anchorView.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}];
}
You should subclass UIActivityItemProvider or create objects that conform to UIActivityItemSource. Pass in an array of those (one for each thing you want to share), and have some of them return nil depending on the chosen activity in the activityViewController:itemForActivityType: call.
This Question has been asked time and time again, the only way to fix it is to make your own UIActivity, see apple documentation on how to do that. Here is a link: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIActivity_Class/Reference/Reference.html
Related
From the iOS SDK docs, an Action extension might help users edit an image in a document that they’re viewing in a text editor. However I've been trying to google for examples how to do this and can only find articles on how to create app extensions and not how to use them in an app.
Suppose that I'm writing a word processing application for iOS. Picture the user having an embedded image in the app and wants to edit the image (e.g. apply a photo effect). How can the application provides the image to whatever image editing applications that the user has installed in the system, let it do it's thing, and then takes in the result?
I'd imagine the interaction style is pretty similar to LinkBack on the Mac. Except that the image editor is an app extension and displayed as a modal dialog (as per the SDK guide).
However I couldn't find any code example that shows:
How to provide input data (e.g. image) to the action extension.
How to invoke the action extension.
How to get back the output data from the action extension (including whatever additional metadata or editing information that the extension generates).
How to display the output data in a recognizable format (e.g. if I gave out a JPEG, I'd expect another JPEG will be given by the action extension as a result).
In the mean time I've figured out how to do this. It revolves primarily around UIActivityViewController and providing a callback block to the controller to receive the results from the action extension.
The example below works with Skitch as the test action extension.
// get the source image
UIImage* image = ...;
NSArray* activityItems = #[image];
UIActivityViewController* activityCtrl = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
activityCtrl.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
[returnedItems enumerateObjectsUsingBlock:^(NSExtensionItem* _Nonnull item, NSUInteger idx, BOOL * _Nonnull stop1) {
[item.attachments enumerateObjectsUsingBlock:^(NSItemProvider* _Nonnull attachment, NSUInteger idx, BOOL * _Nonnull stop2) {
if ([attachment hasItemConformingToTypeIdentifier:(__bridge id)kUTTypeImage]) {
[attachment loadItemForTypeIdentifier:(__bridge id)kUTTypeImage options:nil completionHandler:^(UIImage* returnedImage, NSError * _Null_unspecified error) {
// returnedImage is the result of the action extension
}];
*stop1 = YES;
*stop2 = YES;
}
}];
}];
};
// assume that `self` is a UIViewController
[self presentViewController:activityCtrl animated:YES completion:nil];
Unfortunately action extension providers are a bit rare, hence I couldn't test out how it actually interacts with other action extensions that can produce images.
My rss app is almost complete but I need to have a "share" button on the top right corner of the web view for the articles. I have the code setup so far to show the "action" button right next to the title of the article but since there is no real code implemented it doesn't do anything :
I implemented that by basing it on code that was used for the table view cells where there is a "refresh" option implemented and I just changed the icon. I used a free open source project to put this app together and i'm having a little bit of trouble figuring out how to make that button show the share sheet that pulls up from the bottom of the app, like this:
(image from google)
I tried to implement a button dirtectly into the nav bar but I can't since the web view covers the whole screen:
So, since I couldn't put a button directly into the controller I had to encode it in like so:
In my RSSDetail.m class inside the " -(void)viewDidLoad { " :
self.navigationItem.rightBarButton = [[UIBarButtonItem = [[UIBarButtonItem
alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemAction target:self
action#selector(shareButton)];
and I also have this inside the same class file :
-(void) shareButton {
self.webView.userInteractionEnabled = YES;
self.webView.aplha = 0.3;
}
So as you can see, this little bit of code in that class puts the icon where I want it. But my question is, is there code i can implement into my " -(void) shareButton " method that will implement the sharing functionality?
Also, I need for the button to actually say "Share" as opposed to the icon, is there anyway I can change the code for the "Action" rightBarButton method to allow me to input the word instead of an icon?
Thanks in advance
As I understand you want to implement iOS native sharing functionality. Here is an example of implementation:
- (void)shareButtonPressed {
// 1
// If you want to use UIImage, make sure you have image with that name, otherwise it will crash.
NSArray *activityItems = #[#"Message to share", [UIImage imageNamed:#"imageToShare"]];
// 2
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
// 3
activityViewController.excludedActivityTypes = #[UIActivityTypeCopyToPasteboard, UIActivityTypeAirDrop, UIActivityTypeAssignToContact, UIActivityTypeAddToReadingList, UIActivityTypePrint, UIActivityTypeSaveToCameraRoll, UIActivityTypeMessage, UIActivityTypeMail];
// 4
[activityViewController setCompletionHandler:^(__unused NSString *activityType, __unused BOOL completed){
// Custom completion implementation
}];
[self presentViewController:activityViewController animated:YES completion:NULL];
}
Description:
Prepare activity items which you want to share such string, image, URL.
Initialize activity view controller with the items you want to share + custom activities (only if needed). Custom activities means that you will create your own buttons using UIActivity with own actions, images, titles (more info here). For example, implement sharing to a third party app which does not have share extension.
Here you can specify excluded activity types. In this example I have removed everything such as copy, airdrop and etc.
In completion block you can see which activityType was selected and whether user cancelled or not.
More information on UIActivityViewController can be found here.
Regarding second part of your question about UIBarButtonItem. UIBarButtonItem can be initialised with custom title using this:
UIBarButtonItem *shareButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Share" style:UIBarButtonItemStylePlain target:self action:#selector(shareButtonPressed)];
self.navigationItem.rightBarButtonItem = shareButtonItem;
Be aware that UIBarButtonItem has UIBarButtonItemStyle which you can change. UIBarButtonItemStylePlain (will create a button with a regular font) and UIBarButtonItemStyleDone (will create a button with a bold font).
The Photos app in iOS 7 allows you to select multiple photos, tap "Share" and be presented with a document interaction controller with the appropriate options for multiple items.
The Camera app goes one further and even updates the document interaction controller's options in real time as you select and deselect photos.
However, the UIDocumentInteractionController class seems only to allow for a single URL parameter.
Is it possible to do what the Photos and Camera apps do using public API?
- (void)showShareDialog
{
UIImage *image = [UIImage imageWithCGImage:self.imgView.image.CGImage];
NSArray* dataToShare = #[image, image2, image3]; // ...or whatever pieces of data you want to share.
UIActivityViewController* activityViewController =
[[UIActivityViewController alloc] initWithActivityItems:dataToShare
applicationActivities:nil];
[self presentViewController:activityViewController animated:YES completion:^{
}];
}
I think this should help
Store the URLs of the selected items in an array. You can change the actions displayed depending upon the number of elements in the array. After the user makes his/her selection, you can loop through the URLs and apply the selected action.
This question already has answers here:
Different data for sharing providers in UIActivityViewController
(4 answers)
Closed 9 years ago.
Hope everyone is aware of iOS 6 contains new style of ActionSheet (UIActivityViewController). The UIActivityViewController can be initiated with the paramentes like string, url, image etc. Below is the code snippet for that (where items is an array with string and url params).
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
But, is there any way that we can assign different parameters when we select different share options like Mail, Facebook or Twitter?
One method is we can implement UIActivityItemSource, where we need to implement the source methods
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
which always returns a string value. But I need to pass an Array, so that I can assign various parameters like URL, image and a title.
Any idea how we can achieve this?
You can not change anything for the built in iOS UIActivityViewController items like Mail, Facebook and Twitter. In order to implement custom actions for items in your UIActivityViewController you must create a custom subclass of UIActivity for each custom activity you want. Here is an example:
- (UIActivityViewController *)getActivityViewController {
MyFeedbackActivity *feedbackActivity = [[MyFeedbackActivity alloc] init];
MyFacebookActivity *facebookActivity = [[MyFacebookActivity alloc] init];
MyMailActivity *mailActivity = [[MyMailActivity alloc] init];
NSArray *applicationActivities = #[feedbackActivity, facebookActivity, mailActivity];
NSArray *activitiesItems = #[#"A string to be used for MyFeedbackActivity", #"A string to be used for MyFacebookActivity", #"A string to be used for MyMailActivity"];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:activitiesItems applicationActivities:applicationActivities];
// Removed un-needed activities
activityVC.excludedActivityTypes = [[NSArray alloc] initWithObjects:
UIActivityTypeCopyToPasteboard,
UIActivityTypePostToWeibo,
UIActivityTypePostToFacebook,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeCopyToPasteboard,
UIActivityTypeMail,
UIActivityTypeMessage,
UIActivityTypeAssignToContact,
nil];
return activityVC;
}
A very limited example of a subclassed UIActivity with documentation on the methods that you will be interested in overriding to handle your custom data/actions.
#import "MyFeedbackActivity.h"
#implementation MyFeedbackActivity
- (NSString *)activityType {
return #"MyFeedbackActivity";
}
- (NSString *)activityTitle {
return #"Feedback";
}
- (UIImage *)activityImage {
return [UIImage imageNamed:#"feedback"];
}
- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
return YES;
}
- (UIViewController *)activityViewController {
/**
* DESCRIPTION:
* Returns the view controller to present to the user.
* Subclasses that provide additional UI using a view controller can override this method to return that view controller. If this method returns a valid object, the system presents the returned view controller modally instead of calling the performActivity method.
* Your custom view controller should provide a view with your custom UI and should handle any user interactions inside those views. Upon completing the activity, do not dismiss the view controller yourself. Instead, call the activityDidFinish: method and let the system dismiss it for you.
*/
}
- (void)prepareWithActivityItems:(NSArray *)activityItems {
/**
* DESCRIPTION:
* Prepares your service to act on the specified data.
* The default implementation of this method does nothing. This method is called after the user has selected your service but before your service is asked to perform its action. Subclasses should override this method and use it to store a reference to the data items in the activityItems parameter. In addition, if the implementation of your service requires displaying additional UI to the user, you can use this method to prepare your view controller object and make it available from the activityViewController method.
*/
}
-(void)performActivity {
/**
* DESCRIPTION:
* Performs the service when no custom view controller is provided.
* The default implementation of this method does nothing. If your service does not provide any custom UI using the activityViewController method, override this method and use it to perform the activity. Your activity must operate on the data items received in the prepareWithActivityItems: method.
* This method is called on your app’s main thread. If your app can complete the activity quickly on the main thread, do so and call the activityDidFinish: method when it is done. If performing the activity might take some time, use this method to start the work in the background and then exit without calling activityDidFinish: from this method. Instead, call activityDidFinish: from your background thread after the actual work has been completed.
*/
}
#end
I have implemented UIActivityViewController within my app and can successfully share both strings and images. However, I notice that when you share an image within the iOS Photos app, there are some services that do not appear in my app. Namely Print, Use as Wallpaper, and Assign To Contact, and Photo Stream. My app is able to use Mail, Message, Facebook, Twitter, and Copy just fine.
I am thinking that either:
1.) These extra services have been implemented as custom services within the Photos app using UIActivityItemProvider, UIActivityItemSource, etc..
2.) The data that I am providing is not in the correct format to be used with these services.
I have read through the documentation a few times, but don't seem to see anything about it.
Edit: Showing code as requested:
#define SM_SHARE_IMAGE_AND_STRING 1
-(void)actionToolbarViewControllerUserTappedShareButton:(SMActionToolbarViewController*)sender{
// Reposition anchor view for UIPopoverController to point at
[self repositionAnchorViewToButtonFrame:self.actionToolbarViewController.shareButtonFrame];
// Asynch download of image
[SMUtility downloadAsset:self.selectedAsset completion:^(UIImage *image) {
// Create image source
SMActivitySource *activityImageSource = [[SMActivitySource alloc]initWithImage:image];
#if defined(SM_SHARE_IMAGE_AND_STRING)
// Create string source
NSString *assetsString = [SMUtility assetsString:[NSArray arrayWithObject:self.selectedAsset]];
SMActivitySource *activityStringSource = [[SMActivitySource alloc]initWithString:assetsString];
// Present UIActiviyViewController within an UIPopoverController
NSArray *items = [#[activityImageSource, activityStringSource]mutableCopy];
#else
NSArray *items = [#[activityImageSource]mutableCopy];
#endif
UIActivityViewController *activityViewController = [[UIActivityViewController alloc]initWithActivityItems:items applicationActivities:nil];
[activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed){
[SMMixPanel eventSharePhotoMethod:#"Share"];
}];
self.buttonPopoverController = [[UIPopoverController alloc] initWithContentViewController:activityViewController];
[self.buttonPopoverController presentPopoverFromRect:self.anchorView.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}];
}
The Print, and Assign To Contact activities are standard activities shown by the UIActivityViewController as long as you provide the proper data.
You must provide a UIImage for the Assign To Contact activity. See the docs for UIActivityTypeAssignToContact. See the docs for UIActivityTypePrint for details on what it accepts.
The "Use As Wallpaper" seems to be a custom activity shown only in the Photos app.