In the first part of this series of posts, we took an introductory look at the Xamarin Forms WebView control. In this post we’ll use a custom renderer to implement a label control that uses the platforms native ability to display HTML strings.
Platform labels
Both iOS and Android have the ability to display HTML formatted strings in a built in control. These particular attributes are not available directly to Xamarin Forms, but with a quick custom renderer we can get at the functionality pretty easily.
The PCL bit
We’ll start with the sample project that we started in the previous post. In the PCL, create a new class that we’ll use to inherit from the Xamarin Forms Label control:
using Xamarin.Forms; namespace DisplayHtmlApp.UserControls { public class HtmlLabel : Label { } }
That’s it for the shared code.
Next we can implement the actual functionality on the platforms.
Android
In the Android project create a new class called HtmlLabelRenderer. I like to put custom renderers in their own namespace and folder, but that’s up to you. It’s the Assembly attribute that will let Xamarin Forms know where to find the implementation.
using System.ComponentModel; using Android.OS; using Android.Text; using Android.Widget; using DisplayHtmlApp.Droid.CustomRenderers; using DisplayHtmlApp.UserControls; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; [assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))] namespace DisplayHtmlApp.Droid.CustomRenderers { public class HtmlLabelRenderer : LabelRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Label> e) { base.OnElementChanged(e); Control?.SetText(GetText(), TextView.BufferType.Spannable); } protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == Label.TextProperty.PropertyName) { Control?.SetText(GetText(), TextView.BufferType.Spannable); } } private ISpanned GetText() { return (int)Build.VERSION.SdkInt >= 24 ? Html.FromHtml(Element.Text, FromHtmlOptions.ModeLegacy) : Html.FromHtml(Element.Text); } } }
You can see that we are creating an implementation of ISpanned from the Html.FromHtml method, that Android can use directly in it’s label renderer. The only slight complication is that the FromHtml method is deprecated in SDK v24, so we have to check that, and add the “ModeLegacy” enum as appropriate.
iOS
In the iOS project we’ll follow the same custom renderer pattern, but using the iOS specific NsAttributedString object.
using System.ComponentModel; using DisplayHtmlApp.iOS.CustomRenderers; using DisplayHtmlApp.UserControls; using Foundation; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; [assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))] namespace DisplayHtmlApp.iOS.CustomRenderers { public class HtmlLabelRenderer : LabelRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Label> e) { base.OnElementChanged(e); UpdateElement(); } protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == Label.TextProperty.PropertyName) { UpdateElement(); } } private void UpdateElement() { if (Control != null && Element != null && !string.IsNullOrWhiteSpace(Element.Text)) { var attr = new NSAttributedStringDocumentAttributes(); var nsError = new NSError(); attr.DocumentType = NSDocumentType.HTML; var myHtmlData = NSData.FromString(Element.Text, NSStringEncoding.Unicode); Control.Lines = 0; Control.AttributedText = new NSAttributedString(myHtmlData, attr, ref nsError); } } } }
Wrap up
You do have a few options if you need to display HTML in your Xamarin Forms app. The WebView offers full featured, browser like capabilities with events and navigation, or you can take advantage of the platforms native ability to display HTML by implementing a simple custom renderer.
As usual, a simple example is available at the XamarinInsider repo.
Hello
Please i’m trying to make a xamarin forms app and i’m using webview to display a website on the app but it’s displaying the whole website. I don’t want it to display the whole web site. For example i don’t want it to display the header and footer of the website.
Please how do i achieve that?
LikeLike
Hi Graham. Whatever is returned from the URL you supply is what will be displayed. It sounds like the header and footer are part of the page so there’s not much you can do about that. It may be possible to first get the markup that is returned and then strip out the bits that you don’t want before displaying the rest…depends whether it’s worth the effort!
LikeLike
if I want to display a pop-up or goto another view if source url could not be loaded. please how can I go about this
LikeLike
I think the only way to handle the not found and pop ups would be via the native web view and a custom renderer. I can’t think of any way to handle them via the Xamarin Forms view.
LikeLike
Hi!
Please i’m trying to make a xamarin tabbed page and i’m using webview to display a website. I don’t want it to display an uri with dynamics values . For example,
https://www.windguru.cz/1280/
https://www.windguru.cz/8729/
the first part of the uri is always the same “https://www.windguru.cz/” and the last part is dynamic
Please how do i achieve that?
Thanks in advance
LikeLike
Hi Marcelo, take a look at C#’s string.format (or more recently interpolation) functions.
You’ll be able to format the URL with a fixed domain and change just certain bits with a variable, something like string.Format(“https://www.windguru.cz/{0}/”, yourPageID)
LikeLike
Thanks a lot Nigel, is a good catch and it´s very useful, thanks again for your quick response!
Marcelo
LikeLike
How can I display HTML included image?
LikeLike
Hi there. To reference an embedded image, pop it in the Assets folder with a build action of Asset and you should be able to just reference it from your HTML string as normal.
LikeLike