I am writing an app that I would like to only be viewed in Landscape Mode. I have set it up so that if the iPhone is held in Portrait Mode, nothing happens and the current image remains in Landscape Mode. The iPhone Simulator starts out in Landscape Mode with the Home Button on the right. If the iPhone is rotated from one Landscape Mode to the other, animation then occurs and the view is adjusted. However, whenever the device is in Landscape Mode with the Home Button on the left, the image is 20 pixels higher than needed, revealing a white line at the bottom of the screen.
In spite of all attempts to logically adjust this such as
self.view.frame = CGRectMake (0,20, self.view.frame.size.width, self.view.frame.size.height)
it doesn't fix the problem. I am accounting for the Status Bar in my calculations.
The .xib file contains an UIImageView on top of a UIView. This is my first experience implementing these methods so I apologize if the solution is relatively easy. Below is the code for the two methods used to implement the Landscape Mode views.
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
//set up interface to only be viewed in Landscape
if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
return interfaceOrientation;
else if(interfaceOrientation == UIInterfaceOrientationLandscapeRight)
return interfaceOrientation;
else
return NO;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)tointerfaceOrientation duration:(NSTimeInterval)duration {
if(UIInterfaceOrientationLandscapeRight){
self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
else if (UIInterfaceOrientationLandscapeLeft) {
//shouldn't adjustment to 20 fix the view?
self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
else return;
}
For UIViews to adjust the subviews properly you will have to take a look at this UIView property: autoresizingMask, and set the mask to autoresize what is needed, if that does not work you will have to override:
- (void)layoutSubviews
From the reference: UIView reference
Related
I had a view with some textviews in it that were working as I wanted. The expanded to a the same right-margin whether in landscape or portrait.
I recently have tried changing the normal view to a scrollview. I've had no luck getting these text views to expand as they once did, though. When in landscape mode everything stays huddled over on the left side with the same width as a portrait phone.
Here is some code.
- (void)viewDidLoad {
CGSize screen = [self handleScreenOrientation];
[(UIScrollView *)self.view setContentSize:CGSizeMake(screen.width, screen.height)];
}
- (CGSize)handleScreenOrientation {
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown ) {
return CGSizeMake(screenRect.size.width, screenRect.size.height);
}
else {
return CGSizeMake(screenRect.size.height, screenRect.size.width);
}
}
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
CGSize screen = [self handleScreenOrientation:toInterfaceOrientation];
UIScrollView *scrollView = (UIScrollView *)self.view;
scrollView.frame = CGRectMake(0, 0, screen.width, screen.height);
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, scrollView.frame.size.height);
[scrollView setNeedsDisplay];
}
The method handleScreenOrientation with the passed orientation is the same as the one w/ no parameters, just it uses the passed orientation instead of the current orientation of the status bar.
I've checked and my scrollview is set to autoresize subviews.
Any ideas would be much appreciated. Thanks.
Update: I have added
self.view.autoresizesSubviews = true;
for (UIView *view in self.view.subviews) {
view.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth;
}
to viewdidload and willrotatetointerfaceorientation. No change.
I think the problem is that you are overriding the autoresizingMasks by forcing a change to the scrollView's contentSize. Although you have correctly noted that the screenSize is always in portrait orientation, so you reverse its dimensions for landscape, you are determining which orientation to use before the device actually rotates. So you're forcing the scrollView to maintain portrait dimensions in landscape.
Keep your autoresizeMask routine and discard your willRotateToInterfaceOrientation routine. Does it work now?
If not, try putting the willRotate code into *did*RotateToInterfaceOrientation.
Another idea:
I notice that in viewDidLoad you cast the container view (self.view) to a UIScrollView. I wonder if it might be better to leave the container view as a generic UIView, add a UIScrollView as a subview, and then add the textviews to the scrollview.
I might be out in left field here, but I've never used a scrollview directly at the container-view level, and I wonder if that might be the problem.
So this will almost certainly be a simple answer, but I can't for the life of me work it out!
Basically, I want my current app to be viewable in portrait only (for now at least) and either the right way up, or upside down. Everything works fine the right way up and when you rotate the iPad on a page, everything works fine, the page flips up as normal. But if you hold the iPad upside down (home button at the top) and click a button to load a new page, when the page loads the toolbar is not visible! I don't know if for some reason the toolbar is behind the rest of the content or if its not there. If you then rotate the iPad back to portrait, the toolbar appears and all is back to normal again!
Whats weirder is that on the iPhone, the toolbar is there when you load a page with an upside down iPhone!!
I've tried all sorts with the shouldAutorotateToInterfaceOrientation() and didRotateFromInterfaceOrientation() methods and with resizing/positioning on viewDidLoad depending on the orientation. But nothing seems to work at all!!
This is code I have in my viewDidLoad() method:
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
NSLog(#"iPhone");
if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortrait)
{
self.view.frame = CGRectMake(0, 0, 320, 460);
}
else if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortraitUpsideDown)
{
self.view.frame = CGRectMake(0, 20, 320, 460);
}
}
else
{
NSLog(#"iPad");
if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortrait)
{
self.view.frame = CGRectMake(0, 0, 768, 1024);
NSLog(#"iPad Portrait Up");
}
else if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortraitUpsideDown)
{
self.view.frame = CGRectMake(0, 20, 768, 1024);
NSLog(#"iPad Portrait Upside Down");
}
}
I've tried similar things in the didRotateFromInterfaceOrientation() method but nothing is working!
Thanks in advance for any help and feel free to ask questions/request more code
Matt
I ran into similar problem and here is what I discovered. When You add a toolbar at the top of the iPad UIView xib file, its autosizing is default to set up as shown in figure below. The toolbar will always stick to the bottom instead of the top.
What I did is change it to stick to top as shown in figure below and it fixed my problem.
If you setup the toolbar programmatically, you need to update the autoresizingMask.
This should be a pretty common thing to do, but I haven't been able to get it to work exactly right.
I have rectangular content. It normally fits in 320x361: portrait mode minus status bar minus ad minus tab bar.
I have put that content in a UIScrollView and enabled zooming. I also want interface rotation to work. The content will always be a tall rectangle, but when zoomed users might want to see more width at a time and less height.
What do I need to do in Interface Builder and code to get this done? How should I set my autoresizing on the different views? How do I set my contentSize and contentInsets?
I have tried a ton of different ways and nothing works exactly right. In various of my solutions, I've had problems with after some combination of zooming, interface rotation, and maybe scrolling, it's no longer possible to scroll to the entire content on the screen. Before you can see the edge of the content, the scroll view springs you back.
The way I'm doing it now is about 80% right. That is, out of 10 things it should do, it does 8 of them. The two things it does wrong are:
When zoomed in portrait mode, you can scroll past the edge of the content, and see a black background. That's not too much to complain about. At least you can see all the content. In landscape mode, zoomed or not, seeing the black background past the edge is normal, since the content doesn't have enough width to fill the screen at 1:1 zoom level (the minimum).
I am still getting content stuck off the edge when it runs on a test device running iOS 3.0, but it works on mine running 4.x. -- Actually that was with the previous solution. My tester hasn't tried the latest solution.
Here is the solution I'm currently using. To summarize, I have made the scroll view as wide and tall as it needs to be for either orientation, since I've found resizing it either manually or automatically adds complexity and is fragile.
View hierarchy:
view
scrollView
scrollableArea
content
ad
view is 320x411 and has all the autoresizing options on, so conforms to screen shape
scrollView is 480 x 361, starts at origin -80,0, and locks to top only and disables stretching
scrollableArea is 480 x 361 and locks to left and top. Since scrollView disables stretching, the autoresizing masks for its subviews don't matter, but I tell you anyway.
content is 320x361, starts at origin 80,0, and locks to top
I am setting scrollView.contentSize to 480x361.
shouldAutorotateToInterfaceOrientation supports all orientations except portrait upside down.
In didRotateFromInterfaceOrientation, I am setting a bottom content inset of 160 if the orientation is landscape, resetting to 0 if not. I am setting left and right indicator insets of 80 each if the orientation is portrait, resetting if not.
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 2.0
viewForZoomingInScrollView returns scrollableArea
// in IB it would be all options activated
scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
scrollView.contentSize = content.frame.size; // or bounds, try both
what do you mean with scrollableArea?
your minZoomScale is set to 1.0 thats fine for portrait mode but not for landscape. Because in landscape your height is smaller than in portrait you need to have a value smaller than 1.0. For me I use this implementation and call it every time, the frame of the scrollView did change:
- (void)setMaxMinZoomScalesForCurrentBounds {
CGSize boundsSize = self.bounds.size; // self is a UIScrollView here
CGSize contentSize = content.bounds.size;
CGFloat xScale = boundsSize.width / contentSize.width;
CGFloat yScale = boundsSize.height / contentSize.height;
CGFloat minScale = MIN(xScale, yScale);
if (self.zoomScale < minScale) {
[self setZoomScale:minScale animated:NO];
}
if (minScale<self.maximumZoomScale) self.minimumZoomScale = minScale;
//[self setZoomScale:minScale animated:YES];
}
- (void)setFrame:(CGRect)rect { // again, this class is a UIScrollView
[super setFrame:rect];
[self setMaxMinZoomScalesForCurrentBounds];
}
I don't think I understood the entire problem from your post, but here's an answer for what I did understand.
As far as I know (and worked with UIScrollView), the content inside a UIScrollView is not automatically autoresized along with the UIScrollView.
Consider the UIScrollView as a window/portal to another universe where your content is. When autoresizing the UIScrollView, you are only changing the shape/size of the viewing window... not the size of the content in the other universe.
However, if needed you can intercept the rotation event and manually change your content too (with animation so that it looks good).
For a correct autoresize, you should change the contentSize for the scrollView (so that it knows the size of your universe) but also change the size of UIView. I think this is why you were able to scroll and get that black content. Maybe you just updated the contentSize, but now the actuall content views.
Personally, I haven't encountered any case that required to resize the content along with the UIScrollView, but I hope this will get you started in the right direction.
If I understand correctly is that you want a scrollview with an image on it. It needs to be fullscreen to start with and you need to be able to zoom in. On top of that you want it to be able to rotate according to orientation.
Well I've been prototyping with this in the past and if all of the above is correct the following code should work for you.
I left a bit of a white area for the bars/custombars.
- (void)viewDidLoad
{
[super viewDidLoad];
//first inits and allocs
scrollView2 = [[UIScrollView alloc] initWithFrame:self.view.frame];
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"someImageName"]];
[scrollView2 addSubview:imageView];
[self drawContent]; //refreshing the content
[self.view addSubview:scrollView2];
}
-(void)drawContent
{
//this refreshes the screen to the right sizes and zoomscales.
[scrollView2 setBackgroundColor:[UIColor blackColor]];
[scrollView2 setCanCancelContentTouches:NO];
scrollView2.clipsToBounds = YES;
[scrollView2 setDelegate:self];
scrollView2.indicatorStyle = UIScrollViewIndicatorStyleWhite;
[scrollView2 setContentSize:CGSizeMake(imageView.frame.size.width, imageView.frame.size.height)];
[scrollView2 setScrollEnabled:YES];
float minZoomScale;
float zoomHeight = imageView.frame.size.height / scrollView2.frame.size.height;
float zoomWidth = imageView.frame.size.width / scrollView2.frame.size.width;
if(zoomWidth > zoomHeight)
{
minZoomScale = 1.0 / zoomWidth;
}
else
{
minZoomScale = 1.0 / zoomHeight;
}
[scrollView2 setMinimumZoomScale:minZoomScale];
[scrollView2 setMaximumZoomScale:7.5];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
// Portrait
//the 88pxls is the white area that is left for the navbar etc.
self.scrollView2.frame = CGRectMake(0, 88, [UIScreen mainScreen].bounds.size.width, self.view.frame.size.height - 88);
[self drawContent];
}
else {
// Landscape
//the 88pxls is the white area that is left for the navbar etc.
self.scrollView2.frame = CGRectMake(0, 88, [UIScreen mainScreen].bounds.size.height, self.view.frame.size.width);
[self drawContent];
}
return YES;
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
I hope this will fix your troubles. If not leave a comment.
When you want to put a content (a UIView instance, let's call it theViewInstance ) in a UIScrollView and then scroll / zoom on theViewInstance , the way to do it is :
theViewInstance should be added as the subview of the UIScrollView
set a delegate to the UIScrollView instance and implement the selector to return the view that should be used for zooming / scrolling:
-(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return theViewInstance;
}
Set the contentSize of the UIScrollView to the frame of the theViewInstance by default:
scrollView.contentSize=theViewInstance.frame.size;
(Additionally, the accepted zoom levels can be set in the UIScrollView :)
scrollView.minimumZoomScale=1.0;
scrollView.maximumZoomScale=3.0;
This is the way a pinch to zoom is achieved on a UIImage : a UIImageView is added to a UIScrollView and in the UIScrollViewDelegate implementation, the UIImageView is returned (as described here for instance).
For the rotation support, this is done in the UIViewController whose UIView contains the UIScrollView we just talked about.
i have created a UIScrollVIew(name-helpView) through XIB with the a size of (768,1800).
Now i am adding this to another view through the following code.
-(IBAction)showHelpView:(UIButton *)sender{
if(helpViewIsShowing==NO){
//set the content size more than the view size to make the view scroll
helpView.contentSize = CGSizeMake(helpView.frame.size.width, 2200);
[self.view addSubview:helpView];
helpButton.selected=YES;
helpView.backgroundColor=[UIColor whiteColor];
helpView.frame=CGRectMake(0, 41, helpView.frame.size.width, helpView.frame.size.height);
helpViewIsShowing=YES;
}
else{
[helpView removeFromSuperview];
helpButton.selected=NO;
helpViewIsShowing=NO;
}
}
The frame of the scrollview is appearing fine when i run it in portrait mode. Itz also working fine if i turn the device from to PORTRAIT TO LANDSCAPE. But if i run the the code in landscape mode, then the frame of the scrollview is not adjusting itself to the full screen size. i have also given a auto resizing mask through XIB. But no luck either.
can anyone help me with this please.... Thanku
try to set the view frame in your view controller this function to the view size your required.you can define height and width according to your requirement.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Override to allow orientations other than the default portrait orientation.
if (interfaceOrientation==UIInterfaceOrientationLandscapeLeft || interfaceOrientation==UIInterfaceOrientationLandscapeRight) {
self.helpView.frame = CGRectMake(0, 0, 703,768);
} else {
self.helpView.frame = CGRectMake(0, 0, 768, 1024);
}
return YES;
}
good luck
My aim was to get the application functioning in both landscape and portrait mode, and all I could figure out to do it was this code below. The app was working fine in portrait, but when switched to landscape, the text wouldn't expand (to the right) to fill up the additional space. I made sure my springs/struts where set, and that the parents had "allowResizing" selected in IB.
Here's what I've done instead:
- (void) willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation duration:
(NSTimeInterval)duration {
UIInterfaceOrientation toInterfaceOrientation = self.interfaceOrientation;
if (toInterfaceOrientation == UIInterfaceOrientationPortrait) {
self.myView.frame = CGRectMake(0.0, 0.0, 320.0, 480.0);
}
else {
self.myView.frame = CGRectMake(0.0, 0.0, 480.0, 256.0);
}
}
Note that it looks just fine in portrait mode (toolbar appears):
Portrait http://mr-sk.com/img/land.png
But the toolbar is gone in landscape mode:
Landscape http://mr-sk.com/img/por.png
Any ideas?
If you use Interface Builder - you get this same result if you don't specify constraints in the object inspector to pin the toolbar to both edges and the bottom (click on the little red lines to specify constraints).
You can also do the same in code - you need to lookup how to do this (but its easier in IB)
There are a few reasons why it could be messing up... maybe your UIToolbar has the wrong parent. Maybe a layoutSubviews is being run and moving it somewhere strange. Or something else.
I recommend you implement a didRotateFromInterfaceOrientation: on your view controller and read the frame of the UIToolbar after the rotation to see where it has gone. This will be the best way to discover the exact problem.