对象在视图中和设备方向更改后位置不正确

Posted

技术标签:

【中文标题】对象在视图中和设备方向更改后位置不正确【英文标题】:Objects position incorrectly in view and after device orientation changes 【发布时间】:2012-05-31 23:29:39 【问题描述】:

我正在创建一个 ios 应用程序。它在导航控制器中运行。在我最近构建的视图中,UITextViewsUIImageView 一直在错误的坐标处显示不正确。我相信这可能是由于UINavigationBar

当我在 Interface Builder 中设置视图以镜像该视图时,它实际上 错误地显示视图。我再次假设这是由于UINavigationBar。我设法通过更改 Interface Builder 坐标来“修复”这个问题,直到它正确显示。这是 Interface Builder 现在的样子:

我希望视图可以在两种设备方向(纵向和横向)下工作。视图中的对象不容易被告知旋转,所以我以编程方式定位视图。代码如下:

-(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];

这是我的主要问题: 当视图旋转到横向时,对象不能直接定位。它们不遵循旋转期间要调用的坐标中描述的内容。

旋转回纵向时也会出现此问题:

我该如何解决这个问题?提前谢谢您。

【问题讨论】:

您是否为此视图启用了任何自动布局?您可能是框架更改导致自动布局变得混乱。 不,我已经关闭了所有这些,假设您指的是 Interface Builder 中的方向更改设置 不,我怀疑他的意思是 IB 中的自动调整大小设置。 我确实知道要关闭自动调整大小。我的错误是将它们全部关闭。当我将它调整到左上角时,它起作用了。在我的开发过程中出现了相当愚蠢的错误,但非常感谢。 【参考方案1】:

您可以使用sizeWithFont:constrainedToSize 来做一些复杂的事情,以计算出各种文本框需要在新宽度下的大小以适合您要放入其中的文本,但可能更简单的是消除 UILabel/ UITextView 和 UIImageView,只需创建一个填充整个视图的 UIWebView 并使用它的 loadhtmlString:baseURL 来提供一个 HTML 字符串,其中包括您的副本和您捆绑包中图像的链接。

更新:

问题在于您 (a) 您显然设置了 autoResizingMasks; (b) 您设置新框架的时间过早(因此一旦发生重新定向,autoResizingMask 会再次调整它们)。

所以,有几个想法:

首先,您可能在 Interface Builder 中打开了自动调整大小的蒙版,例如类似:

所以,关闭自动调整大小的蒙版:

其次,虽然我确信你会在 IB 中这样做,但仅供参考,你也可以通过编程方式将其关闭:

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

第三,您可能希望在自动调整大小有可能搞砸您的控件后更改框架坐标。通常,我会看到将这种帧调整推迟到 didRotateFromInterfaceOrientation 而不是 willRotateToInterfaceOrientation 的人,因为(a)你有新方向的坐标(并且因为导航控制器在横向和纵向中的高度不同,这可以很重要,尽管在你的情况下可能不是);巧合的是 (b) 您修复了某些意外的自动调整大小蒙版可能引入的任何调整。

就我个人而言,我已经开始在 iOS 5 及更高版本中的 viewWillLayoutSubviews 以及早期版本的 iOS 中的 didRotateFromInterfaceOrientationviewWillAppear 中重置我的帧(我在我的代码中以编程方式完成所有这些操作)。 viewWillLayoutSubviews 的 iOS 5 替代品更胜一筹,因为它在旋转动画之前设置帧,并使用旋转动画来动画帧的变化,这是非常微妙的变化,但非常流畅。一旦您开始注意到应用程序可以正确执行此操作,您就会一直希望这样做。

【讨论】:

没有文字没问题。 UITextViews 很好。唯一的问题是没有东西移动到我指示它去的位置。 @DevinGund 我最初的评论是基于当我有一个文本和图像组合的框架时,我想重新布局或重新定位,UIWebView 会处理所有这些垃圾,我不必思考关于它,手动计算帧大小,在我碰巧想要更改我的副本时更改 Objective C 编码等等。但是,如果您真的想以编程方式调整控制帧,请参阅我的修改了上面的答案。 @DevinGund 不要在 UIWebView 考虑方面打败死马(假设您不想使用),但 UIWebViews 的另一个明显优势是您可以格式化文本(粗体、斜体)和包括指向电话号码、电子邮件地址等的超链接。好的,我现在就不要再说 UIWebView 了。 我确实知道要关闭自动调整大小。我的错误是将它们全部关闭。当我将它调整到左上角时,它起作用了。在我的开发过程中出现了相当愚蠢的错误,但非常感谢。 @DevinGund 如果您对各种控件更满意,那么您当然应该坚持下去。无论如何,要在 HTML 中准确重现您正在做的事情(宽时为两列,窄时为一列)并非易事。但是让文本和图像在屏幕重定向上重新定位是微不足道的,我经常在 About 屏幕(一个 UIWebView 和零编码,加上你获得所有 HTML 标记和超链接)之类的事情上这样做。但希望上面的代码能回答你原来的问题。【参考方案2】:

从 willRotateToInterfaceOrientation:duration: 回调中过早地调用了 adjustViewsForOrientation:。相反,将对 adjustViewsForOrientation: 的调用移动到 willAnimateRotationToInterfaceOrientation:duration: 回调中。来自文档:

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];

【讨论】:

【参考方案3】:

正如在其他地方的 cmets 中所讨论的,虽然创建单独的控件并在方向更改时移动它们可以为您提供很好的控制水平,但更简单的方法是只创建一个 UIWebView 控件,并让它负责利用为更宽的屏幕重新格式化文本。此外,UIWebView 可以轻松格式化文本(粗体、斜体)或添加超链接(尤其是电子邮件地址和电话号码。无论如何,这里是为 UIWebView 创建 HTML 字符串的示例:

- (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]];

然后,在您的 viewDidLoad 中,添加一行:

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

【讨论】:

谢谢!我以后会用它

以上是关于对象在视图中和设备方向更改后位置不正确的主要内容,如果未能解决你的问题,请参考以下文章

根据设备方向在 alloc/init 上设置正确的 UIView 帧大小

Android在方向上保存视图位置已更改[重复]

Flutter/Camera Plugin 0.5.3 上的设备方向不正确

如何根据设备方向更改堆栈视图方向?

查找设备是不是指向正确的航向/方向?

方向/配置更改后如何维护 ListView 片段状态?