I am brand new to iOS development, and I am trying to implement a rotatable and resizable user interface. The problem that I am encountering is re-setting the position of UI elements upon rotation. I can't even get the simple code below to work properly:
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
- (BOOL)shouldAutorotate {
return YES;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
self.button.frame = CGRectMake(502.0, 207.0, 73.0, 44.0);
} else {
self.button.frame = CGRectMake(197.0, 69.0, 73.0, 44.0);
}
}
I have de-selected the Autoresize Subviews option; however, the button still ends up in the same spot. I have logged the frame position, which appears to have the correct coordinates, but it is definitely not ending up that way.
in the first panel of Utility inspect. uncheck the use auto-layout.
Related
enter image description herehai, i have a list of buttons in a view which is a sub view of another UIView. i need to rearrange these buttons in order while the device orientation changes to landscape mode.
is their any way to do this? or else i need to do all these things manually by repositioning all buttons?
shouldAutorotateToInterfaceOrientation:, mentioned in the other answers, is for letting your view controller decide whether or not to allow autorotation to a given orientation. (you're supposed to return YES or NO).
If you really want to programmatically adjust layout of your subviews, you would do it in either
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[UIView animateWithDuration: duration
delay: 0.0f
options: UIViewAnimationOptionCurveLinear
animations: ^(void) {
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
self.button.frame = CGRectMake(x1, y1, self.button.frame.size.width, self.button.frame.size.height);
} else {
self.button.frame = CGRectMake(x2, y2, self.button.frame.size.width, self.button.frame.size.height);
}
}
completion: ^(BOOL finished) {
// code to run after animation completes can go here
}];
}
or, you can use willAnimateRotationToInterfaceOrientation:duration: for one-step rotations.
Not only is it only called when the autorotation actually happens, but it gives you the duration of the animation. This allows you to wrap any animatable view property changes inside your own animation, so that they smoothly animate during the rotation, instead of just snapping to their new values.
But, really, this is usually not the best way to solve the problem. See this link for a more general discussion of the issue
Change the CGFrame of you buttons in the
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation==UIInterFaceOrientationPortrait)
{
Button1.frame=...;
Button2.frame=....;
}
else if(interfaceOrientation==UIInterFaceOrientationLandscapeLeft)
{
Button1.frame=...;
Button2.frame=....;
}
return YES;
}
1-you can use this
YOUR_OBJECT.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin;
OR
2- use frame property with CGRectMake for your object in
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
if(interfaceOrientation==UIInterFaceOrientationPortrait)
else if(interfaceOrientation==UIInterFaceOrientationLandscapeLeft)
You can handle it via
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
method.
Make two methods in your viewController.h class assume they are -
-(void)viewForPortraitMode;
-(void)viewForLandscapeMode;
And this is the body part of both in your viewcontroller.m file.
//Set frame according to you
-(void)viewForPortraitMode
{
[btn1 setFrame:CGRectMake(117.0, 383.0, 87.0, 37.0)];
[btn2 setFrame:CGRectMake(40.0, 20.0, 240.0, 324.0)];
}
-(void)viewForLandscapeMode
{
[btn1 setFrame:CGRectMake(200.0, 252, 87.0, 37.0)];
[btn2 setFrame:CGRectMake(20.0, 7.0, 446.0, 228.0)];
}
And call these two methods in this
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
[self viewForPortraitMode];
}
else
{
[self viewForLandscapeMode];
}
return YES;
}
In my app, I want to set the UIView orientation according to home button orientation of iPhone. I done it using following way:
/* I handled view orientation in shouldAutorotate method*/
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
viewForBarButtons.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
else if (interfaceOrientation == UIInterfaceOrientationLandscapeRight)
viewForBarButtons.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
else if (interfaceOrientation == UIInterfaceOrientationPortrait)
viewForBarButtons.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin;
else if (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
viewForBarButtons.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
where viewForBarButtons is a UIView inside a viewController.
But if I set return Yes instead of return (interfaceOrientation == UIInterfaceOrientationPortrait); then it does not work.
How to resolve this issue. If anyone knows it, then please help me.
Similar functionality is implemented in LifeCards app.
Thanks in advance.
The above method is to decide whether to rotate your view to a particular orientation, when device orientation change.
return (interfaceOrientation == UIInterfaceOrientationPortrait);
specifies to support only Portrait orientation.
return YES;
would support all orientation.
But if you are putting your viewcontroller in a TabBarController then it will rotate only if all viewcontrollers support that specific orientation.
Instead of putting the above code to autoresize the object in willRotateToInterfaceOrientation.
But you need know one thing, by specifing
UIViewAutoresizingFlexibleLeftMargin
You are just specifying that view can put as much as space want between object and left margin. But it will keep previous positionson other sides during orientation change, so you might need to phsically change the origin of the object (viewForBarButtons)
Ok. I guess what you are saying is you want the viewForBarButtons beside the homeButton, and need to position/rotate its subviews accordingly.
First register for devie rotaion or use didRotateInterfaceOrientation, to initate rotating subviews of viewForBarButtons.
#define degreesToRadians(x) (M_PI * x / 180.0)
Rotate subviews: replace self with subview object
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (animated)
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
}
if (orientation == UIInterfaceOrientationPortraitUpsideDown)
self.transform = CGAffineTransformRotate(CGAffineTransformIdentity, degreesToRadians(180));
else if (orientation == UIInterfaceOrientationLandscapeRight)
self.transform = CGAffineTransformRotate(CGAffineTransformIdentity, degreesToRadians(90));
else if (orientation == UIInterfaceOrientationLandscapeLeft)
self.transform = CGAffineTransformRotate(CGAffineTransformIdentity, degreesToRadians(-90));
else
self.transform=CGAffineTransformIdentity;
if (animated)
[UIView commitAnimations];
Here is my code to set at the center
UIButton *videoImage = [[UIButton alloc]initWithFrame:CGRectMake((secondImageView.frame.size.width/2)-50,(secondImageView.frame.size.height/2)-50,50,50)];
videoImage.transform = CGAffineTransformMakeRotation(ang*(3.14/180));
[videoImage setBackgroundImage:[UIImage imageNamed:#"PlayButton.png"] forState:UIControlStateNormal];
[videoImage addTarget:self action:#selector(PlayMusicOnClickofButton:) forControlEvents:UIControlEventTouchUpInside];
[secondImageView addSubview:videoImage];
videoImage.tag = k+1000;
secondImageView.userInteractionEnabled = YES;
[videoImage release];
The problem that i am facing is when i change orientation of button it's position gets changed. It doesn't remain at center. Please help
Thanks
Actually you should use this method....
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
//handle how you want to show in landscape mode
}
else
{
//handle how you want to show in portrait mode
}
return YES;
}
You need to handle this. What you are doing is correct. You need to do tweak it when the orientation changes as the dimensions of your parent view change. Implement willAnimateRotationToInterfaceOrientation delegate. check this out -
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration
{
if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft||toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
//handle how you want to show in landscape mode
}
else
{
//handle how you want to show in portrait mode
}
}
I am working on a project where I have added UIWebviews in the UIscrollview to show the description. I did this because I want to add the swipe effect to move to the new description page. Now, I want to resize that UIscrollview and its content (i.e uiwebview) when the orientation changes (i.e portrait to landscape or Viceversa).
Please give me any sample code or any suggestions for it.
To resize the webview you have to write:-
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
webview.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * someValue1,
scrollView.frame.size.height * someValue2);
}
You can put your code in the following code block :
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if ([self isPadPortrait]) {
// Your code for Portrait
// set frame here
} else if ([self isPadLandscape]) {
// Your code for Landscape
// set frame here
}
and following code will take care of orientation change :
- (BOOL)isPadPortrait
{
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
&& (self.interfaceOrientation == UIInterfaceOrientationPortrait
|| self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown));
}
- (BOOL)isPadLandscape
{
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
&& (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight
|| self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft));
}
You can set the autoresizingMask of scrollView and add this code to your .m file according to your requirement.
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * someValue1,
scrollView.frame.size.height * someValue2);
}
Here is a link to a similar question and their solution:
Scale image to fit screen on iPhone rotation
They used a combination of AutoresizingMasks and ContentModes for both the ScrollView and, in their case, an ImageView, although I imagine the same solution would work for your WebView.
when ever the orientation changed
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
// this delegate method will called if we set should auto orientation return yes;
when ever we changed orientation so set frames..
}
for example
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
appDelegate.interface=interfaceOrientation;
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
// SET FRAMES FOR LANDSCAPE HERE
}
if (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown || interfaceOrientation == UIInterfaceOrientationPortrait)
{
//SET FRAMES FOR Portrait HERE
}
}
I have a view controller in my iphone app setup so that when I change the orientation from portrait to landscape, I change the view. When I change the orientation back from landscape to portrait, the initial view comes back, except this time it is all crammed into the left hand side of the screen. Eventually, when I change orientations enough times everything disappears completely. Is this a common issue beginners have? What could I be doing wrong?
In my root controller I am allowing the orientation to change only when a specific view is being shown with this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if (self.currentView == (NSInteger*)Chart || self.currentView == (NSInteger*)Detail) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
return (interfaceOrientation == UIInterfaceOrientationPortrait);
Where self.currentView is an enum of what view I currently have up. The Detail view I want to make sure stays as a portrait view, but when I change the orientation while on that view I want it to change the view to the Graph. Again, this works fine the first time, but when I change back from Graph to Detail, it crams all the controls on the Detail view to the left hand side of the screen.
Here is how I'm changing the view:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
if (self.currentView == (NSInteger*)Detail && (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"changeView" object:self userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:Chart] forKey:#"view"]];
}
if (self.currentView == (NSInteger*)Chart && (toInterfaceOrientation == UIInterfaceOrientationPortrait)) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"changeView" object:self userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:Detail] forKey:#"view"]];
}
#justin I once did this which got me into same situation as you are. May be you can check if you haven't done something like this
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
CGRect rect;
if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
rect = CGRectMake(tableView.frame.origin.x,tableView.frame.origin.y,
tableView.frame.size.width - 50, tableView.frame.size.height - 30);
}
else {
rect = CGRectMake(tableView.frame.origin.x,aBar.frame.origin.y,
tableView.frame.size.width, tableView.frame.size.height);
}
[tableView setFrame:rect];
return YES;
}
All I wanted was a table view with small frame in Portrait mode, without saving the original Frame I was trying to reduce its width and height which eventually brought the table view to a very small size after multiple rotation..
Lolzzz. I should have first saved the original tableview frame and then done something like this
if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
tableView.frame = CGRectMake(tableView.frame.origin.x,tableView.frame.origin.y,
tableView.frame.size.width - 50, tableView.frame.size.height - 30);
}
else {
tableView.frame = originalTableViewFrame;
}
check if you have autoresizeSubviews ON (in XIB/Inteface Builder) on your view and possibly parent views and try to turn it off if you are changing frame manually , this solved it for my case