Sams **Teach Yourself iPad Application development in 24 hour's says I can "display an action sheet in a "nonanimated" fashion, filling a full popover view when it first appears...To do this, you need to show the action sheet with the method
showFromRect:inView:animated
with the "rect" set to the dimensions of the popover, the view set to the popover view controller's view, and "animated" set to false. The display of the action sheet would need to take place when the popover view is first loaded such as in the viewDidLoad method of the popover view controller.
OK, easy.. here's my code in my popover's viewDidLoad method:
- (void)viewDidLoad {
self.contentSizeForViewInPopover=CGSizeMake(400.0,400.0);
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Available Actions" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Destroy" otherButtonTitles:#"Negotiate", #"Compromise", nil];
[actionSheet showFromRect:[self.view bounds] inView:self.view animated:NO];
[actionSheet release];
[super viewDidLoad];
}
But this fails every time at the inView:self.view parameter with the exception:
Invalid parameter not satisfying view != nil
Any ideas?
Note, if I put this exact same code in an IBAction method and trigger it from a button in the popover, it works without a hitch!
One solution is to call the UIActionSheet in viewWillAppear or viewDidAppear: For example:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self showActionSheet];
}
- (void)showActionSheet {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Available Actions" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Destroy" otherButtonTitles:#"Negotiate", #"Compromise", nil];
[actionSheet showFromRect:[self.view bounds] inView:self.view animated:NO];
[actionSheet release];
}
self.view hasn't been instantiated completely yet when this code is called.
I would suggest, as a hacky alternative, to put in a short (.1 seconds or something) NSTimer with your IBAction method as the callback.
Related
I am newbie in iOS development and currently stuck on creating back button. I already placed popViewControllerAnimated method on tapping button, also I test it on debugging mode and back button method is calling but popViewControllerAnimated is not working.
Here is the code.
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake((self.view.frame.size.height-100), 30, 80, 20)];
[backButton setTitle:#"Back" forState:UIControlStateNormal];
[backButton addTarget:self action:#selector(BackButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backButton];
//some piece of code...
}//end of viewDidLoad method
-(void)BackButtonClicked: (id)sender{
[self.navigationController popViewControllerAnimated:YES];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"testing" message:#"some message" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:#"NO", nil];
[alert show];
}
On tapping back button this alert is showing but screen is not going back.
Any help regarding this issue will be highly appreciable.
I called this viewController by writing this code in my previous viewController
PlaceTranslatedDetailsViewController *secondViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"placeTranslatedDetail"];
[self presentViewController:secondViewController animated:YES completion:NULL];
However, this viewController and previous viewController were designed programmatically
If your viewcontroller is not an rootviewcontroller for a uinavigationcontroller than the method popViewControllerAnimated won't work. So you need to have a uinavigationcontroller behind in order to push/pop a viewcontroller.
So in your case you have to use [self dismissViewControllerAnimated:YES completion:nil]; instead of popViewController because you presented modally a view controller.
You are not presenting your view controller as part of a navigation stack, so using popViewControlleranimated: is not going to work.
You need to use
[self dismissViewControllerAnimated:YES completion:NULL];
instead.
use this code:
[self dismissViewControllerAnimated:YES completion:NULL]
A push (via pushViewController or storyboard push segue) will need a call to popViewController
A presented view (via presentVewController or a storyboard modal segue) needs a dismissViewController call.
I'm doing an App with a MKMapView that has a back button the UIView which contain the MKMapView in order to go to main menu, that's ok, but when I want to load again the UIView with the MKMapView my App crash, it doesn't gives any error, just crash and show machine code where it crashed, but it says first: com.apple.CoreLocation.ConnectionClient.0x1e5d5220 and then lot of machine code.
The crash report is here:
I have to add, that the first time I load that UIView it's 100% working.
Thanks for your help.
PS: Why I say dealloc? because I think doing something like dealloc probabbly will fix my problem and will be the same as running the first time.
EDIT1:
My - (void) viewDidLoad; method.
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *response = [self sendPostToURL: #"http://hidden.php"
withPost: #"hidden"];
[self tratarXML: response];
yo = #"Posición actual";
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
[self.mapView setDelegate: self];
[self.mapView setZoomEnabled: NO];
[self.mapView setScrollEnabled: NO];
if ([CLLocationManager locationServicesEnabled])
{
self.locationManager.delegate = self;
self.mapView.showsUserLocation = YES;
[self.mapView setMapType: MKMapTypeStandard];
[self.mapView setUserTrackingMode: MKUserTrackingModeFollowWithHeading animated: NO];
[self.locationManager startUpdatingLocation];
//[self.locationManager startUpdatingHeading];
self.mapView.userLocation.title = yo;
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Debe activar la localización en esta aplicación para funcionar"
delegate:self
cancelButtonTitle:#"Aceptar"
otherButtonTitles:nil, nil];
[alert show];
}
}
EDIT2:
My back button code:
- (IBAction) iniciar: (id)sender
{
if ([iniciar.title isEqualToString:#"Volver"])
{
menuViewController *obj = [[menuViewController alloc] initWithNibName:#"menuViewController" bundle:nil withUser:user];
[self presentViewController:obj animated:YES completion:nil];
}
else
{
// censored
}
I'm using simple *.xib navigator, not storyboard, etc...
EDIT3:
The menu button that load the MKMapView UIView
- (IBAction) TEST: (id)sender
{
mapaViewController *obj = [[mapaViewController alloc] initWithNibName: #"mapaViewController" bundle: nil withUser: user];
[self presentViewController:obj animated:YES completion:nil];
}
There are 3 things that are wrong:
Your back button code should not call a presentViewController but a dismissViewController. Right now you are adding view controller after view controller! When you go back you want to instead get rid of your view controller.
In the back button code, add self.locationManager.delegate = nil;
Similarly, in the back button code, add self.mapView.delegate = nil;
That should do it.
It looks like you're doing a series of presentViewController calls to go from main menu to the map view controller, and then back to the main menu. This is not how it should be done. You probably shouldn't be doing modal transitions at all, but if you do, you should have the main menu dismiss the map view controller, not have the map view controller present another main menu controller.
The better way to do this would be with a navigation controller. Main menu should be the root view controller of a navigation controller, and you would push to go to the map view controller. You will automatically get a back button in the navigation bar, which will take you back (to the same instance) of the main menu controller. No need for any back button code. All this would be much easier to implement in a storyboard.
I've been researching this and it seems that the only way to do this is using UIActionSheet, the question is that my UIActionSheet only covers half of the screen, my code is:
MyViewController *myVC = [[myViewController alloc] init];
UIActionSheet *myActionSheet = [[UIActionSheet alloc] initWithTitle:#"\n\n"
delegate:self
cancelButtonTitle:#"cancel"
destructiveButtonTitle:#"done"
otherButtonTitles:nil];
[myActionSheet addSubview:myVC.view];
[myActionSheet showInView:currentView];
[myActionSheet release];
Also how do I then dismiss this UIActionSheet from my MyViewController? Is there any better solution than this? Here's a screenshot of what I mean by loading half of the screen:
screenshot
Here's a sample project to illustrate my issue.
UIActionSheet will increase or decrease it's height according to the number of UIButtons in it. What you can do is add another view above your view with your desired alpha. And remove it from subview and add in subview according to your requirement i.e. add subview when you are displaying actionsheet and remove when you are dismissing UIActionSheet. I hope this is relevant to your question and it will help you to solve your problem.
The problem is because of the frame size of your TestViewController and method for adding the UIView as a subView of the UIActionSheet.
Make the following changes, and it is dismissing properly !
Implement willPresentActionSheet and addSubView in that method
- (IBAction)pressed:(id)sender
{
UIActionSheet *myActionSheet = [[UIActionSheet alloc] initWithTitle:#"\n\n" delegate:self cancelButtonTitle:#"cancel" destructiveButtonTitle:#"done" otherButtonTitles:nil];
[myActionSheet showInView:self.view];
[myActionSheet release];
}
- (void) willPresentActionSheet:(UIActionSheet *)actionSheet{
TestViewController *myVC = [[TestViewController alloc] init];
[actionSheet addSubview:myVC.view];
}
And in the viewDidLoad of the TestViewController, set
- (void)viewDidLoad
{
self.view.frame = CGRectMake(0,0 , 320, 60);
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
I used a Popover to display image in it. When the user touch a button, the popover appears with a slideshow inside.
I initialize the Popover like this : `
- (IBAction)showPopover:(UIButton *)sender {
myPopover *content = [[myPopover alloc] init];
detailViewPopover = [[UIPopoverController alloc] initWithContentViewController:content];
detailViewPopover.popoverContentSize = CGSizeMake(600., 400.);
detailViewPopover.delegate = self;
[detailViewPopover presentPopoverFromRect:sender.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[content release];
}
`
detailViewPopover is a UIPopoverController, I declare it my .h.
I dismiss the Popover like this : `
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
// If a popover is dismissed, set the last button tapped to nil.
[popoverController release];
}`
When I run my app, it works until I got "-[UIPopoverController release]: message sent to deallocated instance 0x1b29b0" and my apps crashes...
I understand I release too much time my UIPopoverController, but I don't know where. Is my implementation good ?
Thanks for your help
Let me know if you need more information, I will edit the post
You shouldn't release your popoverController here.
You need to call release on detailViewPopover in your current view controllers dealloc method
- (void) dealloc
{
[detailViewPopover release];
[super dealloc];
}
I have a method called -showMoreTools: which is: - (IBAction) showMoreTools:(id)sender {
UIActionSheet *popupQuery = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:#"Close" otherButtonTitles:#"Add Bookmark", #"Add to Home Screen", #"Print", #"Share", nil];
popupQuery.actionSheetStyle = UIActionSheetStyleDefault;
popupQuery.dismiss
[popupQuery showFromBarButtonItem:moreTools animated:YES];
[popupQuery release];
}
When an user taps a UIBarButtonItem it displays that UIActionSheet, but then, if the user wants to close the UIActionSheet without taping the Close button, (taping the UIBarButtonItem, then it displays the UIActionSheet over the first UIActionSheet.
It's possible to implement somehow taping another time the UIBarButtonItem to close the UIActionSheet?
Thank you so much – I'm a newbie in iOS Programming!
In order to dismiss it when you click on the button twice, you need to keep track of the currently displaying ActionSheet. We do this in our iPad app and it works great.
In your class that has the showMoreTools, in the header put:
#interface YourClassHere : NSObject <UIActionSheetDelegate> {
UIActionSheet* actionSheet_; // add this line
}
In the class file, change it to:
-(IBAction) showMoreTools:(id)sender {
// currently displaying actionsheet?
if (actionSheet_) {
[actionSheet_ dismissWithClickedButtonIndex:-1 animated:YES];
actionSheet_ = nil;
return;
}
actionSheet_ = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:#"Close" otherButtonTitles:#"Add Bookmark", #"Add to Home Screen", #"Print", #"Share", nil];
actionSheet_.actionSheetStyle = UIActionSheetStyleDefault;
[popupQuery showFromBarButtonItem:moreTools animated:YES];
[actionSheet_ release]; // yes, release it. we don't retain it and don't need to
}
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
// just set to nil
actionSheet_ = nil;
}
I found another solution to this. The problem is that when using showFromBarButtonItem, the toolbar view is automatically added to the popover's list of passthrough views. You can modify (and clear) the passthrough views when using a UIPopoverController directly, but not when it's presented as part of a UIActionSheet.
Anyway, by using showFromRect, there is no toolbar that the popover can automatically add to its passthrough views. So if you know the (approximate) rectangle where your button bar is, you can use something like:
CGRect buttonRect = CGRectIntersection(toolbar.frame, CGRectMake(0, 0, 60, self.frame.size.height));
[popupQuery showFromRect:buttonRect inView:self animated:YES];
In the above example, my button is on the left hand side of the toolbar.
try by setting the flag(YES/NO)
-(void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
use
- (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
My method is similar to christophercotton's.
In my showActionSheet I check if the actionsheet is visible rather than instantiated:
- (IBAction)showActionSheet:(id)sender
{
if ([self.fullActionSheet isVisible]) {
[self.fullActionSheet dismissWithClickedButtonIndex:-1 animated:NO];
_fullActionSheet = nil;
return;
}
//actionsheet code
}