当前位置: 首页 > 工具软件 > html-textview > 使用案例 >

2021-11-04总结安卓开发中HTMLTextView显示文本的流程

夏侯衡
2023-12-01

入职了一段时间了,每天基本上的工作是画ui,处理点击事件。背后数据的获取和显示到界面上的逻辑代码可以看也可以自己写一写不过我还没有自信能上库,所以就把前辈们写的代码加以总结,再自己实践。

一、使用自定义HtmlTextView

xml中的代码如下,用了一个放在com.common.view.htmltextview包中的名为HtmlTextView的TextView:

    <com.common.view.htmltextview.HtmlTextView
        android:id="@+id/html_text"
        android:layout_width="0dp"
        android:layout_height="0dp"/>

HtmlTextView的代码如下,嗯,是有copyright的,这么多方法:

/*
 * Copyright (C) 2013-2014 Dominik Schürmann <dominik@schuermann.eu>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.common.view.htmltextview;

import android.content.Context;
import android.text.Html;
import android.text.Spannable;
import android.text.Spanned;
import android.text.style.QuoteSpan;
import android.util.AttributeSet;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RawRes;


import com.byd.common.R;

import java.io.InputStream;
import java.util.Scanner;

public class HtmlTextView extends JellyBeanSpanFixTextView {

    public static final String TAG = "HtmlTextView";
    public static final boolean DEBUG = false;
    public int blockQuoteBackgroundColor = 0xffffff;//getResources().getColor(R.color.auto_color_white);
    public int blockQuoteStripColor = 0x000000;//getResources().getColor(R.color.auto_color_000000);
    public float blockQuoteStripWidth = 10F;
    public float blockQuoteGap = 20F;
    @Nullable
    private ClickableTableSpan clickableTableSpan;
    @Nullable
    private DrawTableLinkSpan drawTableLinkSpan;
    @Nullable
    private OnClickATagListener onClickATagListener;
    private float indent = 24.0f; // Default to 24px.

    private boolean removeTrailingWhiteSpace = true;
    private String[] removeTags = null;

    public HtmlTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public HtmlTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public HtmlTextView(Context context) {
        super(context);
    }

    /**
     * @see HtmlTextView#setHtml(int)
     */
    public void setHtml(@RawRes int resId) {
        setHtml(resId, null);
    }

    /**
     * @see HtmlTextView#setHtml(String)
     */
    public void setHtml(@NonNull String html) {
        setHtml(html, null);
    }

    /**
     * Loads HTML from a raw resource, i.e., a HTML file in res/raw/.
     * This allows translatable resource (e.g., res/raw-de/ for german).
     * The containing HTML is parsed to Android's Spannable format and then displayed.
     *
     * @param resId       for example: R.raw.help
     * @param imageGetter for fetching images. Possible ImageGetter provided by this library:
     *                    HtmlLocalImageGetter and HtmlRemoteImageGetter
     */
    public void setHtml(@RawRes int resId, @Nullable Html.ImageGetter imageGetter) {
        InputStream inputStreamText = getContext().getResources().openRawResource(resId);

        setHtml(convertStreamToString(inputStreamText), imageGetter);
    }

    /**
     * Parses String containing HTML to Android's Spannable format and displays it in this TextView.
     * Using the implementation of Html.ImageGetter provided.
     *
     * @param html        String containing HTML, for example: "<b>Hello world!</b>"
     * @param imageGetter for fetching images. Possible ImageGetter provided by this library:
     *                    HtmlLocalImageGetter and HtmlRemoteImageGetter
     */
    public void setHtml(@NonNull String html, @Nullable Html.ImageGetter imageGetter) {
        Spanned styledText = HtmlFormatter.formatHtml(
                html, imageGetter, clickableTableSpan, drawTableLinkSpan,
                new HtmlFormatter.TagClickListenerProvider() {
                    @Override
                    public OnClickATagListener provideTagClickListener() {
                        return onClickATagListener;
                    }
                }, indent, removeTrailingWhiteSpace,removeTags
        );
        replaceQuoteSpans(styledText);
        setText(styledText);

        // make links work
        setMovementMethod(LocalLinkMovementMethod.getInstance());
    }

    /**
     * The Html.fromHtml method has the behavior of adding extra whitespace at the bottom
     * of the parsed HTML displayed in for example a TextView. In order to remove this
     * whitespace call this method before setting the text with setHtml on this TextView.
     *
     * @param removeTrailingWhiteSpace true if the whitespace rendered at the bottom of a TextView
     *                                 after setting HTML should be removed.
     */
    public void setRemoveTrailingWhiteSpace(boolean removeTrailingWhiteSpace) {
        this.removeTrailingWhiteSpace = removeTrailingWhiteSpace;
    }

    public void setRemoveTags(String[] removeTags) {
        this.removeTags = removeTags;
    }

    public void setClickableTableSpan(@Nullable ClickableTableSpan clickableTableSpan) {
        this.clickableTableSpan = clickableTableSpan;
    }

    public void setDrawTableLinkSpan(@Nullable DrawTableLinkSpan drawTableLinkSpan) {
        this.drawTableLinkSpan = drawTableLinkSpan;
    }

    public void setOnClickATagListener(@Nullable OnClickATagListener onClickATagListener) {
        this.onClickATagListener = onClickATagListener;
    }

    /**
     * Add ability to increase list item spacing. Useful for configuring spacing based on device
     * screen size. This applies to ordered and unordered lists.
     *
     * @param px pixels to indent.
     */
    public void setListIndentPx(float px) {
        this.indent = px;
    }

    /**
     * http://stackoverflow.com/questions/309424/read-convert-an-inputstream-to-a-string
     */
    @NonNull
    private static String convertStreamToString(@NonNull InputStream is) {
        Scanner s = new Scanner(is).useDelimiter("\\A");
        return s.hasNext() ? s.next() : "";
    }

    private void replaceQuoteSpans(Spanned spanned) {

        Spannable spannable = (Spannable) spanned;
        QuoteSpan[] quoteSpans = spannable.getSpans(0, spannable.length() - 1, QuoteSpan.class);
        for (QuoteSpan quoteSpan : quoteSpans) {
            int start = spannable.getSpanStart(quoteSpan);
            int end = spannable.getSpanEnd(quoteSpan);
            int flags = spannable.getSpanFlags(quoteSpan);
            spannable.removeSpan(quoteSpan);
            spannable.setSpan(new DesignQuoteSpan(
                            blockQuoteBackgroundColor,
                            blockQuoteStripColor,
                            blockQuoteStripWidth,
                            blockQuoteGap),
                    start,
                    end,
                    flags);
        }
    }
}

