无法缩小 UIWebView 和 UINavigationBar 之间的差距

Posted

技术标签:

【中文标题】无法缩小 UIWebView 和 UINavigationBar 之间的差距【英文标题】:Cannot close the gap between UIWebView and a UINavigationBar 【发布时间】:2013-06-26 01:40:20 【问题描述】:

在我的项目中,我在UINavigationBar 下放置了一个UIWebView,并将UIWebView 设置为占据除UINavigationBar 之外的屏幕的其余部分。但我发现这两个控件之间存在一些差距。左侧边缘和UIWebView 左侧之间也有一个间隙。知道我缺少什么吗?

这是我更新的代码: 在UIView+AutoLayout: (该类别会将所有视图的translatesAutoresizingMaskIntoConstraints 属性设置为NO

#import "UIView+AutoLayout.h"

@implementation UIView (AutoLayout)
+ (id)autolayoutView

    UIView *view = [self new];
    view.translatesAutoresizingMaskIntoConstraints = NO;
    return view;

@end

在 ViewController 中:

- (void)viewDidLoad

    [super viewDidLoad];
    self.navigationBar = [UINavigationBar autolayoutView];
    UINavigationItem *backToListItem = [[UINavigationItem alloc] init];
    UIBarButtonItem *listItem = [[UIBarButtonItem alloc] initWithTitle:@"List"   style:UIBarButtonItemStylePlain target:self action:@selector(listButtonPressed:)];
    backToListItem.leftBarButtonItem = listItem;

    self.navigationBar.items = [NSArray arrayWithObject:backToListItem];

    [self.view addSubview:self.navigationBar];

    self.webView = [TNSWebView autolayoutView];

    [self.view addSubview:self.webView];

    NSDictionary *views = NSDictionaryOfVariableBindings(_navigationBar, _webView);
    [self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"|[_navigationBar]|"
                           options:0 metrics:nil
                           views:views]];
    [self.view addConstraints:[NSLayoutConstraint
                                 constraintsWithVisualFormat:@"V:|[_navigationBar]->=0-[_webView]|"
                                 options:0 metrics:nil
                                 views:views]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_webView]|" options:0 metrics:nil views:views]];
    [self.webView setupVideoPlayer:self.videoId];

