简体   繁体   中英

Objects position incorrectly in view and after device orientation changes

I am creating an iOS application. It functions within a navigation controller. In a view I've recently built, the UITextViews and UIImageView have been displaying incorrectly, at the wrong coordinates. I believe that this may be due to the UINavigationBar .

When I set up the view to mirror that in the Interface Builder, it actually displayed the view wrongly. I again assume that this is due to the UINavigationBar . I managed to "fix" this by altering the Interface Builder coordinates until it displayed correctly. This is what the Interface Builder now looks like:

I want the view to work in both device orientations (portrait and landscape). The objects in the view can't easily be told to rotate, so I am positioning the views programmatically. The code is as follows:

-(void) adjustViewsForOrientation:(UIInterfaceOrientation)orientation {
    if (orientation == UIInterfaceOrientationPortrait) {
        appInfo.frame = CGRectMake(20, 19, 280, 90);
        updateInfo.frame = CGRectMake(20, 117, 280, 86);
        authorInfo.frame = CGRectMake(20, 229, 172, 200);
        authorImage.frame = CGRectMake(190, 274, 110, 110);
    }
    else if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
        appInfo.frame = CGRectMake(11, 44, 199, 124);
        updateInfo.frame = CGRectMake(218, 53, 242, 124);
        authorInfo.frame = CGRectMake(11, 180, 340, 90);
        authorImage.frame = CGRectMake(350, 170, 110, 110);
    }
}

-(void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [self adjustViewsForOrientation:toInterfaceOrientation];
}

-(void) viewWillAppear:(BOOL)animated {
    [self adjustViewsForOrientation:self.interfaceOrientation];

    [super viewWillAppear:animated];
}

Here is my main problem: When the view is rotated to landscape, the objects to not position directly. They do not follow what is described in the coordinates to be called during rotation.

This problem also occurs when rotated back to portrait:

How can I resolve this? Thank you in advance.

You could do something complicated using sizeWithFont:constrainedToSize to figure out the size that the various text boxes need to be at the new width to fit the text you want to put in them, but probably easier would be to eliminate the UILabel/UITextView's and the UIImageView, and just create a UIWebView that fills the whole view and use it's loadHTMLString:baseURL to supply a HTML string that includes your copy and a link to your image in your bundle.

Update:

The problem is that you (a) you clearly have autoResizingMasks set; and (b) you're setting your new frames too early (so once the reorientation takes place, the autoResizingMask adjusts them again).

So, a couple of thoughts:

First, you probably have the auto sizing masks turned on in Interface Builder, eg something like:

尺寸检查器具有自动调整大小功能

So, turn off the autoresizing masks:

自动关闭大小调整的大小检查器

Second, while I'm sure you'll do that in IB, FYI you can also turn it off programmatically:

appInfo.autoresizingMask = 0;
updateInfo.autoresizingMask = 0;
authorInfo.autoresizingMask = 0;
authorImage.autoresizingMask = 0;

Third, you might want to change the frame coordinates after autoresizing has a chance to screw up your controls. Typically, I'll see guys who defer this sort of frame adjustments to didRotateFromInterfaceOrientation rather than willRotateToInterfaceOrientation because (a) you have the coordinates of the new orientation (and because navigation controllers are different heights in landscape v portrait, this can be important, though maybe not in your case); and coincidentally (b) you remedy any adjustments that some unintended autoresizing masks may have introduced.

Personally, I've taken to resetting my frames in viewWillLayoutSubviews in iOS 5 and later, and in didRotateFromInterfaceOrientation and viewWillAppear in earlier versions of iOS (I do all of this programmatically in my code). The iOS 5 alternative of viewWillLayoutSubviews is superior because it sets the frames right before the rotation animation, and animates the changing of the frames with the rotation animation, which is very, subtle change, but very slick. Once you start noticing apps that do this right, you'll always want to do it that way.

The call to adjustViewsForOrientation: is made too early from the willRotateToInterfaceOrientation:duration: call back. Instead, move the call to adjustViewsForOrientation: into the willAnimateRotationToInterfaceOrientation:duration: call back. From the documentation:

By the time this method is called, the interfaceOrientation property is already set to the new orientation, and the bounds of the view have been changed. Thus, you can perform any additional layout required by your views in this method.

UIViewController willAnimateRotationToInterfaceOrientation:duration:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
   [self adjustViewsForOrientation:toInterfaceOrientation];
}

As discussed in the comments elsewhere, while creating individual controls and moving them around on orientation change can give you a great level of control, simpler approach is to just create a single UIWebView control, and let it take care of taking advantage of reformatting the text for the wider screen. Also, UIWebView makes it easy to format the text (bold, italics) or add hyperlinks (for email addresses and telephone numbers, especially. Anyway, here is an example of creating the HTML string for the UIWebView:

- (NSString *)htmlString
{
    NSURL *imgUrl = [[NSBundle mainBundle] URLForResource:@"IMG_0999" withExtension:@"PNG"];
    NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];

    NSString *htmlBodyTemplate = 
        @"<html>"
        @"<style type=\"text/css\">"
        @"html {"
        @"    -webkit-text-size-adjust: none; /* Never autoresize text */"
        @"}"
        @"</style>"
        @"<body style=\"font-family:Verdana, Geneva, sans-serif; font-size:14px;\">"

        @"<p>This application is version %@. The recommended iOS version for running this application is iOS 5.0+. The minimum iOS version is iOS 4.3.</p>"
        @"<p>This application will automatically check for updates at startup. It is recommended to immediately update the app when prompted.</p>"
        @"<img src=\"%@\" style=\"float:right;\" width=\"150px\" />"
        @"<p>This application was created by Ridgefield High School student <strong>Devin Gund</strong> in 2012. He worked with the Ridgefield Public Schools technology department in publishing this application.</p>"

        @"</body>"
        @"</html>";

    return [NSString stringWithFormat:htmlBodyTemplate, version, [imgUrl relativeString]];
}

And then, in your viewDidLoad, include a line:

[self.webView loadHTMLString:[self htmlString] baseURL:nil];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM