Hi All,
I have created WkWebviewRenderer since iOS doesn't have one.
The problem is it doesn't show in the UI.
Any pointers here would help!!
Thanks!
using System;
using System.ComponentModel;
using System.Drawing;
using Foundation;
using ObjCRuntime;
using UIKit;
using WebKit;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Platform.iOS
{
public class WKWebViewRenderer : WKWebView, IVisualElementRenderer, IWebViewDelegate, IEffectControlProvider
{
private EventTracker _events;
private bool _ignoreSourceChanges;
private WebNavigationEvent _lastBackForwardEvent;
private VisualElementPackager _packager;
pragma warning disable 0414
private VisualElementTracker _tracker;
pragma warning restore 0414
public WKWebViewRenderer() : base(RectangleF.Empty, new WKWebViewConfiguration())
{
}
public WebView WebView => Element as WebView;
public VisualElement Element { get; private set; }
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
{
return NativeView.GetSizeRequest(widthConstraint, heightConstraint, 44, 44);
}
public void SetElement(VisualElement element)
{
var oldElement = Element;
Element = element;
Element.PropertyChanged += HandlePropertyChanged;
WebView.EvalRequested += OnEvalRequested;
WebView.GoBackRequested += OnGoBackRequested;
WebView.GoForwardRequested += OnGoForwardRequested;
NavigationDelegate = new CustomWebViewDelegate(this);
BackgroundColor = UIColor.Red;
AutosizesSubviews = true;
_tracker = new VisualElementTracker(this);
_packager = new VisualElementPackager(this);
_packager.Load();
_events = new EventTracker(this);
_events.LoadEvents(this);
Load();
OnElementChanged(new VisualElementChangedEventArgs(oldElement, element));
EffectUtilities.RegisterEffectControlProvider(this, oldElement, element);
if (Element != null && !string.IsNullOrEmpty(Element.AutomationId))
AccessibilityIdentifier = Element.AutomationId;
//if (Element != null)
//{
// var width = element.Width;
// var height = element.Height;
// Element.WidthRequest = 200.0;
// Element.HeightRequest = 200.0;
// Element.BackgroundColor = Color.AliceBlue;
//}
//element.SendViewInitialized(this);
}
public void SetElementSize(Size size)
{
Layout.LayoutChildIntoBoundingRegion(Element, new Rectangle(Element.X, Element.Y, size.Width, size.Height));
}
public void LoadHtml(string html, string baseUrl)
{
if (html != null)
LoadHtmlString(html, baseUrl == null ? new NSUrl(NSBundle.MainBundle.BundlePath, true) : new NSUrl(baseUrl, true));
}
public void LoadUrl(string url)
{
LoadRequest(new NSUrlRequest(new NSUrl(url)));
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
// ensure that inner scrollview properly resizes when frame of webview updated
ScrollView.Frame = Bounds;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (IsLoading)
StopLoading();
Element.PropertyChanged -= HandlePropertyChanged;
WebView.EvalRequested -= OnEvalRequested;
WebView.GoBackRequested -= OnGoBackRequested;
WebView.GoForwardRequested -= OnGoForwardRequested;
_tracker?.Dispose();
_packager?.Dispose();
}
base.Dispose(disposing);
}
protected virtual void OnElementChanged(VisualElementChangedEventArgs e)
{
var changed = ElementChanged;
if (changed != null)
changed(this, e);
}
public void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == WebView.SourceProperty.PropertyName)
Load();
}
public void Load()
{
if (_ignoreSourceChanges)
return;
if (((WebView)Element).Source != null)
((WebView)Element).Source.Load(this);
UpdateCanGoBackForward();
}
public void OnEvalRequested(object sender, EvalRequested eventArg)
{
EvaluateJavaScript(eventArg.Script, null);
}
public void OnGoBackRequested(object sender, EventArgs eventArgs)
{
if (CanGoBack)
{
_lastBackForwardEvent = WebNavigationEvent.Back;
GoBack();
}
UpdateCanGoBackForward();
}
public void OnGoForwardRequested(object sender, EventArgs eventArgs)
{
if (CanGoForward)
{
_lastBackForwardEvent = WebNavigationEvent.Forward;
GoForward();
}
UpdateCanGoBackForward();
}
public void UpdateCanGoBackForward()
{
((IWebViewController)WebView).CanGoBack = CanGoBack;
((IWebViewController)WebView).CanGoForward = CanGoForward;
}
public class CustomWebViewDelegate : WKNavigationDelegate
{
public readonly WKWebViewRenderer _renderer;
public WebNavigationEvent _lastEvent;
public CustomWebViewDelegate(WKWebViewRenderer renderer)
{
if (renderer == null)
throw new ArgumentNullException("renderer");
_renderer = renderer;
}
public WebView WebView
{
get { return (WebView)_renderer.Element; }
}
public override void DidFailNavigation(WKWebView webView, WKNavigation navigation, NSError error)
{
var url = GetCurrentUrl();
WebView.SendNavigated(new WebNavigatedEventArgs(_lastEvent, new UrlWebViewSource { Url = url }, url, WebNavigationResult.Failure));
_renderer.UpdateCanGoBackForward();
}
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
if (webView.IsLoading)
return;
_renderer._ignoreSourceChanges = true;
var url = GetCurrentUrl();
WebView.SetValueFromRenderer(WebView.SourceProperty, new UrlWebViewSource { Url = url });
_renderer._ignoreSourceChanges = false;
var args = new WebNavigatedEventArgs(_lastEvent, WebView.Source, url, WebNavigationResult.Success);
WebView.SendNavigated(args);
_renderer.UpdateCanGoBackForward();
}
public override void DecidePolicy(WKWebView webView, WKNavigationAction navigationAction, Action<WKNavigationActionPolicy> decisionHandler)
{
var navEvent = WebNavigationEvent.NewPage;
switch (navigationAction.NavigationType)
{
case WKNavigationType.LinkActivated:
navEvent = WebNavigationEvent.NewPage;
break;
case WKNavigationType.FormSubmitted:
navEvent = WebNavigationEvent.NewPage;
break;
case WKNavigationType.BackForward:
navEvent = _renderer._lastBackForwardEvent;
break;
case WKNavigationType.Reload:
navEvent = WebNavigationEvent.Refresh;
break;
case WKNavigationType.FormResubmitted:
navEvent = WebNavigationEvent.NewPage;
break;
case WKNavigationType.Other:
navEvent = WebNavigationEvent.NewPage;
break;
}
_lastEvent = navEvent;
var lastUrl = webView.Url.ToString();
var args = new WebNavigatingEventArgs(navEvent, new UrlWebViewSource { Url = lastUrl }, lastUrl);
WebView.SendNavigating(args);
_renderer.UpdateCanGoBackForward();
}
private string GetCurrentUrl()
{
return _renderer?.Url?.AbsoluteUrl?.ToString();
}
}
#region IPlatformRenderer implementation
public UIView NativeView
{
get { return this; }
}
public UIViewController ViewController
{
get { return null; }
}
#endregion IPlatformRenderer implementation
void IEffectControlProvider.RegisterEffect(Effect effect)
{
VisualElementRenderer<VisualElement>.RegisterEffect(effect, this, NativeView);
}
}
}