使用webview處理富文字顯示
顯示富文字開始使用了RichText 的三方庫,之後發現對樣式支援度比較低,之後開始考慮使用webview來進行載入,通過重寫webview並增加js來處理進行圖片點選等操作的實現。
懶懶的。。。不想打那麼多字。。。直接複製程式碼吧。。。
用jsoup解析html。。。
依賴 org.jsoup:jsoup:1.11.3
呼叫方法:
tvHtml.imageClick((imageUrls, position) -> { //imageUrls是所有圖片地址的list ///position是點選位置 }) .urlClick(url -> { //url為連結跳轉地址 //返回true為自己處理跳轉,false為webview自行跳轉 return true; }) .imageLongClick(imageUrl->{ //imageUrl為長按圖片的地址 }) .setHtml(html);//html富文字的字串
在xml中加入
控制元件不可滑動。。。請加在可滑動控制元件內
<HtmlView android:id="@+id/tv_html" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" />
顯示富文字的webview類封裝
public class HtmlView extends WebView { private List<String> listImgSrc = new ArrayList<>(); public void setHtml(String html){ loadDataWithBaseURL("", html, "text/html", "UTF-8", ""); } public HtmlView(Context context) { super(context); init(context); } public HtmlView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public HtmlView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"}) private void init(Context context) { this.getSettings().setJavaScriptEnabled(true); this.getSettings().setDefaultTextEncodingName("UTF -8"); this.setHorizontalScrollBarEnabled(false);//水平不顯示 this.setVerticalScrollBarEnabled(false); //垂直不顯示 this.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); //取消滾動條白邊效果 this.getSettings().setUseWideViewPort(true); this.getSettings().setLoadWithOverviewMode(true); this.getSettings().setJavaScriptEnabled(true); this.getSettings().setDefaultTextEncodingName("UTF -8"); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) this.getSettings().setMixedContentMode(WebSettings .MIXED_CONTENT_ALWAYS_ALLOW);//注意安卓5.0以上的許可權 //載入js this.addJavascriptInterface(new MyJavascriptInterface(context), "imageListener"); //獲取 html this.addJavascriptInterface(new InJavaScriptLocalObj(), "local_obj"); this.setWebViewClient(new WebViewClient() { // 網頁跳轉 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url != null && !url.isEmpty() && onUrlClickListener != null) { return onUrlClickListener.urlClicked(url); } else return true; } // 網頁載入結束 @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // web 頁面載入完成,新增監聽圖片的點選 js 函式 HtmlView.this.setImageClickListner(); //解析 HTML HtmlView.this.parseHTML(view); } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { } }); this.setOnLongClickListener(v -> { setWebImageLongClickListener(v); return false; }); } /** * 響應長按點選事件 * @param v */ private void setWebImageLongClickListener(View v) { if (v instanceof WebView) { HitTestResult result = ((WebView) v).getHitTestResult(); if (result != null) { int type = result.getType(); if (type == HitTestResult.IMAGE_TYPE || type == HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { if(imageLongClickListener!=null){ imageLongClickListener.imageLongClicked(result.getExtra()); } } } } } /** * 解析 HTML 該方法在 setWebViewClient 的 onPageFinished 方法中進行呼叫 * * @param view */ private void parseHTML(WebView view) { view.loadUrl("javascript:window.local_obj.showSource('<head>'+" + "document.getElementsByTagName('html')[0].innerHTML+'</head>');"); } /** * 注入 js 函式監聽,這段 js 函式的功能就是,遍歷所有的圖片,並新增 onclick 函式,實現點選事件, * 函式的功能是在圖片點選的時候呼叫本地java介面並傳遞 url 過去 */ private void setImageClickListner() { // 這段js函式的功能就是,遍歷所有的img幾點,並新增onclick函式,函式的功能是在圖片點選的時候呼叫本地java介面並傳遞url過去 this.loadUrl("javascript:(function(){" + "var objs = document.getElementsByTagName(\"img\"); " + "for(var i=0;i<objs.length;i++)" + "{" + "objs[i].onclick=function()" + "{" + "window.imageListener.startShowImageActivity(this.src);" + "}" + "}" + "})()"); } // js 通訊介面,定義供 JavaScript 呼叫的互動介面 private class MyJavascriptInterface { private Context context; public MyJavascriptInterface(Context context) { this.context = context; } @android.webkit.JavascriptInterface public void startShowImageActivity(String url) { for (int i = 0; i < listImgSrc.size(); i++) { if (listImgSrc.get(i).equals(url)){ imageClickListener.imageClicked(listImgSrc, i); break; } } } } /** * 圖片點選回撥 * * @param imageClickListener 回撥 * @return RichTextConfigBuild */ public HtmlView imageClick(OnImageClickListener imageClickListener) { this.imageClickListener = imageClickListener; return this; } private OnImageClickListener imageClickListener; public interface OnImageClickListener { /** * 圖片被點選後的回撥方法 * * @param imageUrls 本篇富文字內容裡的全部圖片 * @param position點選處圖片在imageUrls中的位置 */ void imageClicked(List<String> imageUrls, int position); } /** * 圖片長按回調 * * @param imageLongClickListener 回撥 * @return RichTextConfigBuild */ public HtmlView imageLongClick(OnImageLongClickListener imageLongClickListener) { this.imageLongClickListener = imageLongClickListener; return this; } private OnImageLongClickListener imageLongClickListener; public interface OnImageLongClickListener { /** * 圖片被長按後的回撥方法 * * @param imageUrl 長按圖片地址 */ void imageLongClicked(String imageUrl); } /** * 連結點選回撥 * * @param onUrlClickListener 回撥 * @return RichTextConfigBuild */ public HtmlView urlClick(OnUrlClickListener onUrlClickListener) { this.onUrlClickListener = onUrlClickListener; return this; } private OnUrlClickListener onUrlClickListener; public interface OnUrlClickListener { /** * 超連結點選得回撥方法 * * @param url 點選得url * @return true:已處理,false:未處理(會進行預設處理) */ boolean urlClicked(String url); } private class InJavaScriptLocalObj { /** * 獲取要解析 WebView 載入對應的 Html 文字 * * @param html WebView 載入對應的 Html 文字 */ @android.webkit.JavascriptInterface public void showSource(String html) { //從 Html 檔案中提取頁面所有圖片對應的地址物件 listImgSrc = getImgSrc(html); } } private List<String> getImgSrc(String htmlStr) { Document document = Jsoup.parse(htmlStr); Elements images = document.select("img[src~=(?i)\\.(png|jpe?g|gif)]"); List<String> pics = new ArrayList<>(); for (Element image : images) { pics.add(image.attr("src")); } return pics; } //重寫onScrollChanged 方法 @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); scrollTo(0, 0); } }