二、在Fragment中显示HtmlTextView

创建一个Fragment类,在其中加载HtmlTextView,具体的方法是:

private fun initTextView() {
        val drawTableLinkSpan = DrawTableLinkSpan()
        drawTableLinkSpan.setTableLinkText("    ")
        binding.tvSettingAboutServicesContent.setDrawTableLinkSpan(drawTableLinkSpan)

        binding.tvSettingAboutServicesContent.setRemoveTags(HtmlTextUtil.tags)
        binding.tvSettingAboutServicesContent.setOnClickATagListener(object : OnClickATagListener {
            /**
             * Notifies of anchor tag click events.
             * @param widget - the [HtmlTextView] instance
             * @param spannedText - the string value of the text spanned
             * @param href - the url for the anchor tag
             * @return indicates whether the click event has been handled
             */
            override fun onClick(widget: View?, spannedText: String?, href: String?): Boolean {
                val uri = Uri.parse(href)
                val context = widget!!.context
                val intent = Intent(Intent.ACTION_VIEW, uri)
                intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.packageName)
                try {
                    context.startActivity(intent)
                } catch (e: ActivityNotFoundException) {
                    Log.w("URLSpan", "Actvity was not found for intent, $intent")
                }
                return true
            }

        })
    }

把这个initTextView()方法放到onViewCreated里面就行啦
好家伙,去年想写的东西现在才在草稿箱里发现没写完…还是没有养成写日记的好习惯呐

 类似资料: