Forcing UIAlertView into landscape mode - objective-c

I need to display a UIAlertView in landscape mode. I tried the obvious, setting the transform in the willPresentAlertView: delegate method to no avail:
-(void) willPresentAlertView:(UIAlertView *)alertView {
alertView.transform = CGAffineTransformMakeRotation(M_PI_2);
}
Any suggestions on how to fix this?

Have you tried in the didPresentAlertView?
- (void)didPresentAlertView:(UIAlertView *)alertView
{
// UIAlertView in landscape mode
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:0.1];
alertView.transform = CGAffineTransformRotate(alertView.transform, 3.14159/2);
[UIView commitAnimations];
}

It should rotate automatically if you're using UIViewController.
Did you forget to return YES for the desired orientations in shouldAutorotateToInterfaceOrientation?
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES; /* auto rotate always */
}

What is the orientation of the view that shows the alert? I had the same problem, I tried to show an UIAlertView inside a landscape view but always appeared in portrait orientation. So, I forced the orientation of the status bar:
[[UIApplication sharedApplication] setStatusBarOrientation:theOrientation];
That worked to me.

Before the Alert Window appeared , Set the current window display at the top. If not do this ,you can see the alert window's rotate animate.
-(void) willPresentAlertView:(UIAlertView *)alertView {
[UIView setAnimationsEnabled:NO];
self.view.window.windowLevel = 2003;
}
Rotate the Alert Window
-(void)didPresentAlertView:(UIAlertView *)alertView
{
UIWindow * alertWindow = alertView.window;
alertWindow.transform = CGAffineTransformMakeRotation(M_PI / 2);
alertWindow.bounds = CGRectMake(0, 0, SCREEN_HEIGHT,SCREEN_WIDTH);
alertWindow.center = CGPointMake(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(showLandscapeAlertView) userInfo:nil repeats:NO];
}
After the Alert window rotated, move the current window back.
-(void)showLandscapeAlertView {
self.view.window.windowLevel = 0;
[UIView setAnimationsEnabled:YES];
}

