iOS WebView doesn't resize Width on device rotation.

ChaseFlorellChaseFlorell Chase FlorellCAInsider, University mod

When I drop a WebView into a view, I'm having an issue whereby when I rotate the device, the WebView stays the same width as it was initially.

note: I always start out vertical, so rotating horizontal shows a narrow WebView

        var webView = new WebView
        {
            Source = new HtmlWebViewSource { Html = segment.ContentHtml },
            VerticalOptions = LayoutOptions.FillAndExpand,
            HorizontalOptions = LayoutOptions.FillAndExpand,
            HeightRequest = 250
        };

Is this a bug?

Posts

  • ChristineBlandaChristineBlanda Christine Blanda USMember ✭✭✭

    You need to create a custom render for the webview, and in the OnElementChanged event add:

            this.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
    
  • ChaseFlorellChaseFlorell Chase Florell CAInsider, University mod

    ah interesting. Is this a logged bug then, because building a Custom Render for such a thing seems a little bit odd.

  • HugoLogmans_HugoLogmans_ Hugo Logmans NLMember ✭✭✭

    @ChaseFlorell‌, you will run into issues which need a custom webview renderer five minutes after you solve this one :) So don't mind creating the custom renderer. You can copy/paste code from the WebView docs (workaround for baseurl).

    @ChristineBlanda‌, maybe you did some more? As it does not work for me, and from my memory for UIWebview you have to reload the content, because otherwise the content is scaled to the new size instead of a full relayout.

  • ChristineBlandaChristineBlanda Christine Blanda USMember ✭✭✭

    @HugoLogmans‌ I do a number of other things in the custom render, but not related to the size. I do set ScalesPageToFit=true but it doesn't appear to have an effect.

  • JustinJonesJustinJones Justin Jones USMember

    No luck here either. Only reloading content, or re-adding webview to layout works for me.

    Interestingly, in a native IOS app, the problem goes away if the UIWebView instance is the main view of a UIWebViewController. http://stackoverflow.com/questions/4125316/uiwebview-rotate-content

  • DustinWilliams.0495DustinWilliams.0495 Dustin Williams AUMember
    edited October 2014

    I found that setting the UIAutoResizingMask only worked for the parent view, not the internal webview. In my case even with reloading the webview, the internal view was always 1024 wide on iPad regardless of orientation (although it would load to portrait size initially, sometimes I could scroll past that to the full 1024).

    I've fixed this by resizing the WebView's non-UIImageView (it has two small ones, at least on my page) to the same size as its parent, after the orientation change has occurred.

    This is really hacky, but is working great:

    private void ResizeSubviewsToParent() { foreach (UIView subview in Subviews) { foreach (UIView sub in subview.Subviews) { if ((sub is UIImageView) == false) { sub.Frame = new RectangleF(sub.Frame.X, sub.Frame.Y, subview.Frame.Width, sub.Frame.Height); } } } }

    Edit: I found that on pages longer than the screen height the bottom would be cut off the first time I show a webview, so I changed this to only modify the width of the subview's subview which seems to work fine across all pages in my app on both iPhone and iPad.

  • joseph123joseph123 Joseph Scott USMember ✭✭
    edited February 2015

    I know this thread is old but I've tried everything to get this to work and I found one solution after realizing the problem is also present if you develop for native apps. The solution is to put a tag in the head section of the page. meta name=""viewport"" content=""width=device-width,height=device-height"" Note I had to remove the < and /> from the comment because otherwise this forum cut it off. I know some of you may not have control over the page you are viewing or it may be viewed from other devices but maybe in those cases you can use javascript to inject the content into the head section. Either way it worked great no other modifications required.

  • KeithRoweKeithRowe Keith Rowe USMember

    @ChristineBlanda - THANK YOU! I think FlexibleDimensions was the help I needed - also doing it onchange not just on load.

  • ElielDinaullyElielDinaully Eliel Dinaully USMember

    @KeithRowe , @ChristineBlanda Hi, I can't make it work when i rotate my iphone 5C screen, the webview width don't change at all.

    Here is my customwebviewrender :

    using Xamarin.Forms.Platform.iOS;
    using app.iOS;
    using app;
    using Xamarin.Forms;
    using UIKit;
    
    [assembly: ExportRenderer (typeof (CustomWebView), typeof (CustomWebViewRenderer))]
    namespace app.iOS
    {
        public class CustomWebViewRenderer : WebViewRenderer
        {
            // Override the OnElementChanged method so we can tweak this renderer post-initial setup
            protected override void OnElementChanged (VisualElementChangedEventArgs e)
            {
                base.OnElementChanged (e);
    
                var webView = this;
                webView.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
                webView.ScalesPageToFit = true;
            }
    
    
        }
    }
    

    Any idea of the problem?

  • KeithRoweKeithRowe Keith Rowe USMember

    @ElielDinaully - I'm not positive, but it may be that you need to apply these to the base view hosting the webview as well.

  • ElielDinaullyElielDinaully Eliel Dinaully USMember
    edited March 2015

    @KeithRowe

    Can't get it at all.

    I have a ContentPage, with a custom stacklayout with my webview in :

    var stack = new CustomStackLayout { Padding = 0, Orientation = StackOrientation.Vertical, VerticalOptions = LayoutOptions.FillAndExpand, HorizontalOptions = LayoutOptions.FillAndExpand };

    The CustomStackLayoutRenderer in iOS :

    public class CustomStackLayoutRenderer : VisualElementRenderer<StackLayout> { // Override the OnElementChanged method so we can tweak this renderer post-initial setup protected override void OnElementChanged (Xamarin.Forms.Platform.iOS.ElementChangedEventArgs<Xamarin.Forms.StackLayout> e) { base.OnElementChanged (e); Console.WriteLine ("is called"); this.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions; } }

    and my webview is then added to the stacklayout :

    CustomWebView webView = new CustomWebView {
                    Source = new HtmlWebViewSource {
                        Html = d.description
                    }, 
                    VerticalOptions = LayoutOptions.FillAndExpand,
                    HorizontalOptions = LayoutOptions.FillAndExpand
                };
    stack.Children.add(webview);
    
    Content = stack;
    

    And when i rotate to landscape, same problem... Doesn't fill the screen, i may be missing something or not doing it well at all.

  • MichaelKollegger.4961MichaelKollegger.4961 Michael Kollegger ATMember

    Hey Guys,
    it seems that we may have a similar problem, may you can take a look at my issue too: forums.xamarin.com/discussion/comment/111959
    We would appreciate any help!!! Thanky in advance!

  • Craig.4350Craig.4350 Craig Bentall USMember

    @ChristineBlanda Hi how would I go about creating a custom render for WebView

  • Craig.4350Craig.4350 Craig Bentall USMember

    Just added the autoresizeingMask and it worked. Thanks @ChristineBlanda

            var webView = new UIWebView(View.Bounds);
            webView.ScalesPageToFit = true;
            **webView.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;**
            string url = "WEBSITE.COM";
            webView.LoadRequest(new NSUrlRequest(new NSUrl(url)));
    
            View.AddSubview(webView);
    
  • KeithRoweKeithRowe Keith Rowe USMember

    OK, had used this for a different custom renderer (local video player). Now implementing Xamarin.Forms webview and having the same problems. Are people re-writing the Forms webview into a custom renderer because it does not have the rotation down? Or is there a solution for the Forms Webview?

  • DavidJohnson.9477DavidJohnson.9477 David Johnson USMember

    I'm having the same problem with a custom WebViewRenderer. Setting AutoresizingMask = UIViewAutoresizing.FlexibleDimensions; has no effect. When I rotate to landscape, the right half of the screen is black. Has anyone gotten this to work?

  • JohnHardmanJohnHardman John Hardman GBUniversity ✭✭✭✭✭

    I know this is a long-running thread, and we can find ways to make this work, but this should be sorted in the Xamarin iOS support in XF. I've raised bug 30297 as I couldn't find an existing bug for this in Bugzilla.

  • TimKlingeleersTimKlingeleers Tim Klingeleers BEMember

    I was having issues with this as well, and I've tried every suggestion that was made here without success.

    After looking a bit further I found out that manipulating the Bounds of the NativeView was successfull. Since my WebView is fullscreen the following implementation of LayoutSubviews did the trick:
    public override void LayoutSubviews () { base.LayoutSubviews (); NativeView.Bounds = UIKit.UIScreen.MainScreen.Bounds; }

    However this does only work when you have a fullscreen webview. Haven't tried to get it to work with a WebView that's not fullscreen yet.

    Hoping to see the issue fixed soon because all of these hacks are annoying. Thanks for the bug report @JohnHardman! And just for reference: https://bugzilla.xamarin.com/show_bug.cgi?id=30297

  • GerhardWagnerGerhardWagner Gerhard Wagner ATMember

    Did anyone find a workaround to handle this isue? ( WebView does not resize on iOS when change orientation)

    I have also problems in Loading the page the first time (without changing orientation)
    After Reloading, everything seems to be fine...

    I think it is an timing issue, when the page is originally loaded, and the onchanges event (in the webviewpagerenderer) is a little to late...
    After reloading (it is coming out of the cache) and everything is fine...

    Any ideas?

    Thanks,
    Gerhard

  • hvaughanhvaughan hines vaughan USMember ✭✭✭

    @TimKlingeleers
    This works great, but I am hoping you might be able to help me figure out how to subtract UIKit.UIScreen.MainScreen.Bounds from the height of the Nav Bar on the screen. I found UIKit.UIScreen.MainScreen.ApplicationFrame which subtracts the bounds of the status bar, but I cannot seem to figure out how to get the bounds of the Nav Bar when the view is within a NavigationPage.

    Otherwise the only thing that has worked for me is to refresh the WebView using UIWebView.Refresh() but even that makes everything look weird until you click a new link so it is not a great solution.

  • TimKlingeleersTimKlingeleers Tim Klingeleers BEMember

    @hvaughan I did not test this but you should be able to get the height of the navigation bar from NavigationController.NavigationBar.Frame.Height from within your iOS renderer. Please keep in mind to check for null's on the NavigationController property.

    Let me know if this helped you, otherwise I'll try to investigate further if time permits.

  • rmarinhormarinho Rui Marinho PTMember, Insider, Beta Xamurai
    edited August 2015

    Hey guys we have fixed this issue.. should be available in 1.5.1-pre1 when it's released.

  • hvaughanhvaughan hines vaughan USMember ✭✭✭

    @TimKlingeleers
    Well I am not sure how to get NavigationController from my WebViewRenderer but I did find this site saying that the Navigation Bar is always 44 pts. So subtracting that from Bounds.Height does do the trick for now. But I am glad the they were finally able to fix it! Thanks for your help.

    http://www.idev101.com/code/User_Interface/sizes.html

  • TimKlingeleersTimKlingeleers Tim Klingeleers BEMember

    Oh you are right @hvaughan, NavigationController isn't directly accessible from a WebViewRenderer. I was mixing it up with the PageRenderer base class.

    By the way, the Navigation Bar can also be 32 pts when in landscape mode. In portrait it's 44 pts indeed. However keep in mind that these numbers can change in future versions of the OS.

    Good to see the issue get fixed in 1.5.1-pre1!

  • hvaughanhvaughan hines vaughan USMember ✭✭✭
    edited September 2015

    All, I was able to fix this issue by setting the WebView's HeightRequest and WidthRequest to the ContentPage/ContentView's Height and Width from within the SizeChanged event, which should get called on device Orientation.

    ContentPage's Constructor:

    SizeChanged += (sender, arg) => {
        Padding = new Thickness(0, Height > Width ? 10 : 5, 0, 0);
    
        WebViewItem.HeightRequest = Height;
        WebViewItem.WidthRequest  = Width;
    };
    

    I also fixed another slightly related issue with the iOS WebView. The issue happened when a user clicked a 'Refresh' Button in the app, which would set the WebView's Source property to a new HtmlWebViewSource. The first time a user would click the 'Refresh' Button, the WebView would be completely blank and would not show any content. If the user clicked the Button again, the data would show up normally again.

    To fix this, I am now changing the WebView's Source property, removing the WebView from it's parent StackLayout, and then re-adding the WebView back to the StackLayout.

    Part of a method that eventually gets run when the 'Refresh' button is clicked:

    WebView clickedOnWebView = (WebView)clickedOnStackLayout.Children.FirstOrDefault();
    Device.BeginInvokeOnMainThread(() => {
        clickedOnWebView.Source = new HtmlWebViewSource { Html = newHtmlData };
        clickedOnStackLayout.Children.RemoveAt(0);
        clickedOnStackLayout.Children.Add(clickedOnWebView);
    });
    
  • SubhaMuralidharan.6484SubhaMuralidharan.6484 Subha Muralidharan USMember

    @rmarinho ,
    I don't think this issue is fixed. I am using Xamarin.Forms 1.5.1.6468 and I am changing webview's width & height on device orientation change in OnSizeAllocated method. But its not working. I am testing in iOS devices 6.1 & 8.4. @TimKlingeleers solution is working in 8.4 device. But in 6.1 device, width is not expanding in landscape mode. Its positioning in center of the page.

    How to fix it?

  • rmarinhormarinho Rui Marinho PTMember, Insider, Beta Xamurai

    Hi @SubhaMuralidharan.6484 correct it isn't fixed yet. We got a solution working but it broke other behaviours so we didn't release that fix. Will provide info on the bugzilla issue when we have a fix ready again.

  • CaptainXamtasticCaptainXamtastic Anthony Harrison GBUniversity ✭✭✭

    Hi @rmarinho, this is not working in Xamarin.Forms Version 2.0.0.6484 either, is there any chance of you posting a complete interim Renderer solution codebase that caters for both iOS and Android, we've been putting the release of our Xamarin Forms SDK off for a while for problems like these but we've got to get it out by December 4?

  • CaptainXamtasticCaptainXamtastic Anthony Harrison GBUniversity ✭✭✭

    Thanks hines, that's excellent! We've got a User Story where some content wont have links, so after some discussion the Product Owner decided to put the iOS WebView into the release as is, knowing that the user will just manually resize it themselves; in our case it's just come down to letting it through under the Known Issues category. Thanks for your help, though, it's bookmarked as our go-to workaround where content will contain links, etc.

  • CaptainXamtasticCaptainXamtastic Anthony Harrison GBUniversity ✭✭✭

    For the benefit of others, we did find that the following renderer does work, so long as you want the WebView fullscreen (however in our SDK we aren't to know how integrators will use it, hence abandoned it). But it does work per se:

        public class OurWebViewRenderer : WebViewRenderer
        {
            public OurWebViewRenderer()
            {
                this.ScalesPageToFit = true;
                this.AutoresizingMask = UIKit.UIViewAutoresizing.FlexibleDimensions;
            }
    
            protected override void OnElementChanged(VisualElementChangedEventArgs e)
            {
                base.OnElementChanged(e);
    
           // just to illustrate that the source action is happening in the Forms webview
                OurWebView owv = (OurWebView)this.Element;
                var temp = owv.HtmlString;
    
            }
    
            public override void LayoutSubviews()
            {
                base.LayoutSubviews();
                NativeView.Bounds = UIKit.UIScreen.MainScreen.Bounds;
            }
        }
    

    Naturally the above must be decorated with the following - OUTSIDE the namespace, not inside:

    [assembly: ExportRendererAttribute(typeof(OurWebView), typeof(OurWebViewRenderer))]

    And this is the Forms WebView:

    public class OurWebView : WebView
    {
        public static readonly BindableProperty HtmlStringProperty =
            BindableProperty.Create<OurWebView, string>(ctrl => ctrl.HtmlString,
            defaultValue: string.Empty,
            defaultBindingMode: BindingMode.TwoWay,
            propertyChanging: (bindable, oldValue, newValue) =>
            {
                var ctrl = (OurWebView)bindable;
                ctrl.HtmlString = newValue;
            });
    
            public string HtmlString
            {
                get { return (string)base.GetValue(HtmlStringProperty); }
                set { base.SetValue(HtmlStringProperty, value); }
            }
    
        public OurWebView()
        {
            this.PropertyChanged += (s, e) =>
                {
                    if (e.PropertyName.Equals(OurWebView.HtmlStringProperty.PropertyName))
                    {
                        var htmlSource = new HtmlWebViewSource();
                        htmlSource.Html = HtmlString;
    
                        this.Source = htmlSource;
                    }
                };
        }
    
    }
    
  • zmp2000zmp2000 Daniel Scatigno BRMember

    Hi, heres my solution, I was having a similar problem when rotating Ipad or Iphone, the page inside the UIWebView was fine, but the frame of the component kept it original size. My solution:
    Override the method DidRotate of ViewController and resize every subview:
    public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation) { foreach (UIView view in View.Subviews) { view.Frame = View.Bounds; } base.DidRotate(fromInterfaceOrientation); }

Sign In or Register to comment.