UIImagePickerController in Landscape embedded in a UINavigationController Objective-C - objective-c

Im trying to present the ImagePicker in Landscape with a landscape only app that embedded in UINavigationController. None of the answers I've found are working. Apparently this is possible now. Ive found a way to do this in Swift from here, but I'm not using Swift. Perhaps someone can help me convert this Swift code to Objective-C or provide a real working example in Objective-C. It looks like many people would benefit from this. Thanks for helping in advance.
Working Swift Code that needs converting to Objective-C:
//Appdelegate.swift
func application(application: UIApplication, supportedIntefaceOrentationForWindow window: UIWindow?) ->UIInterfaceOrientationMask{
if let presentViewController = window?.rootViewController?.presentedViewController {
if (presentViewController.isKindOfClass(UIImagePickerController) && !presentViewController.isBeingDismissed() ) {
return UIInterfaceOrientationMask.Portrait
}
}
return UIInterfaceOrientationMask.Landscape
}
Objective-C Code I'm using to present the Image Picker gives a SIGBART error from the app delegate "Works fine with portrait enabled otherwise":
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePicker.mediaTypes = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeMovie, nil];
UIViewController *viewController = self.view.window.rootViewController;
[viewController presentViewController: imagePicker animated: YES completion:nil];

This is the Objective-C code.
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
if (([window.rootViewController.presentedViewController isKindOfClass:[UIImagePickerController class]]) && (window.rootViewController.presentedViewController.isBeingDismissed == NO)) {
return UIInterfaceOrientationMaskPortrait
}
return UIInterfaceOrientationMaskLandscape
}

Related

Conversion of custom init routines in Swift

I need to subclass SVModalWebViewController.m (GitHub), which is itself a subclass of UINavigationController, and am incorporating this code into a new app that will be created entirely in Swift. I've run into several issues, so I decided to first convert just this very simple class into Swift to debug.
Initialization is a little different in Swift compared with Objective-C (read more about Swift initialization here), which is why I'm not returning self in the Swift code.
Here's the original Obj-C code (minus the *.h, which instantiates barsTintColor):
#import "SVModalWebViewController.h"
#import "SVWebViewController.h"
#interface SVModalWebViewController ()
#property (nonatomic, strong) SVWebViewController *webViewController;
#end
#implementation SVModalWebViewController
#pragma mark - Initialization
- (id)initWithAddress:(NSString*)urlString {
return [self initWithURL:[NSURL URLWithString:urlString]];
}
- (id)initWithURL:(NSURL *)URL {
self.webViewController = [[SVWebViewController alloc] initWithURL:URL];
if (self = [super initWithRootViewController:self.webViewController]) {
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self.webViewController
action:#selector(doneButtonClicked:)];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
self.webViewController.navigationItem.leftBarButtonItem = doneButton;
else
self.webViewController.navigationItem.rightBarButtonItem = doneButton;
}
return self;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:NO];
self.webViewController.title = self.title;
self.navigationBar.tintColor = self.barsTintColor;
}
#end
And here's the entire Swift version of the class (I simplified to just one init method since I didn't need to init with URL specifically):
import UIKit
class SVModalWebViewController: UINavigationController {
var webViewController: SVWebViewController!
var barsTintColor: UIColor?
// This was added because of a compiler error indicating it needed to be added
init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
init(address urlString: String!) {
let url: NSURL = NSURL.URLWithString(urlString)
self.webViewController = SVWebViewController(URL: url)
super.init(rootViewController: self.webViewController)
let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self.webViewController, action: Selector("doneButtonClicked:"))
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
self.navigationItem.leftBarButtonItem = doneButton
} else {
self.navigationItem.rightBarButtonItem = doneButton
}
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// self.title may not be set, and is considered an optional in Swift, so we have to check first
if self.title {self.webViewController.title = self.title}
self.navigationBar.tintColor = self.barsTintColor
}
}
The issue I'm having relates to setting the Done button in the navigationItem. Currently they're not showing up at all when this code is called:
let webViewController = SVModalWebViewController(address: "http://www.google.com");
webViewController.barsTintColor = UIColor.blueColor()
self.presentModalViewController(webViewController, animated: true)
The modal view appears just fine and I'm able to correctly set the bar color property, but the Done button does not show up. It appears that I don't have proper access to the navigationItem of the UINavigationController. Note that I had to add the init with nibName method due to a compiler error without it. This wasn't required in the Obj-C code and I'll admit I'm not sure why it's needed in Swift - that could be part of the issue.
Any thoughts as to why I cannot set the self.navigationItem.leftBarButtonItem property of the UINavigationController? Thanks!
A UINavigationController does not have a navigationItem. Well, it does, but it's useless. It is the navigationItem of the child controller (in this case, the rootViewController, which you are also calling self.webViewController) that appears in the navigation bar.

