前言
Tex公式及富文本常见就是使用Webview加载。
添加依赖
这个主要用于使用模板生成HTML
1 2 3
| dependencies { implementation 'com.x5dev:chunk-templates:3.6.2' }
|
添加模板
JS
assets/js 中添加相关JS
下载地址
https://github.com/KaTeX/KaTeX/releases
模板
模板文件要放在src/main/assets/themes文件夹下
注意文件必须以.chtml作为后缀
assets/themes 中添加 ztex.chtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Katex View</title> <link rel="stylesheet" type="text/css" href="file:///android_asset/katex/katex.min.css"> <style type="text/css"> body { margin : 0; padding : 0; font-size: {$fontSize}px !important; color: {$textColor} !important; -webkit-touch-callout: none!important; -webkit-user-select: none!important; user-select: none!important; } </style> </head> <body> {$content} <script type="text/javascript" src="file:///android_asset/katex/katex.min.js"></script> <script type="text/javascript" src="file:///android_asset/katex/contrib/auto-render.min.js"></script> <script> document.addEventListener("DOMContentLoaded", function() { renderMathInElement(document.body, { delimiters : [ {left: '$$', right: '$$', display: true}, {left: '\\[', right: '\\]', display: true}, {left: '$', right: '$', display: false}, {left: '\\(', right: '\\)', display: false} ] }); }); </script> </body> </html>
|
自定义组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
| import android.annotation.SuppressLint import android.content.Context import android.graphics.Color import android.util.AttributeSet import android.webkit.WebSettings import android.webkit.WebView import com.x5.template.Chunk import com.x5.template.Theme import com.x5.template.providers.AndroidTemplates
@SuppressLint("SetJavaScriptEnabled") public class ZTexView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : WebView(context, attrs, defStyleAttr) { val TAG = "ZTexView" private val TAG_CONTENT: String = "content" private val TAG_TEXT_COLOR: String = "textColor" private val TAG_FONT_SIZE: String = "fontSize" private val TAG_TP_NAME: String = "ztex" private var mText: String = "" private var mTextColor: Int = Color.BLACK private var mFontSize: Int = 16
init { settings.cacheMode = WebSettings.LOAD_NO_CACHE settings.displayZoomControls = false settings.builtInZoomControls = false settings.setSupportZoom(false) settings.useWideViewPort = true settings.loadWithOverviewMode = true
settings.javaScriptEnabled = true settings.allowFileAccess = true settings.domStorageEnabled = true settings.loadsImagesAutomatically = true settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
setBackgroundColor(Color.TRANSPARENT)
val mTypeArray = context.obtainStyledAttributes(attrs, R.styleable.ZTexView, 0, 0)
try { setTextColor( mTypeArray.getColor( R.styleable.ZTexView_textColor, Color.BLACK ) ) mFontSize = mTypeArray.getInt(R.styleable.ZTexView_fontSize, 16) val text: String? = mTypeArray.getString(R.styleable.ZTexView_text) text?.also { setText(it) } } finally { mTypeArray.recycle() } }
fun setText(text: String) { mText = text loadHTML() }
fun setTextColor(color: Int) { this.mTextColor = color loadHTML() }
fun setFontSize(size: Int) { this.mFontSize = size loadHTML() }
fun getText(): String { return mText }
private fun getChunk(): Chunk { return Theme(AndroidTemplates(context)).makeChunk(TAG_TP_NAME) }
private fun getHexColor(intColor: Int): String { return String.format("#%06X", 0xFFFFFF and intColor) }
private fun loadHTML() { val mChunk: Chunk = getChunk() mChunk.set(TAG_TEXT_COLOR, getHexColor(mTextColor)) mChunk.set(TAG_FONT_SIZE, mFontSize) mChunk.set(TAG_CONTENT, mText) this.loadDataWithBaseURL(null, mChunk.toString(), "text/html", "utf-8", "about:blank") } }
|
注意
下面的配置确保图片的正常加载
1 2 3 4 5
| settings.javaScriptEnabled = true settings.allowFileAccess = true settings.domStorageEnabled = true settings.loadsImagesAutomatically = true settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
|
Compose封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import android.content.Context import android.webkit.WebViewClient import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.ui.Modifier import androidx.compose.ui.viewinterop.AndroidView import cn.psvmc.ztexview.ZTexView
fun getTexView(context: Context): ZTexView { val texView = ZTexView(context).apply { setFontSize(16) webViewClient = WebViewClient() } texView.layoutParams = android.view.ViewGroup.LayoutParams( android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT ) return texView }
@Composable fun ZTexViewComp( htmlContent: String, modifier: Modifier = Modifier ) { var texView: ZTexView? = null AndroidView( modifier = modifier, factory = { context -> texView = getTexView(context) texView }, update = { texView -> texView.setText(htmlContent) } )
DisposableEffect(Unit) { onDispose { texView?.stopLoading() texView?.webViewClient = WebViewClient() texView?.destroy() } } }
|
注意
销毁时释放Webview资源,避免内存泄漏导致的加载异常。同时也能让网页中播放的音视频停止。
使用
1
| ZTexViewComp(ques.answer, modifier = Modifier.weight(1f))
|