I am new to Objective c Native coding in IOS. I am having two buttons. One to lock the app to portrait and another lock the landscape orientation. What should I do to achieve this. Locking in the sense it will fix to the locked side and will not turn.
Yes i have used a method to implement the same using ios plugin which i created in worklight(For hybrid apps).
The function for setting the flag is
#import "HelloworlPlugin.h"
#implementation HelloworlPlugin
int count=0;
-(void)sayhello:(NSMutableArray *)arguments withDict:(NSMutableDictionary *)option
{
[arguments pop];
NSString *responseString=[NSString stringWithFormat:#"%#",[arguments objectAtIndex:0]];
if([responseString isEqualToString:#"1"])
{
count=1;
}
else
{
count=0;
}
NSLog(#"Zero %#",responseString);
}
-(int)count1
{
NSLog(#"count= %d",count);
if(count<1)
{
Cv=0;
}
else
{
Cv=1;
}
NSLog(#"%d",Cv);
return Cv;
}
#end
Where in say hello function i get the arguments from the hybrid app and based on that i set the flag variable Cv to 1 or 0.
Below is the default method which i have changed little bit to do my implementation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
HelloworlPlugin *object=[[HelloworlPlugin alloc] init];
int fValue=[object count1];
NSLog(#"%d",fValue);
if(fValue==1)
{
return (interfaceOrientation ==UIInterfaceOrientationPortrait);
}
else
{
return true;
}
}
shouldAutorotateToInterfaceOrientation
is a thing that is default function based on which the orientation is set returning true set all the orientation else by giving the approriate orientation we can set the answer.So here based on the cv value i stored in fValue i have locked the orientation.
For example this way:
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];
Related
When I show an alert with UIAlertController, the alert itself presented in a new window. (for now at least) And when the alert window dismisses, system seems to set a random window key-window.
I am presenting a new "banner" window to render some banners over status-bar (AppStore compatibility is out of topic here), and usually, this "banner" window becomes next key window, and causes many problems on user input and first responder management.
So, I want to prevent this "banner" window to become a key window, but I cannot figure out how. For now, as a workaround, I am just re-setting my main window to be a key window again as soon as that "banner" window becomes key window. But it doesn't feel really good.
How can I prevent a window to become a key window?
As a workaround, we can set main window key again as soon as the "banner" window becomes a key like this.
class BannerWindow: UIWindow {
weak var mainWindow: UIWindow?
override func becomeKeyWindow() {
super.becomeKeyWindow()
mainWindow?.makeKeyWindow()
}
}
Faced with this too. It seems that it's enough to just make:
class BannerWindow: UIWindow {
override func makeKey() {
// Do nothing
}
}
This way you don't need to keep a reference to a previous keyWindow, which is especially cool if it might get changed.
For Objective-C it's:
#implementation BannerWindow
- (void)makeKeyWindow {
// Do nothing
}
#end
I've been trying to solve this problem for years. I finally reported a Radar for it: http://www.openradar.me/30064691
My workaround looks something like this:
// a UIWindow subclass that I use for my overlay windows
#implementation GFStatusLevelWindow
...
#pragma mark - Never become key
// http://www.openradar.me/30064691
// these don't actually help
- (BOOL)canBecomeFirstResponder
{
return NO;
}
- (BOOL)becomeFirstResponder
{
return NO;
}
- (void)becomeKeyWindow
{
LookbackStatusWindowBecameKey(self, #"become key window");
[[self class] findAndSetSuitableKeyWindow];
}
- (void)makeKeyWindow
{
LookbackStatusWindowBecameKey(self, #"make key window");
}
- (void)makeKeyAndVisible
{
LookbackStatusWindowBecameKey(self, #"make key and visible window");
}
#pragma mark - Private API overrides for status bar appearance
// http://www.openradar.me/15573442
- (BOOL)_canAffectStatusBarAppearance
{
return NO;
}
#pragma mark - Finding better key windows
static BOOL IsAllowedKeyWindow(UIWindow *window)
{
NSString *className = [[window class] description];
if([className isEqual:#"_GFRecordingIndicatorWindow"])
return NO;
if([className isEqual:#"UIRemoteKeyboardWindow"])
return NO;
if([window isKindOfClass:[GFStatusLevelWindow class]])
return NO;
return YES;
}
void LookbackStatusWindowBecameKey(GFStatusLevelWindow *self, NSString *where)
{
GFLog(GFError, #"This window should never be key window!! %# when in %#", self, where);
GFLog(GFError, #"To developer of %#: This is likely a bug in UIKit. If you can get a stack trace at this point (by setting a breakpoint at LookbackStatusWindowBecameKey) and sending that stack trace to nevyn#lookback.io or support#lookback.io, I will report it to Apple, and there will be rainbows, unicorns and a happier world for all :) thanks!", [[NSBundle mainBundle] gf_displayName]);
}
+ (UIWindow*)suitableWindowToMakeKeyExcluding:(UIWindow*)notThis
{
NSArray *windows = [UIApplication sharedApplication].windows;
NSInteger index = windows.count-1;
UIWindow *nextWindow = [windows objectAtIndex:index];
while((!IsAllowedKeyWindow(nextWindow) || nextWindow == notThis) && index >= 0) {
nextWindow = windows[--index];
}
return nextWindow;
}
+ (UIWindow*)findAndSetSuitableKeyWindow
{
UIWindow *nextWindow = [[self class] suitableWindowToMakeKeyExcluding:nil];
GFLog(GFError, #"Choosing this as key window instead: %#", nextWindow);
[nextWindow makeKeyWindow];
return nextWindow;
}
I am using ZBarSDK for QR Code scanning feature. I want to use this only in PORTRAIT mode only. As per the documentation I set it up with below code line:
_reader.supportedOrientationsMask = ZBarOrientationMask(UIInterfaceOrientationPortrait);
As expected it works well with iOS 5 but with the same code this view changes orientation for iOS 6 & 7. Is supportedOrientationsMask only works with < iOS 6? Is there any other way to force this ZBar reader camera view to work only in Portrait mode? Thanks in advance
Here more details with Code:
if(_reader) // first check `_reader` is created or not?
{
[_reader.readerView stop]; // then stop continue scanning stream of "self.ZBarReaderVC"
for(UIView *subViews in _reader.view.subviews) // remove all subviews
[subViews removeFromSuperview];
[_reader.view removeFromSuperview];
_reader.view = nil;
}
_reader = [ZBarReaderViewController new];
_reader.readerDelegate = self;
_reader.supportedOrientationsMask = ZBarOrientationMask(UIInterfaceOrientationPortrait);
ZBarImageScanner *scanner = _reader.scanner;
// EXAMPLE: disable rarely used I2/5 to improve performance
[scanner setSymbology: ZBAR_I25
config: ZBAR_CFG_ENABLE
to: 0];
[_reader.view setFrame:CGRectMake(0, _topbar.frame.size.height, self.view.bounds.size.width, self.view.bounds.size.height-_topbar.frame.size.height)];
_reader.cameraOverlayView = [self CommomOverlay];
_reader.showsZBarControls=NO;
// present and release the controller
[self presentModalViewController: _reader
animated: NO];
Let me know in case more details required.
Finally found the solution.
The problem was like this:
ZbarViewController *reader was presented from my current view controller and it's portrait support property was not working somehow.
_reader.supportedOrientationsMask = ZBarOrientationMask(UIInterfaceOrientationPortrait);
What i did to resolve this issue is I created TBZbarViewController the new class which was inheriting the ZbarViewController class and placed the below method.
-(BOOL)shouldAutorotate{
return NO;
}
Then I used the TBZbarViewController *reader to present from My controller which solved the issue and it's working in Portrait mode only as needed.
Thanks.
I did like this, and is working for all iOS versions :
Step 1 : Set your Device Orientation
Step 2 : Add this code into you implementation (.m) file.
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_6_0
- (BOOL) shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskPortrait;
}
#endif
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait) || (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
I need to use different xib files for portrait and landscape. I am not using Auto Layout but I am using iOS6. (See my previous question if you care why.)
I'm following Adam's answer to this question modified with amergin's initWithNib name trick, modified with my own iPhone/iPad needs. Here's my code:
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[[NSBundle mainBundle] loadNibNamed:[self xibNameForDeviceAndRotation:toInterfaceOrientation]
owner: self
options: nil];
[self viewDidLoad];
}
- (NSString *) xibNameForDeviceAndRotation:(UIInterfaceOrientation)toInterfaceOrientation
{
NSString *xibName ;
NSString *deviceName ;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
deviceName = #"iPad";
} else {
deviceName = #"iPhone";
}
if( UIInterfaceOrientationIsLandscape(toInterfaceOrientation) )
{
xibName = [NSString stringWithFormat:#"%#-Landscape", NSStringFromClass([self class])];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
xibName = [NSString stringWithFormat:#"%#_%#-Landscape", NSStringFromClass([self class]), deviceName];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
NSAssert(FALSE, #"Missing xib");
return nil;
}
}
} else {
xibName = [NSString stringWithFormat:#"%#", NSStringFromClass([self class])];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
xibName = [NSString stringWithFormat:#"%#_%#", NSStringFromClass([self class]), deviceName];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
NSAssert(FALSE, #"Missing xib");
return nil;
}
}
}
}
and of course I'm doing:
- (BOOL) shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
in my view controller and:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown);
}
in my delegate.
I have two problems which may be related. First, the easy one. I do not rotate upside down. I have all all the proper bits turned on in xcode for both iPad and iPhone. This may be a separate issue or it may be the core of my problem.
The real problem is that when I rotate to landscape mode my xib is replace but the view is off by 90 degrees.
Here's what my 2 xib's look like. (I've colored them garishly so you can see that they are different.)
and
and you can see when I run it (initially in Landscape mode) that the landscape xib is correct.
when I rotate to portrait it is also correct
but when I rotate back to landscape the xib is replaced but the view is off by 90 degrees.
What's wrong here?
I've been following probably the same path as Paul Cezanne did last year. Not sure if he tried this or not, but I solved the original issue (stated in this question) by just making my root controller a navigation controller instead of my view controller class. Since I'm using an "empty project" template and XIB files, this meant changing the normal:
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
inside AppDelegate.m, to this instead:
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
navigationController.navigationBar.hidden = YES;
self.window.rootViewController = navigationController;
That is, I just created a generic UINavigationController and set that as the root view controller.
I'm not sure if this will cause other problems, and there is probably a way to figure out (maybe you would need the source code though) what UINavigationController does that UIViewController doesn't. Could be as simple as one extra setNeedsLayout type of call in the right place. If I figure it out, I'll edit this answer for future readers.
Credit goes to Sakti's comments on Easiest way to support multiple orientations? How do I load a custom NIB when the application is in Landscape? which I shouldn't have ignored the first time I read them:
i added the view controller to navigation controller and presented it
which made it work as intended
Edit: Added extra line to example code to hide navigation bar, since most people following this issue will not want that.
This is how I do it and it works on iOS 5+:
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(checkBagRotation)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:nil];
[self checkBagRotation];
}
- (void)checkBagRotation {
orientation = [UIApplication sharedApplication].statusBarOrientation;
if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
[[NSBundle mainBundle] loadNibNamed:#"Controller-landscape"
owner:self
options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:#"Controller-portrait"
owner:self
options:nil];
}
I'm answering my own question here pasting from the full article on my iOS blog at http://www.notthepainter.com/topologically-challenged-ui/
I had a friend help me out, he used 2 views in one xib file with IBOutlets for portrait and landscape view and he toggled between them the device rotated. Perfect, right? Well, no, when you have 2 views in a XIB you can’t hook up your IBOutlets to both places. I had it working visually but my controls only worked in one orientation.
I eventually came up with the idea of using a orientation master view controller that loaded container view controllers when the device rotated. That worked fine. Lets look at the code:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
if (_timerViewController) {
[_timerViewController.view removeFromSuperview];
[_timerViewController willMoveToParentViewController:nil];
[_timerViewController removeFromParentViewController];
self.timerViewController = nil;
}
self.timerViewController = [[XTMViewController alloc] initWithNibName:
[self xibNameForDeviceAndRotation:interfaceOrientation withClass:[XTMViewController class]]
bundle:nil];
// use bounds not frame since frame doesn't take the status bar into account
_timerViewController.view.frame = _timerViewController.view.bounds = self.view.bounds;
[self addChildViewController:_timerViewController];
[_timerViewController didMoveToParentViewController:self];
[self.view addSubview: _timerViewController.view];
}
The addChildViewController and didMoveToParentViewController should be familiar if you read my previous blog entry on Container View Controllers. There are two things to notice above those calls though. I’ll deal with the second one first, I set the child view controller’s frame and bounds from the parents bounds, not frame. This is to take account of the status bar.
And notice the call to xibNameForDeviceAndRotation to load the view controller from its xib file. Lets look at that code:
- (NSString *) xibNameForDeviceAndRotation:(UIInterfaceOrientation)toInterfaceOrientation withClass:(Class) class;
{
NSString *xibName ;
NSString *deviceName ;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
deviceName = #"iPad";
} else {
deviceName = #"iPhone";
}
if( UIInterfaceOrientationIsLandscape(toInterfaceOrientation) ) {
xibName = [NSString stringWithFormat:#"%#-Landscape", NSStringFromClass(class)];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
xibName = [NSString stringWithFormat:#"%#_%#-Landscape", NSStringFromClass(class), deviceName];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
NSAssert(FALSE, #"Missing xib");
return nil;
}
}
} else {
xibName = [NSString stringWithFormat:#"%#", NSStringFromClass(class)];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
xibName = [NSString stringWithFormat:#"%#_%#", NSStringFromClass(class), deviceName];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
NSAssert(FALSE, #"Missing xib");
return nil;
}
}
}
return nil;
}
There’s a lot going on here. Let’s go over it. I first determine if you are on an iPhone or an iPad. The xib files will have iPhone or iPad in their names. Next we check to see if we are in landscape mode. If we are, we build a test string from the class name, using class reflection via NSStringFromClass. Next, we use pathForResource to check to see if the xib exists in our bundle. If it does, we return the xib name. If it doesn’t, we try again also putting the device name into the xib name. Return it if it exists, assert a failure if it doesn’t. Portrait is similar except by convention we don’t put “-Portrait” into the xib name.
This code is useful enough and generic enough that I’ll put it in my EnkiUtils open source project.
Since this is iOS6 we need to put in the iOS6 rotation boilerplate code:
- (BOOL) shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
Curiously we also need to manually call willAnimateRotationToInterfaceOrientation on iPads. iPhones get a willAnimateRotationToInterfaceOrientation automatically but iPads do not.
- (void) viewDidAppear:(BOOL)animated
{
// iPad's don't send a willAnimate on launch...
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[self willAnimateRotationToInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation] duration:0];
}
}
So, are we finished? Embarrassingly no. You see, when I coded the XTMViewController class I broke the Model-View-Controller design pattern! This is easy to do, Apple already helps us by putting the View and the Controller into the same class. And it is so easy to carelessly mix in Model data in the VC’s .h file. And I had done exactly that. When I run the above code it work brilliantly, I could rotate it all day and the UI was correct in both orientations. But what do you think happened when I rotated the device while my exercise timers were running? Yup, they were all deleted and the UI reset to the initial state. This was not at all what I wanted!
I made a XTMUser class to hold all the timing data, I put all the NSTimers into the XTMOrientationMasterViewController class and then I made a protocol so the XTMOrientationMasterViewController could respond to UI taps in the XTMViewController class.
Then I was done.
I am getting empty string when using StringByEvaluatingJavascriptFromString that is reading a javascript function. I am using a StringByEvalutaingJavascriptFromString in ShouldAutoRotateToInterfaceOrientation because i want to control supported orientations on specific pages.
It seems that i need to use it webViewDidFinishLoad.
But how to control supported orientations on specific pages using StringByEvalutaingJavascriptFromString.
Or how to use it in ShouldAutoRotateToInterfaceOrientation.
I followed this tutorial: link
and he is using it in ShouldAutoRotateToInterfaceOrientation and not in webViewDidFinishLoad
this is my code in MainViewController.m:
- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
NSString *isFirstPage = [self.webView stringByEvaluatingJavaScriptFromString: #"isFirstPage();"];
NSString *truth = #"true";
if ([isFirstPage isEqualToString:truth]) {
return [super shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
else {
return interfaceOrientation==UIInterfaceOrientationPortrait;
}
}
and isFirstPage is return a empty string #"".
function isFirstPage(){
return true;
}
So I have incorporated Mr. Grant Davis' FGallery into my app for a photo gallery. It works great other than it is overriding all my rotation methods in my other views and I cannot for the life of me figure out how to stop it. Here's a snippet from FGallery's FGalleryViewController that handles the gallery:
#implementation UINavigationController (FGallery)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if([self.visibleViewController isKindOfClass:[FGalleryViewController class]]) {
return YES;
}
// we need to support at least one type of auto-rotation we'll get warnings.
// so, we'll just support the basic portrait.
return ( interfaceOrientation == UIInterfaceOrientationPortrait ) ? YES : NO;
}
I have tried changing the line:
return ( interfaceOrientation == UIInterfaceOrientationPortrait ) ? YES : NO;
but that forces all views to that specific orientation. Some of my views allow for rotation and some do not. So I guess my question is, how can I alter this line to allow rotation in some views and not in others? I'm drawing a blank this morning!!
Any help or ideas here would be appreciated!!
So I'm gonna go ahead and answer my own question.
The answer is to remove the code that overrides the rotation:
#implementation UINavigationController (FGallery)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if([self.visibleViewController isKindOfClass:[FGalleryViewController class]])
{
return YES;
}
// we need to support at least one type of auto-rotation we'll get warnings.
// so, we'll just support the basic portrait.
return ( interfaceOrientation == UIInterfaceOrientationPortrait ) ? YES : NO;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// see if the current controller in the stack is a gallery
if([self.visibleViewController isKindOfClass:[FGalleryViewController class]])
{
FGalleryViewController *galleryController = (FGalleryViewController*)self.visibleViewController;
[galleryController resetImageViewZoomLevels];
}
}
#end
And call:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
within #implementation FGalleryViewController
Hopefully this helps someone else out that needs it.