当改变方向时如何完全隐藏一个UIView?

11

我想设计一个视图/视图控制器,在横向方向时自动显示/隐藏子视图。我希望子视图完全消失,其他子视图填补其空间。

使用一个UIViewController,我编写了一些代码,设置了子视图的frame属性,并在以下情况下调用它:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration;

这通常解决了大部分问题,但在视图未出现时发生方向更改时存在问题。为了解决这个问题,我还在以下情况下调用了调整大小的方法:

- (void)viewWillAppear:(BOOL)animated;

但是在某些罕见情况下(涉及UISearchDisplayController),这种方法存在问题,因此我也在调用调整大小的方法。

- (void)viewDidAppear:(BOOL)animated;

如您所理解的,我对这段代码感到不满,并正在寻找更好/更高效的方式来完成这个问题。

有任何想法吗?


我在这个问题上提供赏金。在我的情况下,我在视图中心有一个UIWebView,底部有一个广告横幅。我想要移除广告横幅,并在调整大小时使UIWebView重新调整大小以填充缺失的空间。我尝试仅从superview中删除横幅,但是即使启用了所有自动调整大小掩码,UIWebView也不会调整大小以填充空白空间。 - Dan Fabulich
6个回答

10

假设你只有一个UIWebView和一个广告横幅,那么在横屏时,你可以手动调整webView的大小:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toOrientation 
                                duration:(NSTimeInterval)duration
{
    if (toOrientation == UIInterfaceOrientationPortrait ||
        toOrientation == UIInterfaceOrientationPortraitUpsideDown) {
            [adView setHidden:NO];
        }
    } else {
        if (toOrientation == UIInterfaceOrientationLandscapeLeft ||
            toOrientation == UIInterfaceOrientationLandscapeRight) {
            [adView setHidden:YES];
        }       
    }
}

然后也这样做

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromOrientation 
                                duration:(NSTimeInterval)duration
{
    UIInterfaceOrientation toOrientation = self.interfaceOrientation;
    if (toOrientation == UIInterfaceOrientationPortrait ||
        toOrientation == UIInterfaceOrientationPortraitUpsideDown) {
            [webView setBounds:CGRectMake(0.0,0.0,320.0,436.0)];
        }
    } else {
        if (toOrientation == UIInterfaceOrientationLandscapeLeft ||
            toOrientation == UIInterfaceOrientationLandscapeRight) {
            [webView setBounds:CGRectMake(0.0,0.0,480.0,320.0)];
        }       
    }
}

这些尺寸假设广告横幅的高度为44.0,并且没有导航栏(44.0)或状态栏(20.0),因此你可能需要根据你的布局调整数字。


这个出人意料地不起作用 - 或者说,它是起作用的,但有一个很大的问题。如果你在 "willRotate" 中进行这样的调整大小,iOS 将在旋转后重新转换尺寸。所以当切换到竖屏时,你必须将(当前为横屏)webView 调整为 480x~291(100%x90%);iOS 将把它转换为 320x436。当切换到横屏时,你必须将其调整为 320x480,iOS 将把它转换为 480x320。(头爆炸了)难道真的没有更好的方法吗? - Dan Fabulich
1
我将之前的答案分解成了“将要”和“已经”两种方法。这应该会改善实现。 - PengOne
didRotateFromInterfaceOrientation 中进行调整大小是缺失的技巧。我也必须在 viewWillAppear 中调用此代码,因此它可能不能回答 @Panagiotis Korros 的问题,但这值得我的赏金。 - Dan Fabulich

0
如果有几个子视图在横向和纵向布局上需要非常不同,那么使用一个额外的UIView可能更容易,在IB中添加一个名为landscapeView的视图。将其装载到按钮、子视图等,并按照您的喜好进行布局。您可以使用与通常(纵向)视图相同的所有连接。请记得在头文件中声明IBOutlet UIView *landscapeView;。然后,您可以使用以下代码添加视图:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toOrientation 
                                duration:(NSTimeInterval)duration
{
    if ([landscapeView superview]) {
        if (toOrientation == UIInterfaceOrientationPortrait ||
            toOrientation == UIInterfaceOrientationPortraitUpsideDown) {
            [landscapeView removeFromSuperview];
        }
    } else {
        if (toOrientation == UIInterfaceOrientationLandscapeLeft ||
            toOrientation == UIInterfaceOrientationLandscapeRight) {
            [[self view] addSubview:landscapeView];
        }       
    }
}

