4

I'm interested in creating a custom android component that extends textview and shows the text inside of it as formatted. this is the code I wrote:

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

}

and in the test layout xml I have the following:

<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"/>

The string defined in strings.xml is:

<!-- testing -->
<string name="elad">elad <b> elad </b> elad</string>

This doesnt work, but the weird this is that I get the following exception thrown in 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)

Does anyone have any idea as to why I'm getting this error? Is what I'm trying to achieve even possible? thanks, e.

ekatz
  • 963
  • 3
  • 18
  • 38
  • TextView already supports some HTML elements, why do you want to reinvent the wheel? Just use: mTextSample.setText(Html.fromHtml(text)); – Pentium10 Mar 16 '11 at 19:34
  • Thanks for answer, I forgot to mention that it's imperative that the application is internationalizable, and that's why I want it to use resources from the strings.xml file for the specific language and prefer that the layouts are complete in the xml and not have to run the application to see the contents of the textview – ekatz Mar 16 '11 at 19:38

3 Answers3

4

Just try:

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

For dealing with strings.xml you need to escape certain characters as in this answer. The example given there is:

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

As Robby mentions, this is done for you automatically when you use the string editor.

Community
  • 1
  • 1
Matthew
  • 44,826
  • 10
  • 98
  • 87
  • 2
    and if you add the strings using the editor and don't just edit the file by hand it escapes for you. – Robby Pond Mar 16 '11 at 20:02
  • You can also use a <![CDATA[My Bold Text]]> as the content of the string element like: <![CDATA[My Bold Text]]> – Norman H Feb 21 '12 at 21:32
3

The TextView class already supports some basic html tags using Html.fromHtml so I don't think you need to create an HtmlTextView.

Internally the SDK use's TagSoup to parse the html (which is the missing class). I am assuming that you are getting that Eclipse exception when you try to view your layout in design mode. To have your custom view render correctly in the Eclipse view, there are some special things you need to do.

Either way I think you can use the basic TextView for your needs.

Update:

Strings in strings.xml can include html for use with the TextView.

Robby Pond
  • 73,164
  • 16
  • 126
  • 119
  • The basic textview does not show the text marked as bold in the strings.xml as bold on the design mode. actually, what happens for some strange reason, is that the string defined as : elad1 elad2 elad3 only shows elad1 elad2 on the design view and the elad2 is not bold... – ekatz Mar 16 '11 at 19:50
  • Are you worried more about how it looks in design mode vs how it looks on a real device? – Robby Pond Mar 16 '11 at 19:52
  • are u saying that on the real device it will work and the problem that I'm seeing is only on the design view? – ekatz Mar 16 '11 at 19:55
  • Yes. I have used html.fromHtml to render html in TextViews with both imgs and bold and it works. – Robby Pond Mar 16 '11 at 20:02
0

This works in Android Studio designer. Don't forget to clean and rebuild project as it will not work in designer immediately.

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())
    }
}
Renetik
  • 5,887
  • 1
  • 47
  • 66