安卓:Html TextView - 可行吗?

4
我对创建一个自定义的 Android 组件很感兴趣,它可以扩展 TextView 并且以格式化的形式显示文本内容。以下是我编写的代码:

/** * TODO */

import android.content.Context;
import android.graphics.Canvas;
import android.text.Html;
import android.util.AttributeSet;
import android.widget.TextView;

public class HtmlTextView extends TextView {

    private static final String tag = "HtmlTextView";

    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);
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.widget.TextView#onDraw(android.graphics.Canvas)
     */
    @Override
    protected void onDraw(Canvas canvas) {


                setText(Html.fromHtml((String) getText()));


        super.onDraw(canvas);
    }

}

在测试布局xml中,我有以下内容:
<com.package.ui.tools.HtmlTextView 
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="@string/elad"
  android:textSize="28dip"
  android:padding="10dip"
  android:gravity="center"/>

在strings.xml文件中定义的字符串是:
<!-- testing -->
<string name="elad">elad <b> elad </b> elad</string>

这个不起作用,但奇怪的是我在eclipse中得到了以下异常:

java.lang.NoClassDefFoundError: org/ccil/cowan/tagsoup/Parser
at android.text.Html.fromHtml(Html.java:125)
at android.text.Html.fromHtml(Html.java:102)
at com.package.ui.tools.HtmlTextView.onDraw(HtmlTextView.java:39)
at android.view.View.draw(View.java:6740)
at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.View.draw(View.java:6743)
at android.widget.FrameLayout.draw(FrameLayout.java:352)
at com.android.layoutlib.bridge.Bridge.computeLayout(Bridge.java:452)
at com.android.ide.common.rendering.LayoutLibrary.createLegacySession(LayoutLibrary.java:404)
at com.android.ide.common.rendering.LayoutLibrary.createSession(LayoutLibrary.java:285)
at com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart.renderWithBridge(GraphicalEditorPart.java:1506)
at com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart.renderWithBridge(GraphicalEditorPart.java:1312)
at com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart.recomputeLayout(GraphicalEditorPart.java:1043)
at com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart.activated(GraphicalEditorPart.java:870)
at com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor.partActivated(LayoutEditor.java:378)
at com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor.partBroughtToTop(LayoutEditor.java:387)
at org.eclipse.ui.internal.PartListenerList$2.run(PartListenerList.java:87)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.core.runtime.Platform.run(Platform.java:888)
at org.eclipse.ui.internal.PartListenerList.fireEvent(PartListenerList.java:57)
at org.eclipse.ui.internal.PartListenerList.firePartBroughtToTop(PartListenerList.java:85)
at org.eclipse.ui.internal.PartService.firePartBroughtToTop(PartService.java:208)
at org.eclipse.ui.internal.WorkbenchPagePartList.firePartBroughtToTop(WorkbenchPagePartList.java:76)
at org.eclipse.ui.internal.WorkbenchPagePartList.fireActiveEditorChanged(WorkbenchPagePartList.java:52)
at org.eclipse.ui.internal.PartList.setActiveEditor(PartList.java:162)
at org.eclipse.ui.internal.WorkbenchPage.makeActiveEditor(WorkbenchPage.java:1281)
at org.eclipse.ui.internal.WorkbenchPage.setActivePart(WorkbenchPage.java:3530)
at org.eclipse.ui.internal.WorkbenchPage.requestActivation(WorkbenchPage.java:3077)
at org.eclipse.ui.internal.PartPane.requestActivation(PartPane.java:279)
at org.eclipse.ui.internal.EditorPane.requestActivation(EditorPane.java:98)
at org.eclipse.ui.internal.PartPane.setFocus(PartPane.java:325)
at org.eclipse.ui.internal.EditorPane.setFocus(EditorPane.java:127)
at org.eclipse.ui.internal.PartStack.presentationSelectionChanged(PartStack.java:844)
at org.eclipse.ui.internal.PartStack.access$1(PartStack.java:827)
at org.eclipse.ui.internal.PartStack$1.selectPart(PartStack.java:137)
at org.eclipse.ui.internal.presentations.util.TabbedStackPresentation$1.handleEvent(TabbedStackPresentation.java:133)
at org.eclipse.ui.internal.presentations.util.AbstractTabFolder.fireEvent(AbstractTabFolder.java:269)
at org.eclipse.ui.internal.presentations.util.AbstractTabFolder.fireEvent(AbstractTabFolder.java:278)
at org.eclipse.ui.internal.presentations.defaultpresentation.DefaultTabFolder.access$1(DefaultTabFolder.java:1)
at org.eclipse.ui.internal.presentations.defaultpresentation.DefaultTabFolder$2.handleEvent(DefaultTabFolder.java:88)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1053)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1077)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1062)
at org.eclipse.swt.widgets.Widget.notifyListeners(Widget.java:774)
at org.eclipse.swt.custom.CTabFolder.setSelection(CTabFolder.java:2743)
at org.eclipse.swt.custom.CTabFolder.onMouse(CTabFolder.java:1429)
at org.eclipse.swt.custom.CTabFolder$1.handleEvent(CTabFolder.java:257)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1053)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4066)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3657)
at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2640)
at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2604)
at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2438)
at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:671)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:664)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:115)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:369)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:619)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:574)
at org.eclipse.equinox.launcher.Main.run(Main.java:1407)

