在Android中显示好看的math公式

在Android平台上,科学和math从来没有得到足够的重视,这是令人遗憾的。 也许这是一个简单的问题,但我是一个总的花花公子JavaScript,所以我很难理解如何解决这个问题。

我想要做的很简单: 我只需要使用渲染math公式。 它可以是MathJax或JqMath或任何小而快的东西。 如果我必须在webview中做到这一点,我怎样才能在同一个webview中显示段落和格式化方程式的纯文本?

(任何人出来与其他方法明显工作,我会考虑作为解决scheme也)

我到底是怎么回事:

我开始使用MathJax将公式放到webview中( 我不知道是否有任何成功的jqMath用例?任何人都在意分享他们的经验? )我可以像独立的MathJax应用程序一样重现所有的function。 在该应用程序中,用户将string键入EditText字段,一旦用户按下button确认,MathJax将在Latex中呈现公式。

我不需要用户确认。 我认为这应该是更容易,因为没有用户交互,但不知何故方程永远不会显示。 我知道我必须错过一些东西,因为独立MathJax中的代码是用于用户input的。 我应该修改哪部分代码直接从string中提取方程式,例如\ sqrt {b ^ 2-4ac}? 这是webview的初始标题:

WebView w = (WebView) findViewById(R.id.webview); w.getSettings().setJavaScriptEnabled(true); w.getSettings().setBuiltInZoomControls(true); w.loadDataWithBaseURL("http://bar", "<script type='text/x-mathjax-config'>" +"MathJax.Hub.Config({ showMathMenu: false, " +"jax: ['input/TeX','output/HTML-CSS'], " +"extensions: ['tex2jax.js'], " +"TeX: { extensions: ['AMSmath.js','AMSsymbols.js'," +"'noErrors.js','noUndefined.js'] } " +"});</script>" +"<script type='text/javascript' " +"src='file:///android_asset/MathJax/MathJax.js'" +"></script><span id='math'></span>","text/html","utf-8",""); 

以下是当用户在inputedittext之后按下button时原始webview的加载方式:

 WebView w = (WebView) findViewById(R.id.webview); EditText e = (EditText) findViewById(R.id.edit); w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\[" +doubleEscapeTeX(e.getText().toString()) +"\\\\]';"); w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);"); private static String doubleEscapeTeX(String s) { String t=""; for (int i=0; i < s.length(); i++) { if (s.charAt(i) == '\'') t += '\\'; if (s.charAt(i) != '\n') t += s.charAt(i); if (s.charAt(i) == '\\') t += "\\"; } return t; } 

我试图用一个硬编码的stringreplace

 w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\[" +doubleEscapeTeX("sample string") +"\\\\]';"); 

但它不起作用,文本"sample string"甚至不会显示在web视图中。

[解决]请参阅乔的答案

为了详细说明他的答案,这是一个如何设置纯文本句子,然后以显示forms显示格式化的公式(全部在一个webview中)的例子:

replace上面的最后一行

 +"></script><span id='math'></span>","text/html","utf-8",""); 

 +"></script><span id='text'>This is plain text.</span> <span id='math'></span>", "text/html", "utf-8", ""); 

然后打电话

 w.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); if (!url.startsWith("http://bar")) return; w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\[" +doubleEscapeTeX("\\sqrt{b^2-4ac}") + "\\\\]';"); w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);"); } }); 

这将设置一个string这是普通的字体的纯文本和中心显示公式 FOO +酒吧 在webview中。

编辑(Android 4.4的问题)

从Android KitKat开始,您必须用evaluateJavascript(...)replace所有的loadUrl(...)行。 但是这仅适用于KitKat(API 19或更高版本),所以您需要先进行SDK版本检查。 例如:

 if (android.os.Build.VERSION.SDK_INT < 19) { w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);"); } else { w.evaluateJavascript("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);",null); } 

更新(由于MATHJAX 2.5)

由于存在文件夹更改,以前的代码将不会在最新版本的MathJax上工作。 此外,最小化本地MathJax大小的推荐方法是使用Grunt 。 可以在这里find用于减小MathJax大小的模板。

