Forum Xamarin.Forms

Custom renderer for HTML Label

MartinStievenartMartinStievenart USMember, University ✭✭

Hi,

I have the need to display HTML in a Label. Some webservice returns me HTML content that i need to show in a listview page and a detail one.
The utilisation of a WebView will not be an answer because of performance issue in the listview page and te fact that i have a complex detail page.

The only thing i see on the Forums is to use FormattedString but i can't really decompose the whole HTML.

The last option i have is to create custom renderer in order to do that.
The only thing i know is that there's this function in Android Android.Text.Html.FromHtml() but i don't really know how to use it.

Can anyone help me with this ? First all with Android & iOS, and with Windows Phone later.

Regards

Best Answer

  • ChaseFlorellChaseFlorell CAInsider, University mod
    edited October 2015 Accepted Answer

    There's lots of documentation around writing a renderer, so I'll skip that bit. I believe what you're looking for is how to display html in a UITextView/TextView

    On Android you can do this

    var str = @"<strong>my string</strong>";
    var lbl = new TextView(Application.Context) {TextFormatted = Html.FromHtml(str)}; // bam - html TextView
    

    On iOS, you'll first need an extension method

    public static class NSStringExtensions
    {
        public static NSAttributedString AsAttributedString(this string input, NSDocumentType docType)
        {
            NSError err = null;
            var rtn = new NSAttributedString(input, new NSAttributedStringDocumentAttributes { DocumentType = docType }, ref err);
            if (err == null)
            {
                return rtn;
            }
            throw new NSErrorException(err);
        }
    }
    

    then it's similar to Android

    var str = @"<strong>my string</strong>".AsAttributedString(NSDocumentType.HTML);
    var lbl = new UITextView { AttributedText = str }; // bam - html UITextView
    

Answers

  • ChaseFlorellChaseFlorell CAInsider, University mod
    edited October 2015 Accepted Answer

    There's lots of documentation around writing a renderer, so I'll skip that bit. I believe what you're looking for is how to display html in a UITextView/TextView

    On Android you can do this

    var str = @"<strong>my string</strong>";
    var lbl = new TextView(Application.Context) {TextFormatted = Html.FromHtml(str)}; // bam - html TextView
    

    On iOS, you'll first need an extension method

    public static class NSStringExtensions
    {
        public static NSAttributedString AsAttributedString(this string input, NSDocumentType docType)
        {
            NSError err = null;
            var rtn = new NSAttributedString(input, new NSAttributedStringDocumentAttributes { DocumentType = docType }, ref err);
            if (err == null)
            {
                return rtn;
            }
            throw new NSErrorException(err);
        }
    }
    

    then it's similar to Android

    var str = @"<strong>my string</strong>".AsAttributedString(NSDocumentType.HTML);
    var lbl = new UITextView { AttributedText = str }; // bam - html UITextView
    
  • MartinStievenartMartinStievenart USMember, University ✭✭
    edited October 2015

    Thanks a lot @ChaseFlorell, as you said i known how to create a custom renderer what i didn't know was how to display HTML in a Label in the different platforms.

    Next is the code for my renderers, first for Android :

    protected override void OnElementChanged (ElementChangedEventArgs<Label> e) { base.OnElementChanged (e); Control.TextFormatted = new Android.Widget.TextView(this.Context) { TextFormatted = Android.Text.Html.FromHtml(Control.Text)}.TextFormatted; }

    For iOS :

    public static class NSStringExtensions {
      public static NSAttributedString AsAttributedString(this string input, NSDocumentType docType) {
        NSError err = null;
        var rtn = new NSAttributedString(input, new NSAttributedStringDocumentAttributes { DocumentType = docType }, ref err);
        if (err == null) {
          return rtn;
        }
        throw new NSErrorException(err);
      }
    }
    public class HtmlLabelRenderer : LabelRenderer {
      protected override void OnElementChanged (ElementChangedEventArgs<Label> e) {
        base.OnElementChanged (e);
    
        var text = Control.Text.AsAttributedString(NSDocumentType.HTML);
        Control.AttributedText = new UITextView { AttributedText = text }.AttributedText;
        Control.TextColor = UIColor.White;
      }
    }
    

    I have still a little problem maybe you know about that.
    In Android the ul and li elements are not interpreted, is this normal ?

    == EDIT ===
    Nevermind for my question, Android FromHtml does not support ul and li elements. If people need information about that (http://stackoverflow.com/questions/3150400/html-list-tag-not-working-in-android-textview-what-can-i-do)

  • My solution. Maybe it would help for someone have full solution

    My page

     <ContentPage.Content>
            <ScrollView Padding="10" VerticalScrollBarVisibility="Always">
                <StackLayout>
                    <Label
                        FontSize="Body"
                        Text="Title"
                        TextDecorations="Underline" />
                    <Label HorizontalOptions="FillAndExpand" Text="{Binding Title}" />
    
                   <Label
                        FontSize="Body"
                        Text="Html Info"
                        TextDecorations="Underline" />
    
                    <views:HtmlLabel Text="{Binding ContactInfo}" />
    
                    <StackLayout>
                        <Label
                            FontSize="Body"
                            Text="Products list"
                            TextDecorations="Underline" />
    
                        <ListView x:Name="ProductsInfoList" HasUnevenRows="true">
                            <ListView.ItemTemplate>
                                <DataTemplate>
                                    <ViewCell>
                                        <Grid>
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="*" />
                                                <ColumnDefinition Width="Auto" />
                                            </Grid.ColumnDefinitions>
                                            <Label Grid.Column="0" Text="{Binding Name}" />
                                            <Label Grid.Column="1" Text="{Binding TotalSum}" />
                                        </Grid>
                                    </ViewCell>
                                </DataTemplate>
                            </ListView.ItemTemplate>
                        </ListView>
                    </StackLayout>
                </StackLayout>
            </ScrollView>
        </ContentPage.Content>
    

    Then label renderer for Android

    [assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))]
    namespace App.Mobile.Droid.Services.Renderer
    {
        public class HtmlLabelRenderer : LabelRenderer
        {
            public HtmlLabelRenderer(Context context) : base(context)
            {
            }
    
            protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
            {
                base.OnElementChanged(e);
    
                Control?.SetText(Html.FromHtml(Element.Text), TextView.BufferType.Spannable);
            }
    
            protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged(sender, e);
    
                if (e.PropertyName == Label.TextProperty.PropertyName)
                {
                    Control?.SetText(Html.FromHtml(Element.Text), TextView.BufferType.Spannable);
                }
            }
        }
    }
    

    And custom label

    public class HtmlLabel : Label
        {
        }
    
Sign In or Register to comment.