有没有人知道我为什么会收到这个错误?我尝试的目标是否可行?谢谢,e。


TextView已经支持一些HTML元素了,为什么要重复造轮子呢?只需使用:mTextSample.setText(Html.fromHtml(text)); - Pentium10
谢谢您的回答,我忘了提到这个应用程序必须是国际化的,这就是为什么我希望它使用来自strings.xml文件的资源来支持特定语言,并且更喜欢布局在xml中完整而不必运行应用程序以查看textview内容。 - ekatz
3个回答

4

只需尝试:

normalTextView.setText(Html.fromHtml("<bold>Hello World!</bold>"));

处理 strings.xml 时需要转义某些字符,就像这个答案中所述。那里给出的示例是:

<resources>
    <string name="somestring">
        &lt;B&gt;Title&lt;/B&gt;&lt;BR/&gt;
        Content
    </string>
</resources>

正如Robby所提到的,当您使用字符串编辑器时,这将自动为您完成。

2
如果您使用编辑器添加字符串而不是手动编辑文件,则会自动进行转义。 - Robby Pond
您还可以将<![CDATA[<b>My Bold Text</b>]]>用作字符串元素的内容,例如:<string name="myBoldText"><![CDATA[<b>My Bold Text</b>]]></string> - Norman H

3
TextView类已经支持使用Html.fromHtml的一些基本html标签,因此我认为您不需要创建一个HtmlTextView。
在SDK内部,使用TagSoup解析html(这是缺失的类)。我假设您在尝试在设计模式下查看布局时遇到了Eclipse异常。为了使您的自定义视图在Eclipse视图中正确呈现,您需要做一些特殊的事情。
无论如何,我认为您可以使用基本的TextView来满足您的需求。
更新:
strings.xml中的字符串可以包含用于TextView的html。

基本的TextView在设计模式下无法将strings.xml中标记为粗体的文本显示为粗体。 实际上,由于某种奇怪的原因,定义为: <string name="elad">elad1 <b> elad2 </b> elad3</string> 在设计视图中只显示elad1 elad2,并且elad2并不是粗体... - ekatz
你更担心它在设计模式下的外观还是在真实设备上的外观? - Robby Pond
你是在说实际设备上它会起作用,而我看到的问题只出现在设计视图上吗? - ekatz
是的。我已经使用了html.fromHtml在TextView中呈现带有图片和粗体的HTML,它可以工作。 - Robby Pond

0

这在Android Studio设计器中有效。不要忘记清理和重建项目,因为它不会立即在设计器中生效。

class HtmlTextView : AppCompatTextView {
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        setHtml(text)
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int)
            : super(context, attrs, defStyleAttr) {
        setHtml(text)
    }

    fun setHtml(html: CharSequence) {
        @Suppress("DEPRECATION")
        text = Html.fromHtml(html.toString())
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接