如果时间不如你所愿,那么你也可以尝试在 -(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation; 中尝试类似的操作。
如果你想更加高级一些,那么你可以将主视图保留为空,创建一个 UIView *portraitView 和一个 UIView *landscapeView,然后在 willRotateToInterfaceOrientation 中移除当前视图,在 didRotateToInterfaceOrientation 中添加新视图。
为了安全起见,你还应该确保初始时显示正确的视图:
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    UIInterfaceOrientation toOrientation = self.interfaceOrientation;
    if (toOrientation == UIInterfaceOrientationPortrait ||
        toOrientation == UIInterfaceOrientationPortraitUpsideDown) {
        [self.view addSubview:portraitView];
    } else {
        [self.view addSubview:landscapeView];
    }

}

而且

- (void)viewWillDisappear:(BOOL)animated
{
    if ([landscapeView superview]) {
        [landscapeView removeFromSuperview];
    }
    if ([portraitView superview]) {
        [portraitView removeFromSuperview];
    }
}

这两个选项都不适用于我的情况(我目前正在提供悬赏):-)。我有一个带有广告横幅的UIWebView,我想在横向视图中删除横幅。如果我尝试解决方案#1来删除横幅,则UIWebView不会调整大小以填充空间。如果我尝试解决方案#2,则无法在单独的横向/纵向视图之间共享UIWebView。 - Dan Fabulich
哦,如果你只需要这个,那就手动调整Webview的大小吧。 - PengOne

0

就像这种情况,我个人认为编写子视图的位置比依赖框架的布局管理要简单得多。

因此,假设您的应用程序显示一个高度为20点的标题栏,这是我会做的:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
    CGFloat titleBarHeight = 20;
    CGFloat navBarHeight = self.navigationController.navigationBar.frame.size.height;
    if(UIInterfaceOrientationIsPortrait(toInterfaceOrientation)){
        webView.frame = CGRectMake(0, 0, 320, 480 - titleBarHeight - navBarHeight - adView.frame.size.height);
        adView.hidden = NO;
    }else{
        webView.frame = CGRectMake(0, 0, 480, 320 - titleBarHeight - navBarHeight);
        adView.hidden = YES;
    }
}

请看我对@PengOne的评论。这实际上很棘手/不太优雅。难道真的没有更好的方法吗? - Dan Fabulich

0
我在代码中利用了父视图的边界。尝试下面的代码,看看动画是否能正常工作。
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    switch (toInterfaceOrientation) {
        case UIInterfaceOrientationLandscapeLeft:
        case UIInterfaceOrientationLandscapeRight:
        {
            webView.frame = self.view.bounds;
        adView.hidden=YES;
            break;
        }
    }
}


- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];

    switch (fromInterfaceOrientation) {
        case UIInterfaceOrientationLandscapeLeft:
        case UIInterfaceOrientationLandscapeRight:
        {
            webView.frame = originalFrame;
            adView.hidden=NO;
            break;
        }
    }
}

- (void)viewDidLoad {
    [super viewDidLoad];
    webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    adView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    originalFrame = webView.frame;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}

0

里面

- (void)didRotateFromInterfaceOrientation:
    (UIInterfaceOrientation)fromInterfaceOrientation

隐藏它

sub_view.hidden = YES;

再次显示它

sub_view.hidden = NO;

1
谢谢您的回复,但是隐藏属性只是隐藏视图,它不会调整其他视图来占据它的空间。 - Panagiotis Korros
哦,你想做那个。你检查过是否可以使用layoutSubviews和layoutIfNeeded了吗? - Tuomas Pelkonen

0

一种选项是在旋转时使用交叉淡入淡出过渡呈现模态视图,并在旋转回来时将其关闭。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接