假设你已经成功地减小了MathJax的大小,并且假设输出了HTML-CSS,下面是一个可以加载MathJax的简单版本:

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final WebView w = (WebView) findViewById(R.id.webview); w.getSettings().setJavaScriptEnabled(true); w.getSettings().setBuiltInZoomControls(true); String Url = "</style>" + "<script type='text/x-mathjax-config'>" + " MathJax.Hub.Config({" + " showMathMenu: false," + " jax: ['input/TeX','output/HTML-CSS', 'output/CommonHTML']," + " extensions: ['tex2jax.js','MathMenu.js','MathZoom.js', 'CHTML-preview.js']," + " tex2jax: { inlineMath: [ ['$','$'] ], processEscapes: true }," + " TeX: {" + " extensions:['AMSmath.js','AMSsymbols.js'," + " 'noUndefined.js']" + " }" + " });" + "</script>" + "<script type='text/javascript' src='file:///android_asset/MathJax/MathJax.js'>" + "</script>" + "<p style=\"line-height:1.5; padding: 16 16\" align=\"justify\">" + "<span >"; // Demo display equation url += "This is a display equation: $$P=\frac{F}{A}$$"; url += "This is also an identical display equation with different format:\\[P=\\frac{F}{A}\\]"; // equations aligned at equal sign url += "You can also put aligned equations just like Latex:"; String align = "\\begin{aligned}" + "F\\; &= P \\times A \\\\ " + "&= 4000 \\times 0.2\\\\" + "&= 800\\; \\text{N}\\end{aligned}"; url += align; url += "This is an inline equation \\sqrt{b^2-4ac}."; // Finally, must enclose the brackets url += "</span></p>"; mWebView.loadDataWithBaseURL("http://bar", url, "text/html", "utf-8", ""); mWebView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); if (!url.startsWith("http://bar")) return; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { view.loadUrl(JAVASCRIPT); } else { view.evaluateJavascript(JAVASCRIPT, null); } } }); } 

不像Joes的回答,不需要分离文本或mathtypes,MathJax将相应地格式化它们。

但是,似乎有一个错误,就是KitKat设备中的webview无法呈现大写字母“A”。 任何知道方法的人都欢迎为此提供解决方法。

Solutions Collecting From Web of "在Android中显示好看的math公式"

如果我正确理解你的问题,似乎问题是由于MathJax库尚未完成加载(从loadDataWithBaseURL()调用)当您调用其他loadUrl()显示公式。 最简单的解决方法是等待onPageFinished()callback进行调用。

例如,下面的代码似乎在我的工作正常:

 /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final WebView w = (WebView) findViewById(R.id.webview); w.getSettings().setJavaScriptEnabled(true); w.getSettings().setBuiltInZoomControls(true); w.loadDataWithBaseURL("http://bar", "<script type='text/x-mathjax-config'>" + "MathJax.Hub.Config({ " + "showMathMenu: false, " + "jax: ['input/TeX','output/HTML-CSS'], " + "extensions: ['tex2jax.js'], " + "TeX: { extensions: ['AMSmath.js','AMSsymbols.js'," + "'noErrors.js','noUndefined.js'] } " + "});</script>" + "<script type='text/javascript' " + "src='file:///android_asset/MathJax/MathJax.js'" + "></script><span id='math'></span>", "text/html", "utf-8", ""); w.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); if (!url.startsWith("http://bar")) return; w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\[" + doubleEscapeTeX("sample string") + "\\\\]';"); w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);"); } }); } 

更新 :为了适应WebView中的额外输出,我build议将HTML元素添加到初始loadDataWithBaseURL()调用中。 所以对于上面的例子,而不是最后这一行:

  + "></script><span id='math'></span>", "text/html", "utf-8", ""); 

我们可以做如下的事情:

  + "></script><span id='text'>Formula:</span>" + "<span id='math'></span>", "text/html", "utf-8", ""); 

此外,如果您需要之后交互更新该部分,则可以使用我们用于“math”部分的相同机制,如下所示:

  w.loadUrl("javascript:document.getElementById('text').innerHTML='" + newText + "';"); 

如果您想要具有特定的样式/格式,您也可以使用其他HTML元素(而不是上面使用的<span> )。

