Reputation: 174
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
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
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);
}
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