【问题标题】:Xamarin iOS webview underlap behind navigation barXamarin iOS webview 在导航栏后面重叠
【发布时间】:2020-06-01 00:19:38
【问题描述】:

我正在使用 xamarin 自定义 webview 在应用程序中加载我的页面。但面临网页标题隐藏在导航栏后面的问题。或者有时页面底部未显示。我尝试在布局中添加滚动条,但仍然面临问题。同样适用于android。是因为自定义 webview 吗?我只希望我的 webview 从导航栏下方开始并根据设备大小完全加载。

我的自定义 webview 代码

public class CustomWebView : WebView
    {
        public static readonly BindableProperty UriProperty = BindableProperty.Create(
        propertyName: "Uri",
        returnType: typeof(string),
        declaringType: typeof(CustomWebView),
        defaultValue: default(string));

        public string Uri
        {
            get { return (string)GetValue(UriProperty); }
            set { SetValue(UriProperty, value); }
        }
    }

Xaml 页面:

<StackLayout Orientation="Vertical" HorizontalOptions="StartAndExpand" VerticalOptions="StartAndExpand">
            <StackLayout>
                <Label x:Name="type" Text="Loading..." FontSize="Medium"/>
            </StackLayout>
            <StackLayout  VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
                <ScrollView Orientation="Vertical" FlowDirection="MatchParent" HorizontalOptions="StartAndExpand" VerticalOptions="StartAndExpand" Visual="Material" VerticalScrollBarVisibility="Always">
                    <OnPlatform x:TypeArguments="View">
                        <On Platform="Android">
                            <WebView  x:Name="dashboard_android"  HeightRequest="1000" WidthRequest="1000"  />
                        </On>
                        <On Platform="iOS">
                            <local:CustomWebView  x:Name="dashboard_ios" VerticalOptions="StartAndExpand" HorizontalOptions="FillAndExpand"  WidthRequest="1000"  HeightRequest="1000"/>
                        </On>
                    </OnPlatform>
                </ScrollView>

            </StackLayout>
        </StackLayout>

后面的代码:

dashboard_android.Source = url;
  dashboard_ios.Uri = url;

以下是我尝试过但没有成功的解决方案

解决方案 1: 我试过添加两个属性,但没有用

this.EdgesForExtendedLayout = UIRectEdge.None;

   this.ExtendedLayoutIncludesOpaqueBars = false;

解决方案 2:

尝试启用此不安全区域属性,仍然没有成功

ios:Page.UseSafeArea="true"

解决方案 3:

尝试在内容大小上动态设置 webview 高度,但没有成功

 public override async void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
        {
            // base.DidFinishNavigation(webView, navigation);

            var wv = _webViewRenderer.Element as CustomWebView;
            if (wv != null)
            {
                await System.Threading.Tasks.Task.Delay(100); // wait here till content is rendered
                wv.HeightRequest = (double)webView.Frame.Size.Height; // ScrollView.ContentSize.Height;
            }

        }

更新的 Xaml 代码:

 <StackLayout  VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
 <local:CustomWebView  x:Name="dashboard"  HeightRequest="1000" WidthRequest="1000" />
</StackLayout>

更新后的代码:

public partial class DashboardView : ContentPage
    {
        string url;
        public DashboardView()
        {
            InitializeComponent();
            url= ""; //adding url to load here
           dashboard.Uri = url;

      }
    }

自定义 WebView 渲染器

    [assembly: ExportRenderer(typeof(CustomWebView), typeof(MyCustomWebViewRenderer))]
    namespace Report.iOS
    {


        public class MyCustomWebViewRenderer : ViewRenderer<CustomWebView, WKWebView> 
        {
            WKWebView webView;
            protected override void OnElementChanged(ElementChangedEventArgs<CustomWebView> e)
            {
                base.OnElementChanged(e);

                if (Control == null)
                {
                    webView = new WKWebView(Frame, new WKWebViewConfiguration());

                    webView.NavigationDelegate = new WebViewDelegate();


                    SetNativeControl(webView);     

                }
                if (e.NewElement != null)
                {

                   Control.LoadRequest(new NSUrlRequest(new NSUrl(Element.Uri)));

                }
            }

    }


    public  class WebViewDelegate : WKNavigationDelegate, INSUrlConnectionDataDelegate 
    {
        string uname = null;
        string pass = null;




        public override async void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
        {
            try
            {
                uname = Xamarin.Forms.Application.Current.Properties.ContainsKey("Username") ? Convert.ToString(Xamarin.Forms.Application.Current.Properties["Username"]) : null;
                pass = await SecureStorage.GetAsync("Password");
            }
            catch (Exception ex)
            {

            }
            completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, new NSUrlCredential(uname, pass, NSUrlCredentialPersistence.ForSession));

            return;
        }
    }
}

webview 屏幕截图:

我在这里加载这个网页(https://docs.microsoft.com/en-us/xamarin/essentials/device-display?tabs=android)。 如您所见,页脚的一半被隐藏,我无法滚动它。

Screenshot of app

【问题讨论】:

  • 移动滚动视图可能有效。我使用你的代码,我无法重现你在问题中所说的问题。您能否添加更多代码或示例项目?
  • 我删除了滚动视图并更新了我的最新代码。你能检查一下吗?
  • 您的代码在我这边仍然运行良好。您可以添加屏幕截图还是有其他代码?一个示例项目会更好。
  • 您好,我已添加图片。如您所见,半页脚被隐藏并且无法滚动。请帮忙

标签: xamarin xamarin.forms webview xamarin.ios navigationbar


【解决方案1】:

原因很简单,实际上你已经在 scrollView 中添加了 WebView,这反过来又导致问题 webview 有自己的滚动,所以你所要做的就是:

        <StackLayout  VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">               
           <local:CustomWebView  x:Name="dashboard" />
        </StackLayout>

另外,你不需要在平台上直接使用下面的和你创建的自定义渲染器。

不需要高度/宽度请求和布局选项默认情况下 Webview 将捕获整个视口,实际上您甚至可以删除 StackLayouts,但这取决于您。

另外,您可能想了解更多关于webview

祝你好运

如有疑问,请随时回复

【讨论】:

  • 谢谢!我已尝试按照您的建议更新我的 xaml,但仍然 webview 没有捕获视口。你能帮我吗 ?还有其他变化吗?
  • 您能否更新您的内容页面的最新代码 + 代码?例如,您如何加载页面!此外,带有显示外观的标记的问题屏幕截图会有所帮助!
  • 我已经更新了我的最新代码。你能检查一下吗?
【解决方案2】:

你可以使用最新的WkWebViewRenderer:

public class MyCustomWebViewRenderer : WkWebViewRenderer
{
    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);

        //this.LoadUrl("https://docs.microsoft.com/en-us/xamarin/essentials/device-display?tabs=android");

        this.NavigationDelegate = new WebViewDelegate();

    }
}

在你的代码后面,你可以直接设置源或者设置你的绑定:

dashboard.Source = "https://docs.microsoft.com/en-us/xamarin/essentials/device-display?tabs=android";

另外,从 xamarin.forms 4.5+ 开始,xamarin 使用 WKWebview 作为 iOS 中的默认控件,这意味着如果您使用 xamarin.forms 4.5+,则不再需要自定义渲染器。参考:

UIWebView Deprecation and App Store Rejection (ITMS-90809)

【讨论】:

  • 如果像你说的那样使用 WkViewRenderer,我该如何添加导航委托。我想在加载之前使用 WKNavigationDelegate 对 webview 进行身份验证
  • @SakshiBole 请检查我更新的代码。如果它解决了您的问题,请不要忘记标记此答案:)。
【解决方案3】:

我正面临这个问题,因为我使用的是自定义渲染器。 我的解决方案代码如下:

Xaml 代码

 <ContentPage.Content>
        <StackLayout  VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
            <WebView  x:Name="dashboard" HeightRequest="1000" WidthRequest="1000"/>
        </StackLayout>
    </ContentPage.Content>

代码隐藏:

 public partial class DashboardView : ContentPage
        {
            public DashboardView()
            {
                InitializeComponent();
                dashboard.Source = "url"; 
            }

        }

身份验证渲染器 iOS:

[assembly: ExportRenderer(typeof(WebView), typeof(Report.iOS.WebViewRenderer))]
namespace Report.iOS
{
    class WebViewRenderer : WkWebViewRenderer
    {
        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);
            this.NavigationDelegate = new WebViewDelegate();

        }
    }

    public class WebViewDelegate : WKNavigationDelegate, INSUrlConnectionDataDelegate
    {
        string uname = null;
        string pass = null;

        public override async void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
        {
            try
            {
                uname = Xamarin.Forms.Application.Current.Properties.ContainsKey("Username") ? Convert.ToString(Xamarin.Forms.Application.Current.Properties["Username"]) : null;
                pass = await SecureStorage.GetAsync("Password");
            }
            catch (Exception ex)
            {

            }
            completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, new NSUrlCredential(uname, pass, NSUrlCredentialPersistence.ForSession));

            return;
        }
    }



}

Android 身份验证渲染器:

[assembly: ExportRenderer(typeof(WebView), typeof(AuthWebViewRenderer))]

namespace Report.Droid
{

    public class AuthWebViewRenderer : Xamarin.Forms.Platform.Android.WebViewRenderer
    {
        AuthWebViewClient _authWebClient = null;


        public  AuthWebViewRenderer(Context context) : base(context)
        {

        }


        protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<WebView> e)
        {
            base.OnElementChanged(e);
            if (_authWebClient == null)
            {
                _authWebClient = new AuthWebViewClient();

            }
            Control.SetWebViewClient(_authWebClient);
        }
    }
    public class AuthWebViewClient : WebViewClient
    {

        public AuthWebViewClient()
        {

        }


        public override async  void OnReceivedHttpAuthRequest(global::Android.Webkit.WebView view, HttpAuthHandler handler, string host, string realm)
        {
            string uname = null;
            string pass = null;
            try
            {
                uname = Application.Current.Properties.ContainsKey("Username") ? Convert.ToString(Application.Current.Properties["Username"]) : null;
                pass = await SecureStorage.GetAsync("Password");
            }
            catch (Exception ex)
            {
                Log.Error("Apprise :", "Error Occurred while getting login credentials " + ex);
            }
            handler.Proceed(uname, pass);
        }


    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-03
    • 1970-01-01
    相关资源
    最近更新 更多