而不是使用JavaScript和JavaScript库来呈现LaTeX客户端,为什么不做以下?

  1. 编写一个服务器端函数,它需要一些LaTeXstring并生成一个图像文件。 你可以用“开箱即用”的标准LaTeX命令行工具来做到这一点。 (这似乎是你有能力做的事,而且问题在于让渲染发生在客户端。)

  2. 在您的网站/服务上创build一个如下所示的端点:
    GET /latex?f={image format}&s={latex string}

  3. 在你的网页上,使用一个简单的HTML <img/>标签来渲染你的LaTeX。 例如:
    <img src="/latex?f=jpeg&s=f%40x%41%61x%942"/>
    将把f(x)=x^2方程表示为JPEG。

  4. (可选)为(f,s)对创build一个简单的服务器端caching,以便您只为该特定string(通过任何客户端)的第一个请求呈现特定的LaTeXstring。 作为第一个原型,你可以在服务器目录下有一个名为{hash(s)}.{f}文件,其中hash只是一些散列函数,如SHA1

这可以减轻你试图使一切工作与JavaScript的客户端。 而且,我会争辩(虽然有些人可能不同意),这是一个更清洁。 所有你发送给客户的是:

  1. HTML <img/>标签
  2. 浏览器parsingsrc属性时的实际图像内容

非常轻量级和快速!

“大写A”问题是Android WebView上MathJax的一个bug。 您可以使用调整的字体文件replace字体文件 。 使用TeX字体使用HTML-CSS输出时,此修补程序将起作用。 除了MathJax之外,你可以试试KaTeX ,它不那么漂亮但是速度更快。

其实我已经把它们打包成一个Android自定义的视图,看看MathView

晚了,但我觉得我有比Joe更好的解决scheme。 原来的问题问:

如何在段落中显示纯文本并在同一个webview中显示格式化的公式?

在最初的例子中,我们有:

 w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\[" +doubleEscapeTeX("sample string") +"\\\\]';"); 

你注意到了吗? \\\\[\\\\] ? 这四个反斜杠被LaTeX解释为唯一一个,而LaTeX中的\[\]\begin{equation}... \end{equation} 的简写,它产生了一个显示的math块。 如果我们想要在段落内有一段带有一些方程的文本,我们需要摆脱\\\\[并使用LaTeX命令\(\) 。 具有段落math和显示math的例子的代码将是:

 w.loadUrl("javascript:document.getElementById('math').innerHTML='" +doubleEscapeTeX( "This is a second degree equation \\( \\small ax^2+bx+c=0\\) and its " +"roots are \\[x=\\frac{-b\\pm \\sqrt{b^2-4ac}}{2a}. \\]" )+"';"); 

WebView变成: 在这里输入图像说明 笔记:

  • 我们只需要两个反斜杠而不是四个,这是因为我们在doubleEscapeTeX()并且这个函数复制了反斜杠。

  • 此外,math环境以外的文本使用HTML呈现(在<span id='math'>标记内)。

  • LaTeX字体比html字体大,所以在每个math环境中添加一个\\small将使它们大致相同。 在这里,我只添加了\\small命令到第一个方程来显示差异。

jqMath是一个类似于MathJax的JavaScript库,但是更小,更简单,速度更快。 如果你不需要所有的LaTeX,你可能会喜欢它。 它应该在Android上正常工作。

这只是一个build议,我不知道如果你使用MathJax可能会有什么错误或优点。

MathJax比jqMath更大更复杂, 大约慢了5倍

使用JSFIDDLE: http : //jsfiddle.net/sinhayash/gWWB5/1/

对于\sqrt{b^2-4ac}您可以使用以下代码: √(b^2-4ac)

您可以轻松地在JavaScript中使用string处理将string转换为jqMath格式并轻松显示它

您可以使用下面的代码轻松地在android中使用math公式。

 public void setView(String data,WebView w){ WebSettings webSettings = w.getSettings(); webSettings.setJavaScriptEnabled(true); String path="file:///android_asset/v/"; String js="<html><head>" + "<link rel='stylesheet' href='file:///android_asset/v/jqmath.css'>" + "<script src = 'file:///android_asset/v/jquery-3.0.0.min.js'></script>" + "<script src = 'file:///android_asset/v/jqmath-etc-0.4.3.min.js'></script>" + "<script src = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'></script>" + "</head><body>" + "<script>var s ='"+data+"';M.parseMath(s);document.write(s);</script> </body>"; w.loadDataWithBaseURL("", js, "text/html", "UTF-8", ""); }