I was struggling with quite the same issue lately. For me solution was using UIAlertController - cover older handling of UIAlertview and UIActionsheet.
Create new controller, which is dedicated from UIAlertController, where you must overloaded methods viewWillAppear and viewWillDisappear, like in example bellow.
AlertViewController.h
#import <UIKit/UIKit.h>
#interface AlertViewController : UIAlertController
#end
AlertViewController.m
#import "AlertViewController.h"
#interface AlertViewController ()
#end
#implementation AlertViewController
- (void) viewWillAppear:(BOOL)animated {
[self.view setTransform:CGAffineTransformMakeRotation(M_PI_2)];
}
- (void) viewWillDisappear:(BOOL)animated {
[self.view setHidden:YES];
}
...
implement method for showing alert view where you needed.
(void) showInfoAlertView {
AlertViewController *alert = [AlertViewController alertControllerWithTitle:#"My Alert" message:#"This is an alert." preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:NO completion:nil];
}

Related

How to restore keyWindow (NSView - Appkit)

I have some code which opens a modal window (itself composed from a few views) and makes it closed when we click anywhere on it.
here is some part of code:
int myFunc()
{
// Create views
NSPanel *panel = ...;
CustomNSTextView * textView = ... ;
CustomNSImageView * imageView = ...;
[view addSubview:textView];
[view addSubview:imageView];
[panel setContentView:view];
[[NSApplication sharedApplication] runModalForWindow:panel];
NSView* parentView = [view superview];
[[parentView window] makeFirstResponder:parentView];
[textView release];
[imageView release];
[view release];
[panel release];
}
#implementation CustomNSTextView : NSTextView
- (void) mouseDown:(NSEvent *)theEvent
{
#pragma unused(theEvent)
[[NSApplication sharedApplication] stopModal];
}
#implementation CustomNSImageView : NSImageView
- (void) mouseDown:(NSEvent *)theEvent
{
#pragma unused(theEvent)
[[NSApplication sharedApplication] stopModal];
}
The bug is after the window is closed, the application (that launched the modal window), won't receive any key event anymore (while it still was as the modal window was still open).
Only after I refocus on the application, it will receive key events again.
Please anyone gives me some idea, I could not find something relevant on the net.
Thanks
Nathaniel

what's the difference between self.view.widow and [[UIApplication sharedApplication] keyWindow] in Objective-C

if I do like this
- (void)viewDidLoad {
[super viewDidLoad];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"test" delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil];
[alert show];
}
// Called when a button is clicked. The red view and alert will be automatically dismissed after this call returns
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
[self showView];
}
// after animation ,this will work fine
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
// [self showView];
}
- (void)showView {
// Called when a button is clicked. The view will be automatically dismissed after this call returns
UIView *view = [[UIView alloc] init];
view.frame = CGRectMake(0, 0, 200, 200);
view.backgroundColor = [UIColor redColor];
view.center = CGPointMake([UIScreen mainScreen].bounds.size.width/2.0f, [UIScreen mainScreen].bounds.size.height/2.0f);
// [self.view.window addSubview:view]; //when i use this ,both of the two delegate methods works fine
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
[window addSubview:view];
}
Then the red view and alert will be automatically dismissed after alertView:clickedButtonAtIndex: call returns
who can show me the reason?
what's the difference between self.view.widow and [[UIApplication sharedApplication] keyWindow] in Objective-C
Your question is essentially addressed here:
diffrence between [[[[UIApplication sharedApplication] delegate] window] and [[UIApplication sharedApplication].keyWindow?
To tie it back to your question, the UIAlertView gets presented in a system window, and it is this window that is the keyWindow while your alert is being shown. When the alert is dismissed, that window disappears, hence why your view disappears.
Assuming that self.view is a subview of the app's window (almost always the case), your view continues to display because the window itself continues to be displayed after the alert is dismissed.

How Popup Keyboard After Segue to New Naviagtion Controller Animation Has Finished

I segue from a tableview to detail view controller using custom segues.
#implementation QuickNoteFlipSegue
- (void) perform {
UIViewController *src = (UIViewController *) self.sourceViewController;
UIViewController *dst = (UIViewController *) self.destinationViewController;
dst.navigationItem.hidesBackButton = YES;
[UIView transitionWithView:src.navigationController.view duration:1.00
options:UIViewAnimationOptionTransitionCurlUp
animations:^{
[src.navigationController pushViewController:dst animated:NO];
}
completion:^(BOOL finished){
if (finished) {
}
}];
}
#end
What I would like to do it when the transition has finished, popup the keyboard for my textview.
I currently do this by calling
[textView becomeFirstResponder];
This pops up the keyboard OK but before the transition animation has finished. How to detect when the animation has finished before I popup the keyboard?
I should maybe put something is the completion of the animation, but how to make the custom segue aware of the textview in it's destination?
Do:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[textView becomeFirstResponder];
}
Add a method to your DestinationViewController:
-(void)openKeyboard
{
[textView becomeFirstResponder];
}
Then change your perform method:
- (void) perform {
UIViewController *src = (UIViewController *) self.sourceViewController;
DestinationViewController *dst = (DestinationViewController *) self.destinationViewController;
dst.navigationItem.hidesBackButton = YES;
[UIView transitionWithView:src.navigationController.view duration:1.00
options:UIViewAnimationOptionTransitionCurlUp
animations:^{
[src.navigationController pushViewController:dst animated:NO];
}
completion:^(BOOL finished){
if (finished) {
[dst openKeyboard];
}
}];
}

How to change speed of segue between ViewControllers

Is it possible to control segue speed?
I have checked the documentation but there is no given method by Apple.
But I am more looking for ideas to hack in and change lower level code to make segueing in slow motion.
Below code is of custom segue, and you can set duration of transition in code.
- (void)perform
{
UIViewController *src = (UIViewController *) self.sourceViewController;
UIViewController *dst = (UIViewController *) self.destinationViewController;
[UIView transitionFromView:src.view
toView:dst.view
duration:3.0
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:NULL];
}
Sample project is here in GitHub:https://github.com/weed/p120805_CustomSegue
You can download and just run it. I wish this is help for you.
to prevent zombies creation i think better to do use subview add/remove as well:
- (void)perform
{
UIView *src = ((UIViewController *) self.sourceViewController).view;
UIView *dst = ((UIViewController *) self.destinationViewController).view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window insertSubview:dst aboveSubview:src];
[UIView transitionFromView:src
toView:dst
duration:1.5
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished){
[src removeFromSuperview];
window.rootViewController = self.destinationViewController;
}];
}
this is if you are not using navigation controller!

UIAlertView showing up only after it's dismissed

