Double tap outside action sheet popover presented using UIAlertController leads to going back to parent view in ios8 xcode 6 beta 5 - objective-c

I have a action sheet which i am presenting using UIAlertcontroller in ios8 (xcode 6 beta 5).
I am using UIAlertcontroller because UIActionsheet ( which is deprecated in iOS 8 ) was not working properly in ios8, on click of any option in the actionsheet leaded me back to the parent view.
Now I am facing one issue in UIAlertcontroller too, double tap outside the action sheet popover is leading me back to the previous parent view.
Following is my code snippet:
UIAlertController *actionSheetIos8;
actionSheetIos8 = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
NSArray *buttonsArray = [self returnMoreArray];
int startY = 10;
for (int i = 0; i < [buttonsArray count]; i++) {
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:[buttonsArray objectAtIndex:i] style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
NSString *newStr = [buttonsArray objectAtIndex:i];
newStr = [[newStr lowercaseString] stringByReplacingOccurrencesOfString:#" " withString:#"_"];
}];
[actionSheetIos8 addAction:defaultAction];
}
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
}];
[actionSheetIos8 setModalPresentationStyle:UIModalPresentationPopover];
UIPopoverPresentationController *popPresenter = [actionSheetIos8
popoverPresentationController];
popPresenter.sourceView = sender;
popPresenter.sourceRect = [sender frame];
dispatch_async(dispatch_get_main_queue(), ^ {
[self presentViewController:actionSheetIos8 animated:YES completion:nil];
});

