0

In my project I put a UIWebView under UINavigationBar and the setup the UIWebView to occupy the rest of the screen other than UINavigationBar. But I found some gaps between the two controls. There is also a gap between the left edge and the UIWebView left side. Any idea what I am missing?

enter image description here

Here is my updated code: in UIView+AutoLayout: (this category will set all the view's translatesAutoresizingMaskIntoConstraints property to NO)

#import "UIView+AutoLayout.h"

@implementation UIView (AutoLayout)
+ (id)autolayoutView
{
    UIView *view = [self new];
    view.translatesAutoresizingMaskIntoConstraints = NO;
    return view;
}
@end

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

Using the po [[UIWindow keyWindow] recursiveDescription] command in lldb I got this result

    | <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)

The updated screenshot:

enter image description here

By just changing the height of the navigationbar to 44 and use recursiveDescription command I got:

$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)
newguy
  • 5,668
  • 12
  • 55
  • 95
  • There is something very fishy about your `recursiveDescription`. Your `TNSWebView` has the correct frame, but a `UIWebView`, even when not displaying anything, should have descendants, starting with a `_UIWebViewScrollView`. Yours has no descendants. Either you didn't post the entire output of `recursiveDescription`, or you need to edit your post to include the implementation of `TNSWebView`. – rob mayoff Jun 26 '13 at 07:26
  • sorry I didn't post all the information because it is too long. I can update it. – newguy Jun 26 '13 at 07:28
  • Well, I fail to see any problem. What appears on your screen? Perhaps it's time to update your screen shot. – rob mayoff Jun 26 '13 at 07:30
  • The screenshot is simple. It just shows the navigationbar and the list item. Nothing else. – newguy Jun 26 '13 at 07:34
  • Your problem is no longer with the layout of your views. Now your problem is (apparently) that your web view is not loading the content you want it to load. I assume the `setupVideoPlayer:` method is supposed to tell it what content to load, so you probably need to step through that to figure out what's wrong. – rob mayoff Jun 26 '13 at 07:36
  • You may also need to give your web view a delegate so that you can see any errors the web view is encountering (by implementing `webView:didFailLoadWithError:` on the delegate). – rob mayoff Jun 26 '13 at 07:39
  • No, it is playing the video because I can hear the sounds. It just doesn't show up. Besides, I have no problem showing the video before changing the layout. – newguy Jun 26 '13 at 07:41
  • If you go back to your original code (and turn off autolayout), and just set the height of the navigation bar to 44 instead of 50 when you create it, what happens? – rob mayoff Jun 26 '13 at 07:45
  • I've done that before. It has no effect at all. – newguy Jun 26 '13 at 07:47
  • Please do it again and post the `recursiveDescription` with the video and gaps visible. – rob mayoff Jun 26 '13 at 07:50
  • I've posted the result. – newguy Jun 26 '13 at 07:59
  • I've revised my answer. – rob mayoff Jun 26 '13 at 08:06

2 Answers2

2

UPDATE

I take it all back. Your problem is not with view layout. I believe your problem is that the web content you're loading into your web view has a border (or padding or margin) around it. You may find “Debugging Web Content on iOS” useful. It explains how to use the Web Inspector in Safari (on your Mac) to debug the content in a UIWebView running on the simulator or a device. I think if you inspect the video element in your web content, you will discover that it is not flush with the top and left margins of the viewport.

ORIGINAL

I would guess that the navigation bar height isn't set correctly when you're looking at it in viewDidLoad. That is too soon to be checking the frames of views you've just created.

An iOS app spends its time in a “run loop” that looks like this:

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
}

When you add views to the view hierarchy, they are scheduled to be laid out during the layout phase. It is not until the layout phase completes that you can rely on new views to have their proper frames.

You can tap into the layout phase by writing a subclass of UIView (or a subclass of any other view class as necessary) and overriding its layoutSubviews method. Or you can implement the viewDidLayoutSubviews method in a view controller. I recommend using a UIView subclass and overriding layoutSubviews, but you may find it more expedient to just implement 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;
}

Alternatively, if your deployment target is iOS 6 or later, you can use auto layout to pin the bottom edge of the navigation bar to the top edge of the web view. Put this in viewDidLoad:

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

Now, what I think is specifically happening in your app is you're specifying a height of 50 when you create your UINavigationBar, but a UINavigationBar wants a height of 44. So in the layout phase, the navigation bar resizes itself to 44 points tall. Since you aren't doing anything to fix your web view's frame during layout, the web view remains 50 points below the top edge of your top-level view, leaving a gap of 6 points. So you could just change the height of the navigation bar to 44 when you create it. ;^)

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • I've changed the height of UINavigationBar to 44. I've also changed the code to use layoutConstraint. But this time the UIWebView doesn't show at all. I can hear the sound of the video playing in the web view so I think it is a layout issue. – newguy Jun 26 '13 at 06:43
  • I don't know why you would separate the views using `->=0-` in your visual format. That allows any amount of separation between the views, and is ambiguous, so auto layout is allowed to leave a gap between the views. The visual format I suggested tells auto layout that the edges of the views must not have a gap between them. – rob mayoff Jun 26 '13 at 06:46
  • I've tried adding nothing as well as `->=0-` but none of them works for me. – newguy Jun 26 '13 at 06:47
  • Also, you should probably set `translatesAutoresizingMaskIntoConstraints` to `NO` on both the navigation bar and the web view. I would expect you to be getting auto layout warnings in your console if you're not doing that. – rob mayoff Jun 26 '13 at 06:47
  • Also you need to set horizontal constraints on the web view like you do for the navigation bar. – rob mayoff Jun 26 '13 at 06:48
  • I added a category to UIView to set `translatesAutoresizingMaskIntoConstraints` to `NO` – newguy Jun 26 '13 at 06:48
  • Yes I use something like this `+ (id)autolayoutView { UIView *view = [self new]; view.translatesAutoresizingMaskIntoConstraints = NO; return view; }` on this site:http://commandshift.co.uk/blog/2013/01/31/visual-format-language-for-autolayout/ – newguy Jun 26 '13 at 06:53
  • You are not creating your `UINavigationBar` or your `TNSWebView` using that method. – rob mayoff Jun 26 '13 at 06:54
  • You still need to set horizontal constraints on the web view like you do for the navigation bar. – rob mayoff Jun 26 '13 at 07:03
  • You mean this? `[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_webView]|" options:0 metrics:nil views:views]];` This doesn't work. – newguy Jun 26 '13 at 07:04
  • I don't know what “doesn't work” means. You need to edit your question to include your current code and the current results. It would also be helpful to include any output that appears in the debug console, and also [the `recursiveDescription` of your view hierarchy](http://stackoverflow.com/a/5150281/77567). – rob mayoff Jun 26 '13 at 07:07
  • There's no other information. I've posted the recursiveDescription result in my code. – newguy Jun 26 '13 at 07:19
  • Thank you. The problem is finally resolved. It seems the body of the html has some default margin so I have to use ``. – newguy Jun 26 '13 at 08:24
0

Maybe you need to take a look on your view mode of your webView. On your StoryBoard, or xib, look to the left panel, select Attributes Inspector, check the view mode selection of your webView (e.g Scale to Fill, AspectFit, AspectFill..).

felixwcf
  • 2,078
  • 1
  • 28
  • 45