I've been trying to figure this out for 2 days now, and before anyone posts another stackoverflow question, I've read them all and none of them cover my problem exactly:
I have a CoreData app that updates dynamically. Now during the update I want an UIAlertView to pop up saying that an update is being downloaded.
So here's the important code:
AppDelegate:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[myUpdater checkForUpdatesInContext:self.managedObjectContext];
}
_
Updater Class:
- (void)checkForUpdatesInContext:(NSManagedObjectContext *)myManagedObjectContext
{
[self loadUpdateTime];
NSLog(#"Update start");
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
{
return;
}
[self showAlertViewWithTitle:#"Update"];
... //updating process
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
NSLog (#"Update done");
}
- (void) showAlertViewWithTitle:(NSString *)title
{
self.alertView = [[UIAlertView alloc] initWithTitle:title message:#"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
... //design the alertView
[self.alertView show];
NSLog (#"AlertView shows");
}
So here is what happens when I run this:
Launch image shows
NSLog "Update starts" fires
NSLog "AlertView shows" fires
Screen dims but no AlertView is shown
Update is running
NSLog "Update done" fires
Launch image goes away and TabBarController shows up
UIAlertView shows up and is dismissed right away and the dimmed screen returns to normal
What I would like to have happen:
Launch image
TabBarController shows up
Screen dims and UIAlertView shows
Update is running
UIAlertView gets dismissed and dimmed screen returns to normal
I know it's something with the UI Thread and the main Thread and stuff.. But I tried every combination it seems but still not the expected result. Please help :)
EDIT:
HighlightsViewController Class:
- (void)viewDidLoad
{
[super viewDidLoad];
self.updater = [[Updater alloc] init];
[updater checkForUpdatesInContext:self.managedObjectContext];
... // other setup stuff nothing worth mentioning
}
Is this the right place to call [super viewDidLoad]? Because it still doesn't work like this, still the update is being done while the Launch Image is showing on the screen. :-(( I'm about to give this one up..
Here you go, in this prototype things work exactly how you want them to.
Header:
#import <UIKit/UIKit.h>
#interface AlertViewProtoViewController : UIViewController
{
}
- (void) showAlertViewWithTitle:(NSString *)title;
- (void) checkForUpdatesInContext;
- (void) update;
- (void)someMethod;
- (void)someOtherMethod;
#end
#import "AlertViewProtoViewController.h"
Class:
#implementation AlertViewProtoViewController
UIAlertView *alertView;
bool updateDone;
UILabel *test;
bool timershizzle;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor yellowColor];
UILabel *test = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
test.backgroundColor = [UIColor blueColor];
[self.view addSubview:test];
[self performSelector:#selector(checkForUpdatesInContext) withObject:nil afterDelay:0.0];
}
- (void)update
{
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //commented for auto ref counting
NSLog(#"update start");
//your update stuff
NSLog(#"update end");
updateDone = YES;
//[pool release];
}
- (void)checkForUpdatesInContext//:(NSManagedObjectContext *)myManagedObjectContext
{
//[self loadUpdateTime];
NSLog(#"Update start");
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
// if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
// {
// return;
// }
[self showAlertViewWithTitle:#"Update"];
//[self setManagedObjectContext:myManagedObjectContext];
[self performSelector:#selector(someMethod) withObject:nil afterDelay:0.0];
[self performSelector:#selector(someOtherMethod) withObject:nil afterDelay:0.0];
}
-(void)someOtherMethod
{
while (!updateDone) {
// NSLog(#"waiting...");
}
[alertView dismissWithClickedButtonIndex:0 animated:YES];
NSLog (#"Update done");
self.view.backgroundColor = [UIColor greenColor];
}
-(void)someMethod
{
[self performSelectorInBackground:#selector(update) withObject:nil];
}
- (void) showAlertViewWithTitle:(NSString *)title
{
alertView = [[UIAlertView alloc] initWithTitle:title message:#"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
alertView.frame = CGRectMake(100, 100, 200, 200);
alertView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:alertView];
[self.view setNeedsDisplay];
NSLog (#"AlertView shows");
}
#end
You should adjust were needed for your own purposes but it works.
You are starting a background thread and then dismissing the alert immediately. I would suggest that you might use an NSNotification, posted from the background task, and received in whichever controller starts the alert, triggering a method that dismissed the alert.
I find the UIAlertView interface unsuitable for this type of user notice, and prefer to use a semi-transparent overlay view with a UIActivityIndicatorView, plus an informing message for the user.
You are doing a:
- (void)applicationDidBecomeActive:(UIApplication *)application
Isn't it so that the alertview you want to show needs a view to be loaded which isn't active yet at this point? See: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html
Similar question? UIAlertView starts to show, screen dims, but it doesn't pop up until it's too late!