I read a lot about that. People say it will not autorotate whene its parent is not set to auto rotate. I tried everything but no luck.
I created view-based app (v4.2) with a button that executes this:
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Title" delegate:self cancelButtonTitle:#"Cancel Button" destructiveButtonTitle:#"Destructive Button" otherButtonTitles:#"Other Button 1", nil];
actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;
[actionSheet showInView:self.view];
The root controller is set to auto-rotate. The actionSheet does not. Note that when I rotate the simulator none of the root controller's orientation methods are called. Is there a problem with the delegate? What is wrong?
Well, here's my solution to this problem:
Basically what we do is:
Listen to the rotation event.
Listen to click event.
Dismiss the actionSheet and present it again after the rotation is done. (we need to wait a small delay in order for it to take.
for example:
#interface ViewController ()
{
UIActionSheet *_sheet;
BOOL _isClicked;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
- (IBAction)click:(id)sender
{
_isClicked = YES;
[self showActionSheet];
}
- (void)didRotate:(NSNotification *)note
{
[_sheet dismissWithClickedButtonIndex:1 animated:YES];
[self performSelector:#selector(showActionSheet) withObject:nil afterDelay:1.0];
}
- (void)showActionSheet
{
if (!_isClicked) return;
_sheet = [[UIActionSheet alloc] initWithTitle:#"title" delegate:self cancelButtonTitle:#"cancel" destructiveButtonTitle:#"new" otherButtonTitles:#"bla", nil];
[_sheet showInView:self.view];
}
I found that I was running into this problem when I was presenting the action sheet in a delegate method from a subordinate view (which I had pushed using the navigation controller). The problem was that my view was not the current one, the subordinate view was still up at the point where I was trying to show the action sheet.
By changing my code a little bit so that the delegate method made a note of the interaction needed with the user, and deferring the action sheet presentation to this view’s viewDidAppear method, the sheet appeared at the proper time in the logical interface animation, and the auto-rotation problem went away. You might want to see if that helps you.
In other words, the flow became:
Subordinate view called delegate method to report choices the user made when leaving.
Parent view recorded this information for later.
Navigation controller was told to pop off subordinate view.
Parent view’s viewDidLoad: method detected the note made in the delegate method.
Action sheet was presented; rotation was now correct.
Related
I only want to confirm back navigation for one of the the view I have. The specific view is a UICollectionViewController. I know my exact coding in the if statement isn't right. I'm not quite sure how to do it. Fill in the blanks for me?
CollectionViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
BOOL isThisViewACollectionView = YES;
}
-(void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
// back button was pressed. We know this is true because self is no longer
// in the navigation stack.
if (isThisViewACollectionView) {
UIAlertView *cameraAlertView = [[UIAlertView alloc] initWithTitle:#"Camera Not Available" message:#"The camera feature isn't available on your device." delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil];
[cameraAlertView show];
}
}else{
[super viewWillDisappear:animated];
}
}
There is an issue with the logic,
The following statement is called when you already dropped the viewcontroller
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
}
So a better solution would be to hold a value somewhere "above (before)" viewWillDisappear which knows if the viewcontroller is uicollectionView (let's say a BOOL)
and assuming this value is true alert the user (filling your missing code).
I just want to dismiss UIAlertView but I can't with a strange bug for some days...
After tapping cancel button on UIAlertView, Codes below works.
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
}
But After passing these lines, it makes crash with message below:
[MPMoviePlayerViewController isKindOfClass:]: message sent to deallocated instance 0x27f590
On the same view, I embed
MPMoviePlayerViewController.moviePlayer.view
[self.view addSubview:vc.moviePlayer.view];
Does Anybody know what happend?
I use ARC, iOS5.1. If you need more information, I do add them.
Thank you in advance.
more info:
I set breakpoints on all methods in my code.
And I made sure that it crashes after clickedButtonAtIndex...
codes for calling UIAlertView show are
-(void)applicationDidBecomeActive:(NSNotification *)notification
{
self.alert = hoge; // set delegate = self
[self.alert show];
}
after calling them, viewDidAppear's called.
There are codes for enbedding vc.moviePlayer.view like
MPMoviePlayerViewController *vc;
vc = [[MPMoviePlayerViewController alloc] initWithContentURL:hogeURL];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(finishPreload:)
name:MPMediaPlaybackIsPreparedToPlayDidChangeNotification
object:vc];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(finishPlayback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:vc];
vc.view.frame = CGRectMake( 0, 0, 320, 440);
vc.moviePlayer.allowsAirPlay = YES;
vc.moviePlayer.shouldAutoplay = NO;
vc.moviePlayer.controlStyle = MPMovieControlStyleEmbedded;
vc.moviePlayer.useApplicationAudioSession = NO;
[vc.moviePlayer.view setTag:310];
[self.view addSubview:vc.moviePlayer.view];
My app has 3 tabs, 2 of them's embed MPMoviePlayerViewController.moviePlayer.view. Method called in the other tabs's controller are viewWillDisappear and viewDidDisappear only.
It seems to me that your MPMoviePlayerController instance is deallocated after viewDidAppear. I think you should set vc as a property or instance variable of the View Controller so that it persists throughout the lifetime of the View Controller.
I'm having some trouble with either a UIAlertView or UIActionSheet stealing the focus and not letting go.
To elaborate, I have a setup whereby a user presses a button. This then displays a UIAlertView with a UITextField. When the user presses the 'Ok' button a UIActionSheet is displayed (called from the UIAlertView delegate method) confirming something with the user. However when they press one of the buttons the UIActionSheet goes away but the focus doesn't get returned to the main view.
I have been playing around and whatever I seem to do I always end up with my main UIView being covered with a layer like this (obviously you can seem my view through the layer). I have tried removing all subviews of the view but it didn't have any success.
Please can someone help me out?
Here is the source code:
// This method displays the UIAlertView which contains a UITextView linked up to a
// UIPickerView.
- (IBAction)buttonPressed:(id)sender
{
UIAlertView *deleteAlert = [[UIAlertView alloc] initWithTitle:#"Delete Something"
message:#"Select something to delete:"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Ok", nil];
deleteAlert.alertViewStyle = UIAlertViewStylePlainTextInput;
deleteAlert.tag = kDeleteAlert;
deleteTextField = [deleteAlert textFieldAtIndex:0];
[pickerView reloadAllComponents];
deleteTextField.inputView = pickerView;
[deleteAlert show];
}
// The UIAlertView delegate method is then used to display a UIActionSheet to confirm
// whether the user wants to proceed.
- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex
{
UIActionSheet *confirmDelete = [[UIActionSheet alloc] initWithTitle:#"Delete blah?"
delegate:self
cancelButtonTitle:#"No"
destructiveButtonTitle:#"Yes"
otherButtonTitles:nil];
confirmDelete.actionSheetStyle = UIActionSheetStyleBlackOpaque;
[confirmDelete showInView:self.parentViewController.tabBarController.view];
}
// Then the focus should be returned to the original view (i.e. where the first button
// was pressed to launch the UIAlertView. However the focus is still locked and the
// view appears slightly dimmed around the edges.
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == actionSheet.destructiveButtonIndex)
{
// Do some stuff ...
}
}
I think your issue is a result of the deleteAlert alert view not being dismissed when the actionSheet is called.
I sounds to me like the alert view still has focus but is in an unknown state, because it hasn't been dismissed, but you have done something with it's button press.
Presumably, you want to dismiss the alert view when the action sheet is presented? Then when the action sheet is dismissed, you get back to your main view? So, the order you want:
1) Present alert view
2) If a button on the alert view is pressed, it notifies it's delegate using - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
3) Dismiss the alertView - (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated and present the action sheet.
3) When the action sheet is used, it calls it's delegate method - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex and within that method, dismiss it, or whatever else you need to do.
You would put all of these delegate methods in your original calling viewcontroller, conforming it to <UIAlertViewDelegate, UIActionSheetDelegate>.
You will need to make the original viewcontroller the delegate of the alert view AND the action sheet when you create them. I hope this makes sense.
More information http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html
I would say it's probably b/c you are not resigning the first responder on the UITextField that is inside the UIAlertView. Make sure that before you show your UIActionSheet you do
[myTextField resignFirstResponder];
I have a TabBarController with 2 tabs, in one is a MapView and in the other one a simple TableView in a NavigationController. Both display Data from the same source. If any Data in the table is tapped, I add a DetailViewController to the NavigationController and show more details. Now on the MapView I also want to open this DetailViewController when the Data is tapped in the map. What's the best way to do this? I tried some with Notification but this doesn't work well because the TableViewController is finished loading (and registered as an observer) after the Notification is sent.
Here's my code:
MapViewController:
- (IBAction)goToNearestEvent:(id)sender {
if (currentNearestEvent) {
[[self tabBarController] setSelectedIndex:1];
NSDictionary *noteInfo = [[NSDictionary alloc] initWithObjectsAndKeys:currentNearestEvent, #"event", nil];
NSNotification *note = [NSNotification notificationWithName:#"loadDetailViewForEvent" object:self userInfo:noteInfo];
[[NSNotificationCenter defaultCenter] postNotification:note];
[noteInfo release];
}
}
TableViewController:
- (void)viewDidLoad {
[super viewDidLoad];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(loadDetailViewForEvent:)
name:#"loadDetailViewForEvent"
object:nil];
}
- (void)loadDetailViewForEvent:(NSNotification *)note {
Event *e = [[note userInfo] objectForKey:#"event"];
[self loadEventDetailViewWithEvent:e];
}
So I'm very new to iOS / Cocoa programming. Maybe my approach is the wrong choice. So I hope anybody could tell me how to solve such things the right way.
I forgot to declare my structure clearly:
- UITabBarController
- MapView (1)
- NavigationControllerContainer
- NavigationControllerView (2)
- TableView
I want to push a new View from the MapView (1) to the NavigationControllerView (2).
If you're going to use notifications, the fix is to force the second tab to be "created" before it's displayed.
Something like:
UIViewController *otherController = [[[self tabBarController] viewControllers] objectAtIndex:1];
otherController.view; // this is magic;
// it causes Apple to load the view,
// run viewDidLoad etc,
// for the other controller
[[self tabBarController] setSelectedIndex:1];
I don't have access to my code, but I did something similar to:
[[self.tabBarController.viewControllers objectAtIndex:1] pushViewController:detailView animated:YES];
Give this a try and let me know.
I think the observer/notification pattern is the right one. However, you normally want "controllers" to observe "model" objects.
I would create a Model object that contains the selected Event.
When each viewController is loaded, it looks at the "Model" object and directs itself to the selected event.
When any of the viewControllers changes the selected event, it does so in the Model, and then the notification propagates to the other(s) controllers.
My alertview appears twice and requires 2 user clicks to dismiss.
- (void) showAlert: (NSString *) message
{
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"You chose"
message: message
delegate: self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"ok",nil];
av.tag = SLIDER_ALERT;
[av show];
}
I am then releasing the alertview in the delegate method "alertView: (UIAlertView *) alertView clickedButtonAtIndex: (int) index"
I suspect the problem is that I have built my own view hierarchy programmaticaly. I have one parent view for the viewcontroller. Under that i have 2 other views (parentView -> subview1 and subview2). I've tried to call [self.view addSubview: av] but that does not work. Neither does bringToFrontSubView:
Any help would be much appreciated
Peyman
The Alert code is fine (other than the release, mentioned in the comments).
[av show] is all that's required to show a view. You don't add UIAlertViews as subviews.
Call it after a delay of 0.1 sec [self performSelector:#selector(showAlert:) withObject:nil afterDelay:0.10];
Hope this will solve your problem.
With using autorelease the Alert View seems to be twice or 3 times. And for iOS4 it needs to be autoreleased otherwise it will crash.