Reputation: 2163
I'm developing n app that has some content pages from our CMS
that need to be displayed into a WebView
since they have HTML with some hyperlinks in it
I'm controlling the hyperlinks which is working as expected on Android.
I'm doing this with the Navigating
of the Xamarin.Forms.WebView event
I'm able to use e.Url
to send the user to a internal page.
Example:
public class HybridWebView : WebView
{
public String Code { get; set; }
public HybridWebView()
{
Navigating += HybridWebView_Navigating;
}
private void HybridWebView_Navigating(object sender, WebNavigatingEventArgs e)
{
if(e.Url.EndsWith(".aspx")
{
var CMS = new CMSView(e.Code, null);
Navigation.PushAsync(CMS);
e.Cancel = true;
}
}
}
Note this works well!
The problem is:
when I try this on iOS I got a blank/white WebView
.
I tried to make a CustomRenderer on iOS but since I subclass the WebView to customize it I can't reach the properties Code
for example.
How can I reach the properties in the custom renderer for iOS? I know e.NewElement
but ShouldStartLoad
expects UIWebView and not my custom HybridWebView.
Does anyone has any tips or ideas how I can reach this?
Thanks in advance
Upvotes: 2
Views: 3278
Reputation: 2398
If you want to use ShouldStartLoad
, you'll need to implement a custom UIWebViewDelegate
for the native UIWebView
being used. This can get tricky because if you replace the existing delegate with a custom one, you'll lose some of the built-in features that Xamarin.Forms WebView
provides. Here is the strategy I use to get the best of both:
[assembly: ExportRenderer (typeof (WebView), typeof (CustomWebViewRenderer))]
public class CustomWebViewRenderer : WebViewRenderer
{
protected override void OnElementChanged (VisualElementChangedEventArgs e)
{
base.OnElementChanged (e);
if (e.OldElement == null) {
// Need to capture the existing one so we don't loose functionality
// that Xamarin.Forms already has
var existingDelegate = Delegate;
// Make sure to pass the existing one to the new one
Delegate = new MyCustomWebViewDelegate(existingDelegate);
}
}
}
public class MyCustomWebViewDelegate : UIWebViewDelegate
{
readonly UIWebViewDelegate existingDelegate;
public MyCustomWebViewDelegate(UIWebViewDelegate existing)
{
existingDelegate = existing;
}
public override bool ShouldStartLoad (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType)
{
// You can customize this instead of returning the existingDelegate method
return existingDelegate.ShouldStartLoad(webView, request, navigationType);
}
public override void LoadFailed (UIWebView webView, NSError error)
{
existingDelegate.LoadFailed(webView, error);
}
public override void LoadingFinished (UIWebView webView)
{
existingDelegate.LoadingFinished(webView);
}
public override void LoadStarted (UIWebView webView)
{
existingDelegate.LoadStarted(webView);
}
}
Note* On iOS, WebViewRenderer inherits directly from UIWebView, so you don't have a Control property work with. You are a direct subclass of UIWebView and have access to the properties you would expect. See source here.
You can add custom login to the MyCustomWebViewDelegate.ShouldStartLoad
method.
Upvotes: 2
Reputation: 6098
In your customer renderer (a subclass of WebViewRenderer I assume) you can cast e.newElement to your HybridWebView type, e.g.:
HybridWebView wv = e.NewElement as HybridWebView;
Then you should be able to access your Code
property with wv.Code
.
Also the NativeView
property of the WebViewRenderer
will give you the iOS native UIView
to work with. You should be able to cast this to a UIWebView without issue. E.g:
UIWebView nativeUIWebView = NativeView as UIWebView;
I hope this helps!
Upvotes: 4