Chhotan Bag
Chhotan Bag

Reputation: 21

How to display latex or mathematical equation in a android compose application?

I want to build a android application based on jet pack compose which can display math equations or latex.

I have checked internet and found many libraries but all are for xml and not for compose and also they are outdated and do not work for xml even. I am trying to find a library which work for compose or at the worst case for xml and need bare minimum code snippets for gradle, main activity Kotlin, compose (or xml) which works.

Upvotes: 1

Views: 1742

Answers (1)

Cristi Moldovan
Cristi Moldovan

Reputation: 100

Using KaTeX and WebViews, you need to create a file main/assets/latex_render.html, with the following content (most of it taken from KaTeX docs):

<!DOCTYPE html>
<!-- KaTeX requires the use of the HTML5 doctype. Without it, KaTeX may not render properly -->
<html>
<head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1odI+WdtXRGWt2kTvGFasHpSy3SV" crossorigin="anonymous">

    <!-- The loading of KaTeX is deferred to speed up page rendering -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" integrity="sha384-XjKyOOlGwcjNTAIQHIpgOno0Hl1YQqzUOEleOLALmuqehneUG+vnGctmUb0ZY0l8" crossorigin="anonymous"></script>

    <!-- To automatically render math in text elements, include the auto-render extension: -->
    <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"
            onload="renderMathInElement(document.body);"></script>
</head>
<body style="
background-color:transparent;
display: flex;
align-items: center;
justify-content: center;
">

<p id="ident" style="color: white"></p>

<script>
    function addBody(latexString) {
        katex.render(latexString, document.getElementById('ident'), {
            throwOnError: false
        });
    }
</script>
</body>
</html>

here, you wait for the addBody function to execute and then the LaTeX expression will be displayed.

The styling applied to the body tag is mostly for page arrangement, with the exception of background-color: transparent, which I've found to be needed to stop the flickering of the WebView when it's first created.

Now, for the Android Compose part, you will need to add the following dependency to your build.gradle:

implementation("com.google.accompanist:accompanist-webview:0.31.3-beta")

Then, you can create a wrapper component over the WebView, something simple like this should suffice:

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun LaTeXView(latex: String) {

    var webView: WebView? by remember { mutableStateOf(null) }

    val state = rememberWebViewState("file:///android_asset/latex_render.html")

    if (state.loadingState is LoadingState.Finished) {
        webView?.loadUrl("javascript:addBody('${latex}')")
    }
    com.google.accompanist.web.WebView(
        state = state,
        modifier = Modifier,
        onCreated = {
            it.settings.javaScriptEnabled = true
            webView = it
            it.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null)
            it.setBackgroundColor(0)
        }
    )
}

(inspired by the response to this KaTeXView issue, which unfortunately didn't work for me as-is, but it was close enough)

You should be able now to just render your latex like this:

LaTeXView(latex = "\\\\sin(x) \\\\cdot \\\\cos(y) \\\\cdot \\\\sin(x \\\\cdot y)")

And it should render something like this (minus the gradient background):

LaTeX rendered

Upvotes: 1

Related Questions