extending UIImagePicker controller doesn't help to prevent rotation in io6

My application is set in info.plist to support only portrait mode.
However, the UIImagePickerController, rotates when the user rotates the screen to landscape.
Since in io6 the method shouldAutoRotate is not being called, I tried to extend it like this:
#interface NonRotatingUIImagePickerController : UIImagePickerController
#end
#implementation NonRotatingUIImagePickerController
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationMaskPortrait;
}
#end
But it doesn't help. Any idea why?
And in the log I see the above methods being called. The UIImagePickerController at first is displayed in portrait and when the user rotates - it rotates as well instead of staying portrait.
I set the image picker in the view like this:
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (!self.imagePickerController) {
self.imagePickerController = [[NonRotatingUIImagePickerController alloc] init];
self.imagePickerController.delegate = self;
}
return self;
}
- (void)viewDidAppear:(BOOL)animated{
self.imagePickerController.showsCameraControls = NO;
CGRect imagePickerControllerFrame = CGRectMake(0, topBar.frame.size.height, self.view.frame.size.width, self.view.frame.size.height - topBar.frame.size.height - bottomBar.frame.size.height);
self.imagePickerController.view.frame = imagePickerControllerFrame;
self.imagePickerController.allowsEditing = YES;
self.imagePickerController.view.clipsToBounds = YES;
self.imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera
[self.view.window addSubview:self.imagePickerController.view];
}
self.imagePickerController.view.frame = imagePickerControllerFrame;
// ...
[self.view.window addSubview:self.imagePickerController.view];
Well, that's all totally illegitimate. Apple makes this very clear in the docs:
This class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified
There is only one correct way to use an image picker controller that uses UIImagePickerControllerSourceTypeCamera - as a fullscreen presented view controller:
BOOL ok = [UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera];
if (!ok) {
NSLog(#"no camera");
return;
}
NSArray* arr = [UIImagePickerController availableMediaTypesForSourceType:
UIImagePickerControllerSourceTypeCamera];
if ([arr indexOfObject:(NSString*)kUTTypeImage] == NSNotFound) {
NSLog(#"no stills");
return;
}
UIImagePickerController* picker = [UIImagePickerController new];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.mediaTypes = #[(NSString*)kUTTypeImage];
picker.delegate = self;
[self presentViewController:picker animated:YES completion:nil];
If you want to present a live picture-taking interface inside your own interface, use AVFoundation and the camera capture API that it gives you.
Downloadable working example here:
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch30p816cameraCaptureWithAVFoundation/p683cameraCaptureWithAVFoundation/ViewController.m
Perhaps you'll consider this answer unhelpful; but I'll just paste a snippet from Apple's documentation:
Important: The UIImagePickerController class supports portrait mode only. This class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified, with one exception. You can assign a custom view to the cameraOverlayView property and use that view to present additional information or manage the interactions between the camera interface and your code.
UIImagePickerController Doc Link
Sorry to be a kill-joy. You should look for a replacement class. Quickie search shows there are a bunch.

Pop up UIViewController with an IBAction UIViewController

Is it possible to pop up an UIViewController (xib file) like UIPopOverControl in iPad ?
I have a separate NIB file which is linked to an UIViewController. I want to popup that NIB file along with the button pressed with a customised size (200,200).
Is this possible?
I am trying to get something like this on the iPhone - http://www.freeimagehosting.net/c219p
You can also use one of these custom made clases to show a popup:
https://github.com/sonsongithub/PopupView
https://github.com/werner77/WEPopover
https://github.com/50pixels/FPPopover
Example with FPPopover:
//the view controller you want to present as popover
YourViewController *controller = [[YourViewController alloc] init];
//our popover
FPPopoverController *popover = [[FPPopoverController alloc] initWithViewController:controller];
//the popover will be presented from the okButton view
[popover presentPopoverFromView:okButton];
//release if you arent using ARC
[controller release];
yes it is. load Your pOpOver controller lazily at the point when it is needed. add its view as a subview (you could animate the addition). make its frame size what You need and add the image You have shown as a background subview of the pOpOver controller along with other controls You want in the pop up.
good luck
UPDATE:
alright, ii will show You how ii do this in my app Lucid Reality Check (deployment target iOS4.3).
one can use a UIPopoverController to present another controllers view. what ii do first is to make sure ii always know the current orientation of the device, so ii can reposition the popup on rotation (maybe this works by itself on iOS6?). so in my base controller (from where ii want to show a popup) ii have an instance variable like this:
UIInterfaceOrientation toOrientation;
and also:
UIPopoverController *popover;
UIButton *popover_from_button;
BOOL representPopover;
popover will be reused for all popups, and popover_from_button will hold the button from which the popup is initiated.
then the next code comes into the base controller:
- (void)popoverWillRotate {
if ([popover isPopoverVisible]) {
[self dismissPopover];
representPopover = YES;
}
}
- (void)popoverDidRotate {
if (popover && representPopover) {
representPopover = NO;
[self representPopover];
}
}
these two methods have to be called every time the device is rotated, like this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
//DLOG(#"willRotateTo %i", toInterfaceOrientation);
toOrientation = toInterfaceOrientation;
if ([Kriya isPad ]) {
[self popoverWillRotate];
}
}
as one can see, first the orientation is captured then popoverWillRotate is called. this would hide the popover during the orientation animation. and after rotating, the popover must be redisplayed like this:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
//DLOG(#"didRotateFrom %i", fromInterfaceOrientation);
//[self layout:toOrientation]; //do some layout if You need
if ([Kriya isPad]) {
[self popoverDidRotate];
}
}
- (void)layout:(UIInterfaceOrientation)toInterfaceOrientation {
//one can do view layout here, and call other controllers to do their layout too
}
now that the orientation changes are worked out, the code for presenting the popover arrives here:
#pragma mark Popovers
- (void)presentPopoverWith:(id)controller fromButton:(UIButton*)button {
if (popover)
[popover release];
if (popover_from_button)
[popover_from_button release];
popover_from_button = [button retain];
popover = [[UIPopoverController alloc] initWithContentViewController:controller];
[popover setDelegate:self];
[self representPopover];
}
- (void)representPopover{
if (popover) {
UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirectionAny;
UIViewController *vc = (UIViewController*)[popover contentViewController];
CGSize contentSize = [vc contentSizeForViewInPopover];
if (contentSize.width > 0 && contentSize.height > 0) {
[popover setPopoverContentSize:contentSize animated:NO];
}
//DLOG(#"representPopover rect:%#", [Kriya printRect:popover_from_button.frame]);
[popover presentPopoverFromRect:CGRectOffset(popover_from_button.frame, 0, popover_from_button.frame.size.height + 7.0) inView:self.view permittedArrowDirections:arrowDirection animated:YES];
}
}
- (void)dismissPopover {
if (popover) {
[popover dismissPopoverAnimated:YES];
}
}
finally, if one wants to be notified when the popover is dismissed, the base controller must implement a delegate method:
#pragma mark UIPopoverControllerDelegate
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
//do something important here like drink some water
}
and don't forget to make the base controller a UIPopoverControllerDelegate in its header.
a use case for this way of doing popups would then look like this:
- (void)takeImage {
UIImagePickerController *picker = [[[UIImagePickerController alloc] init] autorelease];
[picker setDelegate:self];
[picker setAllowsEditing:NO];
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[picker setSourceType:UIImagePickerControllerSourceTypeCamera];
if ([Kriya isPad]) {
[self presentPopoverWith:picker fromButton:backgroundImageButton];
} else {
//modals on iPhone/iPod
//DLOG(#"takeImage addSubview picker");
[self presentModalViewController:picker animated:YES];
}
} else {
//DLOG(#"no camera");
}
}
this would use an image picker as the content for the popup, but one can use any controller with a valid view. so just do this:
[self presentPopoverWith:popupsContentController fromButton:tappedButton];
one should not have any missing information, :), the method [Kriya isPad] is just this:
+ (BOOL)isPad {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
// iPad capable OS
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
//this is an iPad
return YES;
}else {
//this is an iPod/iPhone
return NO;
}
#else
//can not pissible be iPad
return NO;
#endif
}
ENJOY!

