In my app I am using TTOpenInAppActivity to insert "Open in" action inside UIActivityController.
Inside it works like this:
Some view controller presents UIActivityController with TTOpenInActivity already built in.
-(void)openWithAction
{
NSURL *fileURL = SOME_URL;
CGRect rect = SOME_RECT;
TTOpenInAppActivity *openInAppActivity = [[TTOpenInAppActivity alloc] initWithView:self.view andRect:rect];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[fileURL] applicationActivities:#[openInAppActivity]];
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
// Store reference to superview (UIActionSheet) to allow dismissal
openInAppActivity.superViewController = activityViewController;
// Show UIActivityViewController
[self presentViewController:activityViewController animated:YES completion:NULL];
} else {
// code for iPad, irrelevant
}
}
When user taps "Open in" button, the following method is triggered:
- (void)performActivity
{
if(!self.superViewController){
[self activityDidFinish:YES];
return;
}
// Dismiss activity view
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
// iPhone dismiss UIActivityViewController
[self.superViewController dismissViewControllerAnimated:YES completion:^(void){
if (self.fileURLs.count > 1) {
[self openSelectFileActionSheet];
}
else {
// Open UIDocumentInteractionController
[self openDocumentInteractionControllerWithFileURL:self.fileURLs.lastObject];
}
}];
} else {
// code for iPad, irrelevant
}
}
}
As the app is for iPhone only, this piece of code should be executed:
[self.superViewController dismissViewControllerAnimated:YES completion:^(void){
if (self.fileURLs.count > 1) {
[self openSelectFileActionSheet];
}
else {
// Open UIDocumentInteractionController
[self openDocumentInteractionControllerWithFileURL:self.fileURLs.lastObject];
}
}];
In iOS7 everything works fine. In iOS8 UIActivityController is dismissed and then nothing happens.
While debugging I did manage to detect that in iOS8 completion handler is never called.
Please, help me find out the reason for this behavior and make it work as it should.
Thank you in advance.
In iOS 8, when you tap on "Open in", UIActivityViewController is dismissed automatically. So, when you call self.superViewController dismissViewControllerAnimated:completion:, viewController was already dismissed and method do nothing (so completion not called).
Related
I am using custom camera with the help of UIImagePickerController. I am subclassing the UIImagePickerController class and using without present/dismiss. We are just opening the customise camera view and taking picture. After sometime by clicking camera takepicture method gets called and app is getting crash. No delegate method called during this. My code is this:
-(void)viewDidLoad
{
if([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear] && self.camType==2)
{
self.sourceType=UIImagePickerControllerSourceTypeCamera;
self.cameraDevice=UIImagePickerControllerCameraDeviceRear;
self.showsCameraControls = NO;
self.wantsFullScreenLayout=NO;
self.navigationBar.hidden=NO;
self.cameraOverlayView = mainView;
}
}
else
{
self.navigationBar.hidden=YES;
self.sourceType=UIImagePickerControllerSourceTypePhotoLibrary;
[notAllowBtn setHidden:TRUE];
[cmView setHidden:TRUE];
}
self.delegate=self;
[self.view addSubview:cmView];
}
-(void)cameraTakePic {
if([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]) {
[self takePicture];
}
}
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info{
if (![info objectForKey:#"UIImagePickerControllerOriginalImage"]) {
NSArray *arr=[[appDel navController] viewControllers];
id obj=[arr lastObject];
UIViewController *objContr=((UIViewController *)obj);
objContr.navigationController.navigationBar.userInteractionEnabled = YES;
[clickBtn setEnabled:YES];
return;
}
UIImage* image = nil;
UIImage *imageTemp = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
}
From the Apple UIImagePickerController class reference:
The UIImagePickerController class supports portrait mode only. This
class is intended to be used as-is and does not support subclassing.
The view hierarchy for this class is private and must not be modified,
with one exception. You can assign a custom view to the
cameraOverlayView property and use that view to present additional
information or manage the interactions between the camera interface
and your code.
You shouldn't subclass the UIImagePickerController class, instead you should use AVFoundation and make your custom capture methods.
I've just implemented a commenting feature in my app. Ideally when someone leaves a comment, I'd like all notified people be able to swipe the push notification and open the app on that post.
I assume you want to open the concerned page directly. There are many ways to go about this, and it depends on how your app is laid out.
If you want to open an inner page upon app launch, you can programmatically trigger the segues that the user would otherwise need to make manually. (this ensures the back/home buttons work as opposed to loading the desired page directly).
Here's an excerpt from one of my own code, your use case may not be the same, but this is all i can do unless you give us more details.
- (BOOL) navigateToRespectiveSectionforPushNot:(NSDictionary*)pushNot
{
id rootVC = self.window.rootViewController;
NSLog(#"ROOT CLASS : %#", [rootVC class]);
if ([rootVC isKindOfClass:[SWRevealViewController class]])
{
NSLog(#"Root Class looking good... mission Navigate!!");
SWRevealViewController *homeVC = (SWRevealViewController*) rootVC;
NSString *category = [[pushNot objectForKey:pushPayloadKeyaps] objectForKey:pushPayloadKeyCategory];
NSString *subCat = [[pushNot objectForKey:pushPayloadKeyaps] objectForKey:pushPayloadKeySubCategory];
NSLog(#"category : %# , subcat : %#",category,subCat);
//The code for the page to which i'm supposed to navigate to is contained in the push notification payload
if ([category isEqualToString:pushCategoryItemChat])
{
[homeVC.rearViewController performSegueWithIdentifier:#"chatPush" sender:nil];
UINavigationController *nc = (UINavigationController*)homeVC.frontViewController;
NSLog(#"FrontView Class : %#",[nc.viewControllers[0] class]);
UITableViewController *tvc = (UITableViewController*)nc.viewControllers[0];
NSDictionary *send = #{chatPushTargetUserId:subCat,chatPushTargetUserName:#"",chatPushTargetUserImage:#""};
[tvc performSegueWithIdentifier:#"seguePushDemoVC" sender:send];
return YES;
}
//communityPush historyPush
else if ([category isEqualToString:pushCategoryItemCommunity])
{
if ([subCat isEqualToString:pushSubCatItemNewRequest])
{
[homeVC.rearViewController performSegueWithIdentifier:#"communityPush" sender:nil];
return YES;
}
else if ([subCat isEqualToString:pushSubCatItemAccepted])
{
[homeVC.rearViewController performSegueWithIdentifier:#"communityPush" sender:nil];
return YES;
}
}
else if ([category isEqualToString:pushCategoryItemHistory])
{
[homeVC.rearViewController performSegueWithIdentifier:#"historyPush" sender:nil];
return YES;
}
}
else
{
UIAlertView *whoa = [[UIAlertView alloc] initWithTitle:#"WHOA!!" message:#" That wasn't supposed to happen. You are not even logged in. Call 911..." delegate:nil cancelButtonTitle:#"mmKay.." otherButtonTitles:nil, nil];
[whoa show];
}
return NO;
}
I hope the code is self explanatory. cheers
Say you want to do something once user finish. What do you do?
It doesn't have a delegate. What to do once a present view controller is dismissed?
In the Apple documentation you'll find that SLComposeViewController has a completion handler property instead of a delegate. You just need to set that property using the setCompletionHandler method. Then you use the constant SLComposeViewControllerResult to recover whether the post was posted or canceled and take action accordingly.
-(void) shareToFacebook {
//1. Set link and image
NSString *appLink = #"https://itunes.apple.com/app/id989793966";
UIImage *twitterImage = [UIImage imageNamed:#"TF_400x400.png"];
//2. Check if we can share
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
//3. Compose the share view controller
SLComposeViewController *FBViewController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[FBViewController addURL:[NSURL URLWithString:appLink]];
[FBViewController addImage:twitterImage];
//4 Set completion handler and define actions to take
[FBViewController setCompletionHandler:^(SLComposeViewControllerResult result)
{
if (result == SLComposeViewControllerResultCancelled) {
[self addEmptyScreenButtonTargets];
} else if (result == SLComposeViewControllerResultDone) {
//Unlock words; show thank you screen
[NewCardManager unlockWordsForPackage:4];
[self openFBThankYouScreen];
}
}];
//5. Call to modally present the share controller
[self presentViewController:FBViewController animated:YES completion:nil];
}
}
I am using UIActivityViewController to present sharing options and I want to display another view controller when the UIActivityViewController is dismissed by the user or when the animation that follows "activityDidFinish:(bool)completed" gets over. When I try to present the other controller in the completion handler of the UIActivityViewController, I get the following warning and the second VC does not get displayed at all!
Attempt to present <_UIViewController: 0x1e16f020> on <###> while a presentation is in progress!
UIActivityViewController activityVC = [[UIActivityViewController alloc]initWithActivityItems:selectedAssetsURL applicationActivities:nil];
[activityVC setCompletionHandler:^(NSString *activityType, BOOL completed) {
NSLog(#"completed");
//Present another VC
}];
The question is, how to know when the UIActivityViewController disappears from the screen? Even the -ViewDidAppear method of the view controller which presents the UIActivityViewController does not get fired!
In this link there's good information about how the UIActivityViewController works:
http://www.apeth.com/iOSBook/ch26.html#_activity_view
Basically you can subclass the UIActivityViewController into another class and implement a method to know when it has been dissmissed.
UIActivityViewController* avc =
[[UIActivityViewController alloc]
initWithActivityItems:#[myCoolString]
applicationActivities:#[[MyCoolActivity new]]];
Here’s the preparatory part of the implementation of MyCoolActivity:
-(NSString *)activityType {
return #"com.neuburg.matt.coolActivity"; // make up your own unique string
}
-(NSString *)activityTitle {
return #"Be Cool";
}
-(UIImage *)activityImage {
return self.image; // prepared beforehand
}
-(BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
for (id obj in activityItems) {
if ([obj isKindOfClass: [NSString class]])
return YES;
}
return NO;
}
-(void)prepareWithActivityItems:(NSArray *)activityItems {
self.items = activityItems;
}
To perform the activity, we implement one of two methods:
-(void)performActivity {
// ... do something with self.items here ...
[self activityDidFinish:YES];
}
-(UIViewController *)activityViewController {
MustacheViewController* mvc = [MustacheViewController new];
mvc.activity = self;
mvc.items = self.items;
return mvc;
}
And then MustacheViewController would have code like this:
- (IBAction)doCancel:(id)sender {
[self.activity activityDidFinish:NO];
}
- (IBAction)doDone:(id)sender {
[self.activity activityDidFinish:YES];
}
I want to make a "terms and conditions" screen that pops up the very first time that app is opened. On this view I would add a button that says "agree," and upon clicking it the code would execute:
[self dismissViewControllerAnimated:YES completion:nil];
...and would go to the first view of the app.
I am currently using a Tab Bar Controller that has 4 ViewControllers. So basically, I just need to have some method in viewWillAppear on my first ViewController that checks for an NSUserDefault key:value. The first time the app opens, it will be zero. After they click agree, I'll set it to 1 and the bit of code would never execute again.
Can you please offer some code to accomplish the task of routing the view from the firstViewController's view to this alternate view controller upon loading the app?
Thanks!
In the viewWillAppear method in your FirstViewController, check NSUserDefaults then present your TermsViewController. After user click agree in TermsViewController, set NSUserDefaults then call
[self.presentingViewController dismissModalViewControllerAnimated:YES]
The use of the popover window can get complicated. Try something like the following if you have little experience with Objective-C.
- (void)viewDidLoad {
if ([termsvalue == 0]) {
NSString *msg = [NSString stringWithFormat:#"Do you agree with the terms of use?"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"- Confirmation -"
message:msg
delegate:self
cancelButtonTitle:#"Disagree"
otherButtonTitles:#"I agree", nil];
[alert setTag:100];
[alert show];
}
}
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView { // Validation
if ([alertView tag] == 100) {
return YES;
}
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { // Go
if ([alertView tag] == 100) {
if (buttonIndex == 1) {
// The user has agreed
}
}
}