Leo Jebran
Leo Jebran

Reputation: 174

Styling an external webpage with local css Xamarin forms

I'm getting an external page HTML code from my Backend as a string

and displaying it in a Webview in a Xamarin forms app

Now I would like to style it

I was wondering what is the most efficient way to do that?

and is it possible to style it in the same way a Xamarin Page would get styled with XAML and shared resources?

so far I tried referencing a CSS file in the shared resources, which I found out doesn't work...

htmlData = "<link rel=\"stylesheet\" type=\"text/css\"href=\"Assets\"Styles\"style.css\" />" + htmlData; 
htmlSource.Html = htmlData;
myWebView.Source = htmlSource;

Update

I ended up using a custom renderer for the Webview

which worked for Android but not for IOS

here is my IOS implementation of the renderer

    [assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace XXX.iOS.Renderers
{
    public class CustomWebViewRenderer : WkWebViewRenderer
    {
        WKUserContentController userController;

        public CustomWebViewRenderer() : this(new WKWebViewConfiguration())
        {
        }
        public CustomWebViewRenderer(WKWebViewConfiguration config) : base(config)
        {
            userController = config.UserContentController;
        }

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            var customWebView = e.NewElement as CustomWebView;

            if (e.NewElement != null)
            {
                string htmldata = customWebView.HTMLData;

                htmldata = "<link rel=\"stylesheet\" type=\"text/css\" href=\"StyleSheet.css\" />" + htmldata;

                WkWebViewRenderer wkWebViewRenderer = new WkWebViewRenderer();

                NSData data = NSData.FromString(htmldata);

                wkWebViewRenderer.LoadData(data,"text/html", "UTF-8",new NSUrl(""));
            }
        }
    }
}

Note: I don't have any idea what is happening here with the IOS code, cause I have never coded in the native language

Upvotes: 0

Views: 438

Answers (1)

Paul Kertscher
Paul Kertscher

Reputation: 9703

I don't know whether this is feasible for you, but you could inject the actual CSS in the HTML string and then assign the HtmlSource

var css = ReadStringFromAsset("style.css");
htmlData = InjectCssInHtml(htmlData, css);
htmlSource.Html = htmlData;
myWebView.Source = htmlSource;

Depending on how much control you have over the HTML you receive, you have several option on how to realize InjectCssInHtml

Pseudo-Markup comment

If changing the HTML is feasible, you could add an HTML comment as a pdeudo markup. This will make the code simple, but each HTML must be edited accordingly

<html>
<head>
<style>
<!-- CSS -->
</style>
...
</html>

your InjectCssInHtml then becomes

string InjectCssInHtml(string html, string css)
{
    return html.Replace("<!-- CSS -->", css);
}

Without editing the HTML

If editing the HTML is not feasible, the InjectCssInHtml becomes a tad more complicated. The following is a first guess, but I think you get the idea

string InjectCssInHtml(string html, string css)
{
    string codeToInject;
    int indexToInject = 0;

    if(ContainsStyleTag(html))
    {
        indexToInject = IndexOfStyleTagContent(html);
        codeToInject = css;
    }
    else if(ContainsHeadTag(html))
    {
        indexToInject = IndexOfHeadTagContents(html);
        codeToInject = $"<style>{css}</style>";
    }
    else
    {
        indexToInject = IndexOfHtmlTagContents(html);
        codeToInject = $"<head><style>{css}</style></head>";
    }

    return html.Insert(indexToInject, codeToInject);
}

Surely this does not cover each possible case, but I think you get the idea. The ìf-else` could be replaced by an abstract factory generational pattern combined with the strategy behavioral pattern.

string InjectCssInHtml(string html, string css)
{
    ICssInjector injector = injectorFactory.CreateInjector(html);
    return injector.InjectCss(html, css);

}

Upvotes: 1

Related Questions