I am trying to work on iOS app , one viewController portrait , one viewController using GoogleMap landscape orientation as follows :
When it comes to the implementation and testing, it shows :
I am not sure how it could be when running on iPhone 6 iOS 8.3 . it seems that setting device orientation and interface orientation are different parameters have to be set. I have
AppDelegate.m
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
ViewControllerA.m
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
ViewControllerB.m
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
isPresented = YES;
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
[[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeRight];
}
viewDidLoad ...
GMSMarker *marker = [[GMSMarker alloc] init];
NSLog(#"assadsd arrived map");
if(latitide!=0.00&&longitude!=0.00) {
CLLocationCoordinate2D position = CLLocationCoordinate2DMake(latitide, longitude);
marker.position = CLLocationCoordinate2DMake(position.latitude, position.longitude);
camera = [GMSCameraPosition cameraWithLatitude:latitide longitude:longitude zoom:12];
}else{
camera = [GMSCameraPosition cameraWithLatitude:22.2855200 longitude:114.1576900 zoom:12];
marker.position = CLLocationCoordinate2DMake(22.2855200, 114.1576900);
}
self.myMapView = [GMSMapView mapWithFrame:self.view.bounds camera:camera];
Could you please tell me the know-how to work as the first picture does ? It seems that iOS 8.3 has some orientation bug that has to re-=assign the correct view width and height but I am not sure how exactly it could work.
If you are using NavigationController then create navigationController subclass and override the shouldAutorotate method.
Related
I need to fix orientation portrait or landscapeLeft like Youtube's full screen.
When a user click button, it was changed portrait or landscapeLeft.
and was fixed.
The user can control only by button.
accept Device orientation Portrait, Landscape Left in General
It's my code
AppDelegate
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(restrictRotation)
return UIInterfaceOrientationMaskPortrait;
else
return UIInterfaceOrientationMaskLandscapeLeft;
}
ViewController
-(void) restrictRotation:(BOOL) restriction
{
AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
appDelegate->restrictRotation = restriction;
}
- (IBAction)rotateOrientationAction:(id)sender
{
[self restrictRotation:NO];
if(isPortrait){
[[UIDevice currentDevice] setValue:#(UIInterfaceOrientationLandscapeLeft) forKey:#"orientation"];
self.myNewScrollViewHeight.constant = self.view.frame.size.height - self.naviBar.frame.size.height - self.horizMenu.frame.size.height;
self.portraitMenuView.hidden = YES;
}else{
[[UIDevice currentDevice] setValue:#(UIInterfaceOrientationPortrait) forKey:#"orientation"];
self.myNewScrollViewHeight.constant = self.view.frame.size.height * 0.5;
self.portraitMenuView.hidden = NO;
}
isPortrait = !isPortrait;
[self restrictRotation:YES];
}
If I click the button, it was changed landscapeLeft but not changed portrait again.
Thank you
Your condition is not satisfied for restrictRotation, please check below code to desire result.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
isPortrait = YES;
}
-(void) restrictRotation:(BOOL) restriction
{
AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
appDelegate.restrictRotation = restriction;
}
- (IBAction)rotateOrientationAction:(id)sender
{
if (isPortrait) {
[self restrictRotation:NO];
[[UIDevice currentDevice] setValue:#(UIInterfaceOrientationLandscapeLeft) forKey:#"orientation"];
} else {
[self restrictRotation:YES];
[[UIDevice currentDevice] setValue:#(UIInterfaceOrientationPortrait) forKey:#"orientation"];
}
isPortrait = !isPortrait;
}
Update :
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
isPortrait = YES;
}
- (IBAction)rotateOrientationAction:(id)sender
{
AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
appDelegate.restrictRotation = NO;
[[UIDevice currentDevice] setValue:#(UIInterfaceOrientationPortrait) forKey:#"orientation"];
if (isPortrait)
{
[[UIDevice currentDevice] setValue:#(UIInterfaceOrientationLandscapeLeft) forKey:#"orientation"];
}
else
{
[[UIDevice currentDevice] setValue:#(UIInterfaceOrientationPortrait) forKey:#"orientation"];
}
isPortrait = !isPortrait;
}
It is an superclass file name Apporientationviewcontroller.h/m. And i am calling this super class in all other subclasses. So that if "isPortraitModeONN" is "ON"
then all the screen should work only in portrait mode. if user try to changes the device to landscape it should not rotate. it should be always in portrait mode if switch is "ON".. In my case while laughing the app it is in portrait mode. but if i rotate the screen it is changing towards landscape. but it should not change its orientation until turning OFF the switch in settings..
if(isPortraitModeONN)
{
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
}
else
{
if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft){
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
}
else if([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)
{
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];
}
else{
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
}
}
This code works for me somewhat..
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator: (id<UIViewControllerTransitionCoordinator>)coordinator
{
///if isPortraitMode On then force the orientation to portrait if it's other than Portrait
///else force the orientation to landscape
if (isPortraitModeONN)
{
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
// do whatever
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (UIInterfaceOrientationIsLandscape(orientation)) {
///App is rotating to landscape, force it to portrait
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
}];
}
else{
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
// do whatever
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (UIInterfaceOrientationIsPortrait(orientation)) {
///App is rotating to portrait, force it to landscape
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
}];
}
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
You can do like this-
Add - #property () BOOL isPortraitModeONN; in AppDelegate.h class.
Now code this in AppDelegate.m -
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.isPortraitModeONN=YES;
return YES;
}
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(self.isPortraitModeONN)
return UIInterfaceOrientationMaskPortrait;
else
return UIInterfaceOrientationMaskLandscape;
}
Now Add IBAction of UIButton for changing orientation in Apporientationviewcontroller.m--
- (IBAction)changeOrientation:(id)sender {
if (allowedToRotate) {
allowedToRotate=NO;
AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
appDelegate.isPortraitModeONN = NO;
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}else{
allowedToRotate=YES;
AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
appDelegate.isPortraitModeONN = YES;
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
}
define in Apporientationviewcontroller.m BOOL allowedToRotate; default value is YES;
Goto Target -> Deployment info -> set device Orientation to portrait only
As par your question if you want to do this by tapping on button
Please try this code i am not sure about this it works on your project but it works for my dummy project
please try it
[[UIDevice currentDevice] setValue:
[NSNumber numberWithInteger: UIInterfaceOrientationPortrait]
forKey:#"orientation"];
change the device orientation for both buttons
You code should be like this,
AppDelegate.h
#property () BOOL restrictRotation;
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window;
AppDelegate.m
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(self.restrictRotation)
return UIInterfaceOrientationMaskLandscape; //you can change upsidedown etc
else
return UIInterfaceOrientationMaskPortrait; // you can change landscape right or left only
//this should be your initial app orientation because by default value of bool is false
}
SettingsViewController (from where you want to change whole app orientations)
-(void) restrictRotation:(BOOL) restriction
{
AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
appDelegate.restrictRotation = restriction;
[appDelegate application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:self.view.window];
}
don't forget to import appdelegate.h ;)
And finally from your switch for changing orientation,
[self restrictRotation:YES]; // or NO
You can manipulate supportedInterfaceOrientationsForWindow as per requirement like you can set property as int instead of bool and can set multiple orientation for different int value.
hope this will help :)
I have a bit of a strange situation. I have a photo app that automatically sets the app orientation based upon the dimensions of the image loaded. I use the following code.
- (BOOL)prefersStatusBarHidden {
return YES;
}
- (BOOL) shouldAutorotate {
return NO;
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return NO;
}
- (IBAction)setRotation {
if(imageOriginal.size.height > imageOriginal.size.width){
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}else {
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
}
The problem is that lets say I load a portrait image into the app the UIImagePicker is in portrait mode. I now select a Landscape image and select the UIImagePicker again, instead of the picker now being in landscape mode it jumps back to portrait and looks pretty ugly.
Is there a better way to set the device orientation based upon the image or fix the problem above?
Found the solution needed to change the following code to make sure the UIImagePicker was in context.
- (IBAction)loadImage:(id)sender {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
-- > imagePicker.modalPresentationStyle = UIModalPresentationCurrentContext;
//imagePicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentViewController:imagePicker animated:NO completion:nil];
}
My app is a portrait only. I need to present a UIViewController in Landscape mode(Reason for that is I am using Core-Plot sdk for drawing graphs on that viewcontroller, so it needs to be in landscape mode).
I tried the following methods and it work fine. But the issue is, when I dismiss the landscape viewcontroller, app cannot force to portrait mode.
http://www.sebastianborggrewe.de/only-make-one-single-view-controller-rotate/
http://b2cloud.com.au/tutorial/forcing-uiviewcontroller-orientation/
How can I force the app to become portrait only mode after dismiss the landscape viewcontroller?
This is How I presenting the landscape view controller and dismissing it.
LineChartViewController *obj = [[LineChartViewController alloc]initWithNibName:#"LineChartViewController" bundle:nil];
[self.navigationController presentViewController:obj animated:YES completion:nil];
- (IBAction)btnDonePressed:(id)sender{
[self dismissViewControllerAnimated:NO completion:nil];
}
XIB of the LineChartViewController is in landscape mode.
In simple words, My app is portrait only, and I wanted to show CorePlot hostView in landscape mode.
Actually I could solve the issue by rotating the CorePlot hostView. The solution isn't the perfect for the the question described, but I'd like to put my solution here, since it solved my problem
self.hostView = [(CPTGraphHostingView *) [CPTGraphHostingView alloc] initWithFrame:self.viewGraphBack.bounds];
self.hostView.allowPinchScaling = YES;
[self.viewGraphBack addSubview:self.hostView];
CGAffineTransform transform =
CGAffineTransformMakeRotation(DegreesToRadians(90));
viewGraphBack.transform = transform;
viewGraphBack.frame = CGRectMake(-285, 0, 568, 320);
[self.view addSubview:viewGraphBack];
This kind of workaround works for me (temporary pushing fake model view controller), called after other view controller which introduces new orientation is demised:
- (void)doAWorkaroudnOnUnwantedRotation {
// check if is workaround nesesery:
if (UIInterfaceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
double delayInSeconds = 0.7;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
UIViewController *fake = [[[UIViewController alloc] init] autorelease];
UIViewController *rootController = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootController presentModalViewController: fake animated: NO];
[fake dismissModalViewControllerAnimated: NO];
});
}
}
If Parent viewcontroller in UIInterfaceOrientationPortrait mode & current viewcontroller should be in UIInterfaceOrientationLandscapeLeft or UIInterfaceOrientationLandscapeRight in that case you may use device orientation changing delegate & a few codes in viewdidload
In ViewDidLoad
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
& implement shouldAutorotateToInterfaceOrientation delegate in ViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) return YES;
return NO;
}
Like this. Assure that landscape mode must be checked in from target settings.
Write this category in your project
#import "UINavigationController+ZCNavigationController.h"
#implementation UINavigationController (ZCNavigationController)
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
#end
And in your viewcontroller where you need Landscape
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
I am currently working with Google Maps API in my project. I am trying to set the default camera/zoom to the users location. I do this:
#implementation ViewController{
GMSMapView *mapView_;
}
#synthesize currentLatitude,currentLongitude;
- (void)viewDidLoad
{
[super viewDidLoad];
mapView_.settings.myLocationButton = YES;
mapView_.myLocationEnabled = YES;
}
- (void)loadView{
CLLocation *myLocation = mapView_.myLocation;
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(myLocation.coordinate.latitude, myLocation.coordinate.longitude);
marker.title = #"Current Location";
marker.map = mapView_;
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:myLocation.coordinate.latitude
longitude:myLocation.coordinate.longitude
zoom:6];
mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.view = mapView_;
NSLog(#"%f, %f", myLocation.coordinate.latitude, myLocation.coordinate.longitude);
}
However, it does not work, since when I do
NSLog(#"%f, %f", myLocation.coordinate.latitude, myLocation.coordinate.longitude);
it returns 0, 0, and it does not give the current location coordinates. How can I properly get the user's coordinates?
.h
#import <CoreLocation/CoreLocation.h>
#property(nonatomic,retain) CLLocationManager *locationManager;
.m
- (NSString *)deviceLocation
{
NSString *theLocation = [NSString stringWithFormat:#"latitude: %f longitude: %f", locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude];
return theLocation;
}
- (void)viewDidLoad
{
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
}
answered here.
When an app first starts it may not yet know your location, as it usually takes a while for the GPS device to lock on to your location (if it has just been started), and especially if this is the first time the application has been run, and so the user hasn't yet answered the prompt to give the app access to their location. Also it seems like mapView.myLocation is always empty (either nil or has coordinates 0,0) when the map view has just been created.
So you will need to wait until the user's location is known, and then update the camera position.
One way might be using the code at how to get current location in google map sdk in iphone as suggested by Puneet, but note that the sample code there is missing the details of setting up the location manager (like setting the location manager's delegate), which might be why it didn't work for you.
Another option could be to use KVO on mapView.myLocation, as described here: about positioning myself,some problems
By the way in your sample code you are accessing mapView.myLocation before you create the mapView, and so the location would always be nil anyway.
I just Downloaded the new GoogleMap SDK Demo for iOS. Here is what I have seen from the source code that how the "Current Location" is achieved via KVO.
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#import "SDKDemos/Samples/MyLocationViewController.h"
#import <GoogleMaps/GoogleMaps.h>
#implementation MyLocationViewController {
GMSMapView *mapView_;
BOOL firstLocationUpdate_;
}
- (void)viewDidLoad {
[super viewDidLoad];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868
longitude:151.2086
zoom:12];
mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
mapView_.settings.compassButton = YES;
mapView_.settings.myLocationButton = YES;
// Listen to the myLocation property of GMSMapView.
[mapView_ addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
self.view = mapView_;
// Ask for My Location data after the map has already been added to the UI.
dispatch_async(dispatch_get_main_queue(), ^{
mapView_.myLocationEnabled = YES;
});
}
- (void)dealloc {
[mapView_ removeObserver:self
forKeyPath:#"myLocation"
context:NULL];
}
#pragma mark - KVO updates
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if (!firstLocationUpdate_) {
// If the first location update has not yet been recieved, then jump to that
// location.
firstLocationUpdate_ = YES;
CLLocation *location = [change objectForKey:NSKeyValueChangeNewKey];
mapView_.camera = [GMSCameraPosition cameraWithTarget:location.coordinate
zoom:14];
}
}
#end
Hope it can help you.
Just in case anyone wants DrDev's excellent answer in Swift 3:
var locationManager: CLLocationManager?
func deviceLocation() -> String {
let theLocation: String = "latitude: \(locationManager.location.coordinate.latitude) longitude: \(locationManager.location.coordinate.longitude)"
return theLocation
}
func viewDidLoad() {
locationManager = CLLocationManager()
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
// 100 m
locationManager.startUpdatingLocation()
}