I am using UIDocumentInteractionController's presentPreviewAnimated method to preview document. It works fine. But I wish to disable the action button while in the preview mode. I have the following two delegated methods to return NO. But these two methods never got called at all. The other delegated methods work fine. Any suggestion?
-(BOOL)documentInteractionController:(UIDocumentInteractionController *)controller canPerformAction:(SEL)action {
NSLog(#"canPerformAction");
return NO;
}
and
-(BOOL)documentInteractionController:(UIDocumentInteractionController *)controller performAction:(SEL)action {
NSLog(#"performAction");
return NO;
}
I finally switched to use the QLPreviewController class. Where you can subclass it and make the action button gone away. (With the help from the answer by rbrown of this SO.
Related
I want to disable the swipe back gesture that allows users to go back.
I've tried:
if ([self.navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
and all sorts of other code I've found online, but none of them work at all? I'm using iOS 8.3.
Is there a way to disable this all together? Thank you.
First of all as #Fogmeister said in comments, you need to have a very good reason to remove this native function to your app.
Now, having said this, the solution:
SwipeBack and JRSwizzle (Needed by SwipeBack)
You can use this in a single ViewController in which you want to remove the functionality or you create a custom class for UINavigationController and you use it there:
#import <SwipeBack/SwipeBack.h>
- (void)viewWillAppear:(BOOL)animated
{
//For a single viewcontroller
self.navigationController.swipeBackEnabled = NO;
//If you are in the custom class
self.swipeBackEnabled = NO;
}
Hope it helps.
I have category for supporting portrait only when vc is presented over another vc. To use that, normally we use import UINavigationController+Portrait.h. However, when I try to call in another vc, although I haven't import yet, supportedInterfaceOrientations is always calling in my category. May I know what is wrong?
#import "UINavigationController+Portrait.h"
#implementation UINavigationController (Portrait)
- (BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
//ios4 and ios5
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return NO;
}
When you create a category in Objective-C, any methods you define will affect every instance of the class the category is created for – it doesn't only take effect in files where you import the category.
The Objective-C runtime is dynamic, meaning that when you call a method, it will look up the method on the appropriate class and call it. When you override that method via a category, even without importing it anywhere, the runtime will look for the right method to call and find that the one defined in the category is available and instead call that.
That's the reason that all instances of UIViewController now find your category's method instead.
Because of this, overriding methods in categories is pretty dangerous. Instead, the right thing to do is to subclass a class and override its methods there. If that isn't an option, method swizzling is another way of doing it, but that also has its own risks.
I have a class A which has delegates . The delegates are being implemented in another class B.
In B I have a text field , which I am trying to make hidden when the delegate is called.
- (void) didRecieveResponseDelegate : (BOOL) status{
textField.hidden = YES;
}
But the textField doesnt get hidden. I've noticed none of the view related changes work inside the delegate including removing of child view controllers. What's the problem and how do I fix it ?
EDIT : B is a child view controller of another view controller
Try this,
- (void) didRecieveResponseDelegate : (BOOL) status{
dispatch_async(dispatch_get_main_queue(), ^{
textField.hidden = YES;
});
}
Does the method get called? (Breakpoint or NSLog to prove it).
Why are you using instance variables with leading underscore? That leads to bugs and confusion as well as distrust in your code.
Is textField actually set or is it nil? NSLog to prove it.
Fix spelling errors in method names. Quite possible that didReceiveResponseDelegate is called instead of didRecieveResponseDelegate.
Make sure you don't make UI calls from a background thread.
I have a UIActivity subclass that creates its own activityViewController:
- (UIViewController *)activityViewController {
WSLInProgressViewController* progressView = [[[WSLInProgressViewController alloc] init] autorelease];
progressView.message = [NSString stringWithFormat:NSLocalizedString(#"Posting to %#...",#"Posting to..."),
self.activityType];
return progressView;
}
I've add a full repro on GitHub.
According to the documentation, you aren't supposed to dismiss this manually. Instead, the OS does that when you call activityDidFinish:. This works fine when ran on an iPhone.
When I say "works," this is the sequence of events that I'm expecting (and see on the iPhone):
Display the UIActivityViewController
User presses my custom activity
My view controller appears
I call activityDidFinish:
My custom view controller is dismissed
The UIActivityViewController is also dismissed
However, when I run this same code on the iPad Simulator -- the only difference being that I put the UIActivityViewController in a popup, as the documentation says you should -- the activityViewController never dismisses.
As I say, this is code wo/the popUP works on the iPhone and I have stepped through the code so I know that activityDidFinish: is getting called.
I found this Radar talking about the same problem in iOS6 beta 3, but it seems such fundamental functionality that I suspect a bug in my code rather than OS (also note that it works correctly with the Twitter and Facebook functionality!).
Am I missing something? Do I need to do something special in the activityViewController when it's run in a UIPopoverViewController? Is the "flow" supposed to be different on the iPad?
The automatic dismissal only appears to happen when your 'activity' controller is directly presented, not wrapped in anything. So just before showing the popup it's wrapped in, add a completion handler
activity.completionHandler = ^(NSString *activityType, BOOL completed){
[self.popup dismissPopoverAnimated:YES];
};
and you'll be good.
I see the question is quite old, but we've been debugging the same view-controller-not-dismissing issue here and I hope my answer will provide some additional details and a better solution than calling up -dismissPopoverAnimated: manually.
The documentation on the UIActivity is quite sparse and while it hints on the way an implementation should be structured, the question shows it's not so obvious as it could be.
The first thing you should notice is the documentation states you should not be dismissing the view controller manually in anyway. This actually holds true.
What the documentation doesn't say, and what comes as an observable thing when you come across debugging the non-dissmissing-view-controller issue, is iOS will call your -activityViewController method when it needs a reference to the subject view controller. As it turns out, probably only on iPad, iOS doesn't actually store the returned view controller instance anywhere in it's structures and then, when it wants to dismiss the view controller, it merely asks your -activityViewController for the object and then dismisses it. The view controller instantiated in the first call to the method (when it was shown) is thus never dismissed. Ouch. This is the cause of the issue.
How do we properly fix this?
Skimming the UIActivity docs further one may stumble accross the -prepareWithActivityItems: method. The particular hint lies along the following text:
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.
So, the idea is to instantiate your view controller in the -prepareWithActivityItems: method and tackle it into an instance variable. Then merely return the same instance from your -activityViewController method.
Given this, the view controller will be properly hidden after you call the -activityDidFinish: method w/o any further manual intervention.
Bingo.
NB! Digging this a bit further, the -prepareWithActivityItems: should not instantiate a new view controller each time it's called. If you have previously created one, you should merely re-use it. In our case it happily crashed if we didn't.
I hope this helps someone. :)
I had the same problem. It solved for me saving activityViewController as member and return stored controller. Activity return new object and dismiss invoked on new one.
- (UIViewController *)activityViewController {
if (!self.detaisController) {
// create detailsController
}
return self.detailsController;
}
I pass through the UIActivity to another view then call the following...
[myActivity activityDidFinish:YES];
This works on my device as well as in the simulator. Make sure you're not overriding the activityDidFinish method in your UIActivity .m file as I was doing previously. You can see the code i'm using here.
a workaround is to ask the calling ViewController to perform segue to your destination ViewController via - (void)performActivity although Apple does not recommend to do so.
For example:
- (void)performActivity
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
[self.delegate performSomething]; // (delegate is the calling VC)
[self activityDidFinish: YES];
}
}
- (UIViewController *)activityViewController
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
UIViewController* vc=XXX;
return vc;
}
else
{
return nil;
}
}
Do you use storyboards? Maybe in your iPad storyboard, the UIActivityIndicatorView doesn't have a check on "Hides When Stopped"?
Hope it helps!
So I had the same problem, I had a custom UIActivity with a custom activityViewController and when it was presented modally it would not dismiss not matter what I tried. The work around I choose to go with so that the experience remained the same to the user was to still use a custom UIActivity but give that activity a delegate. So in my UIActiviy subclass I have the following:
- (void)performActivity
{
if ([self.delegate respondsToSelector:#selector(showViewController)]) {
[self.delegate showViewController];
}
[self activityDidFinish:YES];
}
- (UIViewController *)activityViewController
{
return nil;
}
Then I make the view controller that shows the UIActivityViewController the delegate and it shows the view controller that you would otherwise show in activityViewController in the delegate method.
what about releasing at the end? Using non-arc project!
[progressView release];
Many Users have the same problem as u do! Another solution is:
UIActivityIndicatorView *progress= [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(125, 50, 30, 30)];
progress.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
[alert addSubview:progress];
[progress startAnimating];
If you are using storyboard be sure that when u click on the activityind. "Hides When Stopped" is clicked!
Hope that helped...
In a UIWebView, I want a certain class div element to display only one custom contextual menu entry. So that I implemented the canPerformAction:: method in the UIWebView delegate like this:
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (self.webView.superview != nil) {
BOOL isMyClass=[[self.webView stringByEvaluatingJavaScriptFromString:#"window.getSelection().getRangeAt(0).startContainer.parentNode.className;"] isEqualToString:#"myClass"];
if (isMyClass) {
if (action == #selector(myAction:)) {
return YES;
} else {
return NO; // should disable any other menu items
}
}
}
return [super canPerformAction:action withSender:sender];
}
The result is quite strange: when the user selects such a myclass div, most menuItems are not displayed (cut: copy: past:...) but select: and selectAll: are still displayed (along with myAction). Under debugger, I notice that these two select/selectAll methods do not fire canPerformAction:: in the delegate... Where are these two method fired?
I think I know why you may be having problems.
I had the same question and similar frustration:
"Why are select: and selectAll: not appearing when stepping through calls to canPerformAction::?"
I then realized that the firstResponder when displaying the UIMenuController was just a container, and that this class had a member that was actually extending the UITextView class. Since the sharedMenuController interacts with the first responder in the Responder chain, implementing canPerformAction in the container skipped select and selectAll because they had already been handled by the textView member (the REAL firstResponder in this situation).
What you should do is find which object is your firstResponder when displaying the UIMenuController, find any responder objects it might own until you find the highest responder on the stack, and implement canPerformAction there.
Good Luck!
Sometimes, when application is used on the iPad device, with no connection to Xcode, the menu correctly displays only the authorized item... Sometimes not... Very erratic behaviour indeed