The following solution worked for me in my popover presentation controller scenario; I suspect the same bug underlies your situation:
Set a delegate (conforms to UIPopoverPresentationControllerDelegate protocol) on your UIPopoverPresentationController.
Implement the delegate method popoverPresentationControllerShouldDismissPopover:.
For example:
/**
The presence of this delegate callback inhibits the popover presentation controller
from mistakenly calling 'dismissViewControllerAnimated:completion:' on us twice.
*/
- (BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController;
{
NSLog(#"delegate method called asking permission to dismiss popover");
return YES;
}
Here's more context, where I'm setting up my popover presentation controller with a presented controller and a delegate:
// Set modal presentation style and issue the presentViewController:animated:completion:
// call before retrieving popover presentation controller created for us, as suggested
// in the API documentation that is more recent than the sample code from the
// WWDC2014 slides in Session 228:
presentedController.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:presentedController animated:YES completion:nil];
// Now we can retrieve the popover presentation controller and configure it:
UIPopoverPresentationController *popPC = presentedController.popoverPresentationController;
popPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
CGRect popoverRect = cell.infoButton.bounds; // Assume 'cell' exists; it's an object of mine with an 'infoButton' view.
popPC.sourceView = cell.infoButton; // has to be provided along with sourceRect
popPC.sourceRect = popoverRect; // has to be provided along with sourceView
popPC.delegate = self; // or whomever you set to be your popover presentation controller delegate.

Related

Using dismissViewController with UIAlertController

I'm updating an Objective-C application in iOS and since UIAlertView is deprecated I'm using UIAlertController with UIAlertAction for the OK and Cancel buttons. So I have the following function for the back button but I don't know how to handle the OK and Cancel buttons since the OK should let you go back to the previous screen and the Cancel should let you stay in the same screen. The following is my code so far.
- (void)backAction:(id)sender
{
//do your saving and such here
if ([doneBtn isEnabled])
{
//CHANGE 2018
UIAlertController *alert = [UIAlertController alertControllerWithTitle: #"Alert" message:#"Signature will be lost. Do you want to continue?." preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle: #"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
//should go to the previous scree.
//[alert dismissViewControllerAnimated:TRUE completion:nil]; //I'm not sure if this only hides the alert or hides the entire screen
}];
UIAlertAction *cancel = [UIAlertAction actionWithTitle: #"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
//should stay in the same screen
[alert dismissViewControllerAnimated:TRUE completion:nil]; //the same doubt
}];
[alert addAction: ok];
[alert addAction: cancel];
[self presentViewController:alert animated:YES completion:nil];
//UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"Alert" message:#"Signature will be lost. Do you want to continue?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok",nil];
//[alert show];
}
The statement [alert dismissViewControllerAnimated:TRUE completion:nil] will only dismiss the alert, because it's the top view controller on the screen.
So, you don't need to do anything else for your Cancel action.
For your Ok action, you have multiple actions to go back to the previous screen :
If your view controller is a UIViewController alone, simply call [self dismissViewControllerAnimated:TRUE completion:nil]`
If the view controller is embedded into a navigation controller, call [self.navigationController popToRootViewControllerAnimated:YES].
You also can use an unwind segue to the view controller you want to go back too.
I hope it will help you! ;)
It is not necessary to call [alert dismissViewControllerAnimated:TRUE completion:nil];, when you tap on one of the button the alert is dismissed.
In the completion of your ok button if your viewController is in embedded in a navigationController you can use [self.navigationController popToRootViewControllerAnimated:YES];.
The above answers are correct. I actually wanted to comment but I don't have enough reputation.
You should try to take a look at this thread to get a better understanding of dismissing a viewController.
Dismissing a Presented View Controller
Try this, hope this will solve your issue.
UIAlertController * alert=[UIAlertController alertControllerWithTitle:#"Title"
message:#"Message"preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* okButton = [UIAlertAction
actionWithTitle:#"Ok, please"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
[self okButtonPressed];
}];
UIAlertAction* cancelButton = [UIAlertAction
actionWithTitle:#"No, thanks"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
[self cancelButtonPressed];
}];
[alert addAction:okButton];
[alert addAction:cancelButton];
[self presentViewController:alert animated:YES completion:nil];
Now Dismiss the viewcontroller.
- (void)cancelButtonPressed{
// Write your implementation for Cancel button here.
}
- (void)okButtonPressed{
//Write your implementation for Ok button here
}

Application tried to present modally an active controller, why this code is crashing, knows anything about it?

UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:#"Select Language"
message:#""
preferredStyle:UIAlertControllerStyleActionSheet];
//We add buttons to the alert controller by creating UIAlertActions:
for (int j =0 ; j<val.count; j++)
{
NSString *titleString = val[j];
UIAlertAction * action = [UIAlertAction actionWithTitle:titleString style:UIAlertActionStyleDefault handler:^(UIAlertAction * action)
{
}];
[alertController addAction:action];
[self presentViewController:alertController animated:YES completion:nil];
You should only present the alert controller once. Move it out of your loop, and it should work.

UIPopoverPresentationController can not be dismissed on iPhone

I'm implementing a CABTMIDICentralViewController (Apple's pre-fab BTLE MIDI configuration panel). The code below is Apple's sample code - unmodified.
It works perfectly on iPad, but on iPhone/iPod it results in an uncloseable fullscreen view. The code clearly creates a Done button, but it isn't shown on the devices.
The common answer is "you need a UINavigationController", but there is one being made in this code. So I'm not sure what else is missing?
- (void)doneAction:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)configureCentral:(id)sender
{
CABTMIDICentralViewController *viewController [CABTMIDICentralViewController new];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
// this will present a view controller as a popover in iPad and modal VC on iPhone
viewController.navigationItem.rightBarButtonItem =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:#selector(doneAction:)];
navController.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popC = navController.popoverPresentationController;
popC.permittedArrowDirections = UIPopoverArrowDirectionAny;
popC.sourceRect = [sender frame];
UIButton *button = (UIButton *)sender;
popC.sourceView = button.superview;
[self presentViewController:navController animated:YES completion:nil];
}
You will have to implement the UIPopoverPresentationControllerDelegate to view popovers in iPhones. By default it will be presented in the style of an already presented view controller.
Add this piece of code to present the controller as popover
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(nonnull UITraitCollection *)traitCollection {
return UIModalPresentationNone;
}

UITabBarController Subviews Don't Appear Weirdness

I have a curious issue with an iOS 9/ObjC app I am writing using a 4 tab format. The "main" ViewController has several subviews with controls and an image. When the user taps the image a PickerView pops up and it is dismissed with another tap on the image. The other tabbed ViewControllers lead to simple views. It was all put together with IB, except for a single subview on the "main" view where I do some Quartz animation drawing superimposed on the image view there.
If I stay on and interact with just the "main" view, all works exactly as desired. The PickerView appears and disappears as designed. Tabbing to another ViewController, then back to the "main" View leads to the problem: A tap on the image view fails to pop up the Picker. The tap is recognized in the Quartz layer, fires a Notification event which is picked up in the picked up in the main view controller which in turn adds the picker subview, brings it to the front and enables interaction just as when it works properly, but the picker never appears, even though the Debugger shows it successfully added to the subview array.
Even stranger, if I tab off the main to any other tab view, then back to main, the picker now appears again as it should. This sequence is completely repeatable - tab once off the main, and the picker doesn't visualize, tab again and then back to main and the picker works.
Any thoughts on where to start looking? Thanks
Here's some code (but I'm not sure where the problem is)
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.picker = [[UIPickerView alloc] init];
self.picker.datasource = self;
self.picker.delegate = self;
float screenWidth = [UIScreen mainScreen].bounds.size.width;
float pickerWidth = screenWidth * 3 / 4;
// Calculate the starting x coordinate.
float xPoint = screenWidth / 2 - pickerWidth / 2;
[self.Picker setFrame: CGRectMake(xPoint, 50.0f, pickerWidth, 250.0f)];
[self.Picker setClipsToBounds:NO];
[self.Picker setBackgroundColor:[UIColor whiteColor]];
self.Picker.showsSelectionIndicator = YES;
self.Picker.userInteractionEnabled = YES;
.
.
.
UIImage *base = [UIImage imageNamed:#"Base"];
self.baseAView = [[UIImageView alloc] initWithFrame:imFrame];
[self.baseView setImage:base];
[self.view addSubview:_baseView];
self.GView = [[GView alloc] initWithFrame:imFrame];
self.GView.backgroundColor = [UIColor clearColor];
[self.view addSubview:_GView];
}
-(void) viewDidAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doSin) name:#"touchP" object:nil];
}
- (void) doSin {
// user hits GView, draw Picker if not in View Hierarchy, if in Hierarch, grab value and resign
NSArray *subViews = [self.view subviews];
__block NSInteger foundIndex = NSNotFound;
[subViews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[UIPickerView class]]) {
foundIndex = idx;
// stop the enumeration
*stop = YES;
}
}];
if (foundIndex != NSNotFound) {
// Found the UIPickerView in subviews, so grab value & remove from screen
[self.view.subviews[foundIndex] removeFromSuperview];
} else {
// not in hierarchy, so put it up on screen
[self.view addSubview:self.Picker];
[self.view bringSubviewToFront:self.Picker];
self.view.userInteractionEnabled = YES;
}
}

Done button in game center leader-board doesn't work

When i press done button in leaderboard view, it doesn't do anything and leaderboard is still visible.
here is code:
GKGameCenterViewController *gcViewController = [[GKGameCenterViewController alloc] init];
gcViewController.gameCenterDelegate = self;
[gcViewController setDelegate:self ];
if (shouldShowLeaderboard) {
gcViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
gcViewController.leaderboardIdentifier = currentLeaderBoard;
}
else{
gcViewController.viewState = GKGameCenterViewControllerStateAchievements;
}
[self presentViewController:gcViewController animated:YES completion:nil];**
you must add the function to dismiss the view controller (to delegate)
-(void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController{
[gameCenterViewController dismissViewControllerAnimated:YES completion:nil];
}
What worked for me was to add GKGameCenterControllerDelegate to the protocol list.