iOS 6 Orientation with Navigation Controller

I have an app that works fine on ios 5,im trying to upgrade my app to work on ios 6, i had read tons of questions and tutorials about using ios 6 orientation,
my problem is when i call my rootViewController its work fine with me, but when i push any viewController the orientation look so bad because i use the orientation to change the view sizes (my app support any orientation)
here is my code:
AppDelegate:
UINavigationController *nav =[ [UINavigationController alloc] initWithRootViewController:theView] ;
self.window.rootViewController = nav;
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window // iOS 6
{
return UIInterfaceOrientationMaskAll;
}
myFirstViewController:
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[self viewWillAppear:NO];
}
-(BOOL)shouldAutorotate{
return YES;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:NO];
if ( [[UIDevice currentDevice].systemVersion floatValue] >= 6.0){
if (pointRange.location != NSNotFound) {
UIInterfaceOrientation interfaceOrientation = [[UIDevice currentDevice] orientation];
if( (interfaceOrientation >= 3) ) {
width=1024;
self.view.frame=CGRectMake(0, 0, 1024, 768);
}
if ( (interfaceOrientation == 1) || (interfaceOrientation == 2 )) {
width=768;
self.view.frame=CGRectMake(0, 0, 768, 1024);
}}
....etc
and i did the same in my second view, Hope to find why!!
You could always make an extension to the UINavigationController like this
#implementation UINavigationController (RotationFix)
-(NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
-(BOOL)shouldAutorotate
{
return YES;
}
#end
even i suffered for 2 days.. gone through many tutorials, blogs, forums, even apple docs.
So far i came to know, In iOS 6 each template of the app should be handled in a different ways.
So far the discussions were only for view based app, and these changes were not working on navigation based app or tabBar based app.
Finally i got the solution, it like this
Implement a subclass of these two types UITabBarController or UINavigationController.
Got to know from this blog. Thanks to Shabbir for the solution.

initializing rootViewController from different xibs depending on the device the App runs on

Hey guys,
I Have the following Problem:
I have an IPad App and now I want it to run on IPhone also. (I know it should be the other way round, but I cant change it).
So now i want to decide which view i need by using:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// The device is an iPad running iOS 3.2 or later.
}
else {
// The device is an iPhone or iPod touch.
}
This works well for all views exept the RootViewController.
No Matter where i set the xib for the RootViewController, it always displays the one i defined for the IPad-App.
This is my Code in the App-Delegate:
viewController = [VoycerUniversalAppViewController sharedInstance];
UINavigationController *myNavigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
[self.window addSubview:myNavigationController.view];
//[self.window addSubview:self.vcSplashScreen.view];
[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
And this is the Code in my [VoycerUniversalAppViewController sharedInstance]:
+ (VoycerUniversalAppViewController*) sharedInstance
{
#synchronized(self)
{
if(sharedInstance == nil)
{
// only allocate here - assignment is done in the alloc method
if (![AppState sharedInstance].loggedIn)
{
[AppState sharedInstance ].loggedIn = FALSE;
}
}
}
return sharedInstance;
}
+ (id) allocWithZone:(NSZone*)zone {
#synchronized(self) {
if(sharedInstance == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
// The device is an iPad running iOS 3.2 or later.
NSLog(#"The device is an iPad running iOS 3.2 or later.");
sharedInstance = [[super allocWithZone:zone] initWithNibName:#"VoycerUniversalAppViewController" bundle:nil];
}
else {
// The device is an iPhone or iPod touch.
NSLog(#"The device is an iPhone or iPod touch.");
sharedInstance = [[super allocWithZone:zone] initWithNibName:#"VoycerUniversalAppIPhoneViewController" bundle:nil];
}
// allocate and assign instance variable on first allocation
return sharedInstance;
}
}
return nil;
}
I looked almost everywhere i think if i missed some setting or something, but i couldnt find any.
Does anyone of you have an idea, why constantly loads the VoycerUnversalAppViewController instead of the other one?
Both Xibs are linked to the same class.
If the solution is a quite simple one and obvious please don't blame me, i'm really new to xcode, IB and objective-c (i code in objective-c for 1 1/2 month now).
Thx in advance.
Maverick1st.
For the main NIB, there are settings in the info.plist file: NSMainNibFile and NSMainNibFile~ipad.
In the NIB file you can create the application delegate and set up a navigation controller.