lldb 中使用po [[UIWindow keyWindow] recursiveDescription] 命令我得到了这个结果

    | <UIView: 0x1d23f880; frame = (0 20; 768 1004); autoresize = RM+BM; layer = <CALayer: 0x1d23cba0>>
   |    | <UINavigationBar: 0x1d00a4b0; frame = (0 0; 768 44); gestureRecognizers = <NSArray: 0x1d015ff0>; layer = <CALayer: 0x1d0c8f60>>
   |    |    | <_UINavigationBarBackground: 0x1d010250; frame = (0 0; 768 44); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d011140>>
   |    |    |    | <UIImageView: 0x1d0d26b0; frame = (0 44; 768 3); opaque = NO; autoresize = W+TM; userInteractionEnabled = NO; layer = <CALayer: 0x1d23fbd0>>
   |    |    | <UINavigationItemView: 0x1d016740; frame = (384 22; 0 0); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d016840>>
   |    |    | <UINavigationButton: 0x1d013ff0; frame = (7 7; 48 30); opaque = NO; layer = <CALayer: 0x1d014170>>
   |    |    |    | <UIImageView: 0x1c5d9ca0; frame = (0 0; 48 30); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1c58b330>>
   |    |    |    | <UIButtonLabel: 0x1d0144c0; frame = (13 7; 22 15); text = 'List'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d014560>>
   |    | <TNSWebView: 0x1d016bc0; baseClass = UIWebView; frame = (0 44; 768 960); layer = <CALayer: 0x1d016ca0>>
   |    |    | <_UIWebViewScrollView: 0x1d012390; frame = (0 0; 768 960); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x1d011380>; layer = <CALayer: 0x1d0125e0>; contentOffset: 0, 0>
   |    |    |    | <UIImageView: 0x1d00f2a0; frame = (0 0; 10 10); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d00f300>>
   |    |    |    | <UIImageView: 0x1d00f210; frame = (0 0; 10 10); transform = [0, 1, -1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d00f270>>
   |    |    |    | <UIImageView: 0x1d00f180; frame = (0 0; 10 10); transform = [0, -1, 1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d00f1e0>>
   |    |    |    | <UIImageView: 0x1d00efb0; frame = (0 0; 10 10); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d00f150>>
   |    |    |    | <UIImageView: 0x1d00ef20; frame = (-4.5 4.5; 10 1); transform = [0, 1, -1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d00ef80>>
   |    |    |    | <UIImageView: 0x1d00ee90; frame = (-4.5 4.5; 10 1); transform = [0, -1, 1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d00eef0>>
   |    |    |    | <UIImageView: 0x1d00ee00; frame = (0 0; 1 10); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d00ee60>>
   |    |    |    | <UIImageView: 0x1d00ec30; frame = (0 0; 1 10); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d00edd0>>
   |    |    |    | <UIImageView: 0x1d00eba0; frame = (0 954; 768 6); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d00ec00>>
   |    |    |    | <UIImageView: 0x1d00fcd0; frame = (0 0; 768 6); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1d00fe70>>
   |    |    |    | <UIWebBrowserView: 0x1dbf2400; frame = (0 0; 768 960); gestureRecognizers = <NSArray: 0x1d014c40>; layer = <UIWebLayer: 0x1d017d00>>
   |    |    |    |    | <TileHostLayer: 0x1d017e70> (layer)
   |    |    |    |    |    | <TileLayer: 0x1c5511a0> (layer)
   |    |    |    |    |    | <TileLayer: 0x1c551210> (layer)
   |    |    |    |    |    | <TileLayer: 0x1c551250> (layer)
   |    |    |    |    |    | <TileLayer: 0x1c551290> (layer)

更新后的截图:

只需将导航栏的高度更改为 44 并使用 recursiveDescription 命令,我就得到了:

$0 = 0x2008f680 <UIWindow: 0x1ed814f0; frame = (0 0; 768 1024); autoresize = W+H; layer = <UIWindowLayer: 0x1ed815f0>>
   | <UIView: 0x20167680; frame = (0 20; 768 1004); autoresize = RM+BM; layer = <CALayer: 0x1ed0ea50>>
   |    | <UINavigationBar: 0x1ed14b70; frame = (0 0; 768 44); gestureRecognizers = <NSArray: 0x20081bd0>; layer = <CALayer: 0x1ed09ff0>>
   |    |    | <_UINavigationBarBackground: 0x1ed8b9b0; frame = (0 0; 768 44); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1ed08570>>
   |    |    |    | <UIImageView: 0x2007aa90; frame = (0 44; 768 3); opaque = NO; autoresize = W+TM; userInteractionEnabled = NO; layer = <CALayer: 0x200f9640>>
   |    |    | <UINavigationItemView: 0x20053320; frame = (384 22; 0 0); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x200f9c30>>
   |    |    | <UINavigationButton: 0x200fa980; frame = (7 7; 48 30); opaque = NO; layer = <CALayer: 0x200f50c0>>
   |    |    |    | <UIImageView: 0x2016af20; frame = (0 0; 48 30); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x2016af80>>
   |    |    |    | <UIButtonLabel: 0x2004e420; frame = (13 7; 22 15); text = 'List'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x200f8040>>
   |    | <TNSWebView: 0x2004d660; baseClass = UIWebView; frame = (0 44; 768 960); layer = <CALayer: 0x20053f20>>
   |    |    | <_UIWebViewScrollView: 0x2004a230; frame = (0 0; 768 960); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x20049700>; layer = <CALayer: 0x2004a6c0>; contentOffset: 0, 0>
   |    |    |    | <UIImageView: 0x20048d50; frame = (0 0; 10 10); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x20048db0>>
   |    |    |    | <UIImageView: 0x20048cc0; frame = (0 0; 10 10); transform = [0, 1, -1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x20048d20>>
   |    |    |    | <UIImageView: 0x20048c30; frame = (0 0; 10 10); transform = [0, -1, 1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x20048c90>>
   |    |    |    | <UIImageView: 0x200f7c50; frame = (0 0; 10 10); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x20048c00>>
   |    |    |    | <UIImageView: 0x200f7bc0; frame = (-4.5 4.5; 10 1); transform = [0, 1, -1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x200f7c20>>
   |    |    |    | <UIImageView: 0x200f7b30; frame = (-4.5 4.5; 10 1); transform = [0, -1, 1, 0, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x200f7b90>>
   |    |    |    | <UIImageView: 0x200f7a30; frame = (0 0; 1 10); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x200f7b00>>
   |    |    |    | <UIImageView: 0x200f7890; frame = (0 0; 1 10); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x200f7a00>>
   |    |    |    | <UIImageView: 0x200fad20; frame = (0 954; 768 6); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x200fad80>>
   |    |    |    | <UIImageView: 0x200fab80; frame = (0 0; 768 6); transform = [-1, 0, -0, -1, 0, 0]; alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x200facf0>>
   |    |    |    | <UIWebBrowserView: 0x1fb37600; frame = (0 0; 768 960); gestureRecognizers = <NSArray: 0x20049910>; layer = <UIWebLayer: 0x200f81c0>>
   |    |    |    |    | <TileHostLayer: 0x2004ed10> (layer)
   |    |    |    |    |    | <TileLayer: 0x20168820> (layer)
   |    |    |    |    |    | <TileLayer: 0x20168890> (layer)
   |    |    |    |    |    | <TileLayer: 0x201688d0> (layer)
   |    |    |    |    |    | <TileLayer: 0x20168910> (layer)

【问题讨论】:

您的recursiveDescription 有一些非常可疑的地方。你的TNSWebView 有正确的框架,但是UIWebView,即使没有显示任何东西,也应该有后代,从_UIWebViewScrollView 开始。你的没有后代。要么您没有发布 recursiveDescription 的全部输出,要么您需要编辑您的帖子以包含 TNSWebView 的实现。 对不起,我没有发布所有信息,因为它太长了。我可以更新它。 好吧,我看不出有什么问题。你的屏幕上会出现什么?也许是时候更新您的屏幕截图了。 截图很简单。它只显示导航栏和列表项。没有别的了。 您的问题不再在于视图的布局。现在您的问题是(显然)您的 Web 视图没有加载您希望它加载的内容。我假设 setupVideoPlayer: 方法应该告诉它要加载什么内容,所以你可能需要逐步找出问题所在。 【参考方案1】:

更新

我收回了一切。您的问题不在于视图布局。我相信您的问题是您加载到 Web 视图中的 Web 内容周围有边框(或填充或边距)。您可能会发现“Debugging Web Content on ios” 很有用。它解释了如何使用 Safari(在您的 Mac 上)中的 Web Inspector 来调试在模拟器或设备上运行的 UIWebView 中的内容。我认为,如果您检查 Web 内容中的视频元素,您会发现它与视口的顶部和左侧边缘不齐。

原创

我猜当您在viewDidLoad 中查看导航栏高度时设置不正确。现在检查您刚刚创建的视图框架还为时过早。

iOS 应用程序将其时间花在如下所示的“运行循环”中:

while (1) 
    Event phase: process one event (e.g. touch event, timer firing, local or push notification, etc.)
    Layout phase: update the frames of new views and views with added or removed subviews
    Draw phase: draw the contents of views that need to be drawn
    Wait for the next event to arrive

当您将视图添加到视图层次结构时,它们会被安排在布局阶段进行布局。直到布局阶段完成后,您才能依靠新视图来获得正确的框架。

您可以通过编写UIView 的子类(或必要时任何其他视图类的子类)并覆盖其layoutSubviews 方法来进入布局阶段。或者您可以在视图控制器中实现viewDidLayoutSubviews 方法。我建议使用UIView 子类并覆盖layoutSubviews,但您可能会发现只实现viewDidLayoutSubviews 更方便:

- (void)viewDidLayoutSubviews 
    [super viewDidLayoutSubviews];
    [self layoutWebView];


- (void)layoutWebView 
    CGRect frame = self.view.bounds;
    CGFloat navBarHeight = self.navigationBar.frame.size.height;
    frame.origin.y = navBarHeight;
    frame.size.height -= navBarHeight;
    self.webView.frame = frame;

或者,如果您的部署目标是 iOS 6 或更高版本,您可以使用自动布局将导航栏的底部边缘固定到 Web 视图的顶部边缘。把这个放在viewDidLoad:

[self.view addLayoutConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"|V:[_navigationBar][_webView]|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(_navigationBar, _webView)]];

现在,我认为在您的应用中具体发生的情况是,您在创建 UINavigationBar 时指定高度为 50,但 UINavigationBar 需要高度为 44。所以在布局阶段,导航bar 将自身调整为 44 点高。由于在布局期间您没有做任何事情来修复 Web 视图的框架,因此 Web 视图仍然在顶层视图的顶部边缘下方 50 点处,留下 6 点的间隙。因此,您可以在创建导航栏时将其高度更改为 44。 ;^)

【讨论】:

我已将 UINavigationBar 的高度更改为 44。我还更改了代码以使用 layoutConstraint。但这一次 UIWebView 根本不显示。我可以听到在 Web 视图中播放视频的声音,所以我认为这是布局问题。 我不知道您为什么要在视觉格式中使用-&gt;=0- 来分隔视图。这允许视图之间有任意数量的分离,并且是模棱两可的,因此允许自动布局在视图之间留下间隙。我建议的视觉格式告诉自动布局视图的边缘之间不能有间隙。 我尝试过像 -&gt;=0- 一样不添加任何内容,但它们都不适合我。 另外,您可能应该在导航栏和 Web 视图上将 translatesAutoresizingMaskIntoConstraints 设置为 NO。如果您不这样做,我希望您会在控制台中收到自动布局警告。 您还需要像在导航栏上一样在 Web 视图上设置水平约束。【参考方案2】:

也许你需要看看你的 webView 的视图模式。 在 StoryBoard 或 xib 上,查看左侧面板,选择 Attributes Inspector,检查 webView 的视图模式选择(例如 Scale to FillAspectFit AspectFill..)。

【讨论】:

我不使用情节提要,我的 xib 文件为空。我以编程方式添加 UIViews。

以上是关于无法缩小 UIWebView 和 UINavigationBar 之间的差距的主要内容,如果未能解决你的问题,请参考以下文章

黑色图块在UIWebview中以pdf缩放显示

如何添加视图(以及缩小或拉伸其他)iOS

防止 UIWebview 上的捏缩放和双击缩放

UIWebview 旋转+变换问题

UIWebView“无法读取文档”错误

qwebview怎样调整加载的网页的大小