iPhone 5 device modifier for dynamic xib loading - iphone

I'm working on a universal iOS app and wanting to use different xib files for iPhone 5. The way it currently works is by automatically selecting the file with the right device modifier (as specified here: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/LoadingResources/Introduction/Introduction.html#//apple_ref/doc/uid/10000051i-CH1-SW2). However there's no mention there of how to handle the iPhone 5. I'm surprised because I'm under the impression they'd prefer developers to create a different/unique experience on the 5 instead of just auto scaling...
Anyone aware of a modifier that works? (eg myxib~iphone5.xib) It would be more convenient than having to handle the device detection and switching myself.
Cheers!

There's no naming convention unfortunately, but there's a way. This is what I'm using:
I have a global .h file called GlobalConstants that I put all my #define macros in. There I have this:
static BOOL is4InchRetina()
{
if ((![UIApplication sharedApplication].statusBarHidden && (int)[[UIScreen mainScreen] applicationFrame].size.height == 548) || ([UIApplication sharedApplication].statusBarHidden && (int)[[UIScreen mainScreen] applicationFrame].size.height == 568))
return YES;
return NO;
}
then in any of my view controller classes - I override the init method like this:
#import GlobalConstants.h
-(id) init {
if(is4InchRetina()) self = [super initWithNibName:#"myNibName5" bundle:[NSBundle mainBundle]];
else self = [super initWithNibName:#"myNibName" bundle:[NSBundle mainBundle]];
return self
}

Related

MonoTouch - How do I declare UIPopoverController only when using an iPad device?

As I understand from reading documentation, UIPopoverControllers are only supported on the iPad. Therefore if you try to declare a variable as a UIPopoverController and run the app in the iPhone simulator or on an iPhone, you get an error such as:
UIPopoverController initWithContentViewController:] called when not running under UIUserInterfaceIdiomPad
So I have a universal monotouch app I am trying out, where I would like to use a UIPopoverController when the user is using an iPad, for the iPhone I have another solution.
This is how I am declaring it at the moment, but obviously running on the iPhone does not work, and I get the above error message.
public partial class IOPSCalculatorViewController : UIViewController
{
static bool UserInterfaceIdiomIsPhone {
get { return UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone; }
}
static bool UserInterfaceIdiomIsIPAD {
get { return UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad; }
}
UIPopoverController DetailViewPopover = new UIPopoverController(new PopoverContentViewController());
}
How can I only declare the:
UIPopoverController DetailViewPopover = new UIPopoverController(new PopoverContentViewController());
part if the device is an iPad? I need the UIPopoverController to be in the public partial class so that I can access it publically in other places.
Instead of declaring and allocating in one line just split it in two lines. E.g.
UIPopoverController DetailViewPopover = null;
if (IOPSCalculatorViewController.UserInterfaceIdiomIsIPAD) {
DetailViewPopover = new UIPopoverController (new PopoverContentViewController ());
}
That will also work if DetailViewPopover is a (public) field instead of an instance variable and, as long as the UIPopoverController constructor is not invoked, you won't be getting the error.
You need to find out what is your current device and write code for iphone and iPad as well. here is a snap of code that I've used in my case.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
//Do your coding here
}
else {
if(![popoverController isPopoverVisible]){
contact = [[[ContactViewController alloc] initWithNibName:#"ContactViewController_iPad" bundle:nil] autorelease];
popoverController = [[[UIPopoverController alloc] initWithContentViewController:contact] retain];
[popoverController setPopoverContentSize:CGSizeMake(400.0f, 400.0f)];
[popoverController presentPopoverFromRect:CGRectMake(230, 860, 320.0f, 320.0f) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
[popoverController release];
}else{
[popoverController dismissPopoverAnimated:YES];
}
}
hope this will help you. Happy Coding!!!

How to change the orientation of the app without changing the device orientation in iphone app

I want to change the orientation of the app without changing the device orientation in iphone app.
I want to change my view from portraid mode to landscap mode programmatically.
And also want to know that will this be accepted by the apple store or not ?
Thanks
Now I got the solution from other that is as follow
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
when you add this line at that time one warning appear and for remove this warning just add bellow code on you implementation file..
#interface UIDevice (MyPrivateNameThatAppleWouldNeverUseGoesHere)
- (void) setOrientation:(UIInterfaceOrientation)orientation;
#end
and after that in bellow method just write this code if required..
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
But now want to know is this accepted by apple app store or not ?
thanks
use this line for programmatically change orientation...
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
and also when you add this line at that time one warning appear and for remove this warning just add bellow code on you implementation file..
#interface UIDevice (MyPrivateNameThatAppleWouldNeverUseGoesHere)
- (void) setOrientation:(UIInterfaceOrientation)orientation;
#end
and after that in bellow method just write this code if required..
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
// return NO;
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
i hope this help you..
:)
Add a class variable
Bool isInLandsCapeOrientation;
in viewDidLoad
set this flag to
isInLandsCapeOrientation = false;
Add the following function
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (!isInLandsCapeOrientation) {
return (UIInterfaceOrientationIsPortrait(interfaceOrientation));
}else {
return (UIInterfaceOrientationIsLandscape(interfaceOrientation));
}
}
To changing orientation from portrait to landscape, let it happens on a button action
- (IBAction)changeOrientationButtonPressed:(UIButton *)sender
{
isInLandsCapeOrientation = true;
UIViewController *viewController = [[UIViewController alloc] init];
[self presentModalViewController:viewController animated:NO];
[self dismissModalViewControllerAnimated:NO];
}
This works fine for me.
To change Orientation portraid mode to landscap mode use this code
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
use this code for programmatically change orientation...
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
If you want to change the particular view only in landscape..then u can try the following in its viewDidLoad
float angle = M_PI / 2;
CGAffineTransform transform = CGAffineTransformMakeRotation(angle);
[ [self.view] setTransform:transform];
The documentation describes the orientation property as being read-only, so if it works, I'm not sure you can rely on it working in the future (unless Apple does the smart thing and changes this; forcing orientation changes, regardless of how the user is currently holding their device, is such an obvious functional need).
As an alternative, the following code inserted in viewDidLoad will successfully (and somewhat curiously) force orientation (assuming you've already modified you shouldAutorotateToInterfaceOrientation ):
if (UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]))
{
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];
}
Clearly, this does it if the user is currently holding their device in portrait orientation (and thus presumably your shouldAutorotateToInterfaceOrientation is set up for landscape only and this routine will shift it to landscape if the user's holding their device in portrait mode). You'd simply swap the UIDeviceOrientationIsPortrait with UIDeviceOrientationIsLandscape if your shouldAutorotateToInterfaceOirentation is set up for portrait only.
For some reason, removing the view from the main window and then re-adding it forces it to query shouldAutorotateToInterfaceOrientation and set the orientation correctly. Given that this isn't an Apple approved approach, maybe one should refrain from using it, but it works for me. Your mileage may vary. But this also refers to other techniques, too. Check
SO discussion

Camera button on UIImagePickerController is randomly disbled

I have a UIImagePickerController (source type camera) that I use to take pictures. I have it put properly in my .h (added the #property) and .m (#synthesize). Here's what I use to show it:
if (thePicker == nil) {
thePicker = [[UIImagePickerController alloc] init];
thePicker.delegate = self;
thePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
thePicker.allowsEditing = NO;
}
[self presentModalViewController:thePicker animated:YES];
I'm having an odd problem. Every now and again, after closing/opening it a few times, the camera button OR the used button won't work (but the retake and cancel buttons work). I'm not getting any memory warnings and I have a dealloc and didReceiveMemoryWarnings void statement, but they don't get called.
ANyone else having this problem?
I have seen some apps cover it up with their overlay, but you can't remove it. AVCaptureSession really does sound more appropriate for your purposes. I see one example here:
http://www.musicalgeometry.com/?p=1273
Try this it may help u i guess Thanks!!

Universal iOS app crashing on iPhone/iTouch 3.1.3 due to UIPopoverController

I just updated my app so that it's a universal app. In doing so I added support for UIPopoverController in a certain place. Now the app seems to be crashing on 3.1.3 iPhone/iTouch devices:
OS Version: iPhone OS 3.1.3 (7E18)
Report Version: 104
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x00000001, 0xe7ffdefe
Crashed Thread: 0
Dyld Error Message:
Symbol not found: _OBJC_CLASS_$_UIPopoverController
What I don't get is that I'm only trying to call UIPopoverController if the hardware is an iPad:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:btc];
CGSize popoverSize = { 300.0, 500.0 };
popover.delegate = self;
popover.popoverContentSize = popoverSize;
self.bmPopover = popover;
[popover release];
[self.bmPopover presentPopoverFromBarButtonItem:self.bmBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
} else {
[self presentModalViewController:nav animated:YES];
}
I do have an iVar and a property of type UIPopoverController declared but I wouldn't have expected this to cause an issue at runtime if I didn't actually try to call methods in the class.
What am I supposed to do to make sure that the system doesn't try to link with UIPopoverController at runtime when this isn't supported?
For Universal app you should not only check if this is ipad or does this class exists but you should link UIKit as Weak reference a not default ( strong ), to do this:
get to target info
select general
in linked libraries change UIKit required to UIKit weak
Have fun making universal apps :]
Even though this code would most likely never run on the iPhone, it will still be linked and thus you are receiving the error. Before instantiating, you need to check if the class exists. You can modify your code above to the following which will fix it.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
Class UIPopoverControllerClass = NSClassFromString(#"UIPopoverController");
if (UIPopoverControllerClass != nil) {
UIPopoverController *popover = [[UIPopoverControllerClass alloc] initWithContentViewController:btc];
CGSize popoverSize = { 300.0, 500.0 };
popover.delegate = self;
popover.popoverContentSize = popoverSize;
self.bmPopover = popover;
[popover release];
[self.bmPopover presentPopoverFromBarButtonItem:self.bmBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
} else {
[self presentModalViewController:nav animated:YES];
}
Also, you could weak link against the UIKit framework, which would also solve the problem. I prefer the code solution as it is more safe.
You need to stop the compiler errors by referencing the class from a string. This should be used in tandem with UI_USER_INTERFACE_IDIOM() and will compile on an SDK that does not know about UIPopoverController. Here is an example:
Class popClass = NSClassFromString(#"UIPopoverController");
if(popClass) {
id infoPop = [[popClass alloc] initWithContentViewController:popViewController];
[infoPop presentPopoverFromRect:CGRectMake(20, 70, 10, 10) inView:self.view permittedArrowDirections:4 animated:YES];
}
The easy answer:
In your Xcode project, Select the top level project icon. Do a Get Info, go to the BUILD panel. set Configurations to All Configurations, set Show: to ** All Settings**
Set the iOS Deployment Target to iOS 3.1.
Recompile. Your program is failing because the minimum OS is set too high, so the loader can't resolve the symbol UIPopoverController. The change I just walked you through makes that symbol weak: it will resolve to NULL, but at least your program will load.
Are you loading a NIB file that implicitly creates a UIPopoverController? That's another way to crash.
I found it useful to add this, so that I could use UI_USER_INTERFACE_IDIOM() on pre-3.2 systems.
#ifndef __IPHONE_3_2 // if iPhoneOS is 3.2 or greater then __IPHONE_3_2 will be defined
typedef enum {
UIUserInterfaceIdiomPhone, // iPhone and iPod touch style UI
UIUserInterfaceIdiomPad, // iPad style UI
} UIUserInterfaceIdiom;
#define UI_USER_INTERFACE_IDIOM() UIUserInterfaceIdiomPhone
#endif // ifndef __IPHONE_3_2

UIViewController does not auto rotate

As the title says. My UIViewController will not rotate no matter what. When it loads shouldAutorotateToInterfaceOrientation is being called but after that it doesnt.
UPDATE 1:
It's a really really wierd problem. At least for me. And i ll try to explain everything.
It's a navigation based app. Every controller has
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
Xcontroller is a child of Acontroller and it doesn't auto rotate. If Xcontroller become a child of Bcontroller then it will autorotate. So something is wrong with Acontroller. But Acontroller is identical (except its data) to Bcontroller.
Whats Wrong?
UPDATE 2:
I decided to recreate Acontroller. And it worked.I believe I was missing something stupid.
I am not sure whether it's the same reason as your case. But I experienced the same thing. the shouldAutorotateToInterfaceOrientation was only called once in the beginning.
After some serious debugging by taking code apart, I found that the reason is in my overridden init method.
I had this before:
- (id)initWithAlbum:(PhotoAlbum *)theAlbum {
if (self) {
self.photoAlbum = theAlbum;
}
return self;
}
And then I changed to this
- (id)initWithAlbum:(PhotoAlbum *)theAlbum {
if (self = [super init]) {
self.photoAlbum = theAlbum;
}
return self;
}
Note: the only difference is I added [super init] to call the parent init.
After this change, the rotation works well and the shouldAutorotateToInterfaceOrientation is being called everytime I rotate the screen.
Hope this help.
There can be several possible reasons your view controller does not rotate.
See Apple's official Q&A on this issue:
Why won't my UIViewController rotate with the device?
http://developer.apple.com/library/ios/#qa/qa2010/qa1688.html
Apple Q&A has the detailed solution for the problem.
Why won't my UIViewController rotate with the device?
http://developer.apple.com/library/ios/#qa/qa1688/_index.html
If you add a viewcontroller.view to uiwindow, you should set this viewcontroller as rootviewcontroller.
[self.window addSubview: mainViewcontroller.view];
self.window.rootViewController=mainViewcontroller;
Also, make sure you don't have rotation lock on. I spent a good hour trying to figure out why my views stopped rotating. shouldAutorotateToInterfaceOrientation was being called only once at start up and when Game Center leaderboards/achievements were presented.
I had the same issue - the reason was, that it was my first UIViewController, that i created on the fly in my ApplicationDelegate, added it's View to my UIWindow and immediately released it.
That's of course not correct as I just added the UIView of the UIViewController (retaining it) and than released the whole controller.
You should add your first UIViewController as an instance variable in Your ApplicationDelegate instead, and release it in Your ApplicationDelegate's dealloc-method.
In my case, the ViewController was inside a NavigationController which was used by a "parent" viewControlled that received the orientation changes.
What I did in this parent was:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
if(_navigationController){
return [_navigationController.topViewController shouldAutorotateToInterfaceOrientation: toInterfaceOrientation];
}
return toInterfaceOrientation == UIInterfaceOrientationPortrait;
}
This way you can implement your own orientation change logic depending on the currently visible controller.
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{ return YES; }
The above method if u using, you will able to call many time if u want with out any error.
I think there is no strange behavior here, it is called only one which is right. There is no need to call more than one to decide if the device should rotate to a direction or not.
This method just ask if the device should rotate to a direction or not.
If you want to handle the orientation change, you should register for the notification from the UIDeviceDidChangeOrientationNotification and override the following method:
- (void)orientationChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) &&
!isShowingLandscapeView)
{
[self presentModalViewController:self.landscapeViewController
animated:YES];
isShowingLandscapeView = YES;
}
else if (deviceOrientation == UIDeviceOrientationPortrait &&
isShowingLandscapeView)
{
[self dismissModalViewControllerAnimated:YES];
isShowingLandscapeView = NO;
}
}
See more here.
I have the same problem but with two view controllers added to the application's UIWindow. The reason
is The view controller's UIView property is embedded inside UIWindow but alongside an additional view controller
From Apple Technical Q&A
http://developer.apple.com/library/ios/#qa/qa1688/_index.html