Adsenseバナー

2015年3月19日木曜日

AndroidのTextViewにHTMLを表示するのは意外と厳しいお話

StickyText 1.4では、ノートのテキストをHTML形式で表示できるようにしました。
情報もそこそこあるし楽勝と思いきや、悪戦苦闘になったため、ハマった点を書いておきます。

主に Html#fromHtml() の話です。



グーグル先生に

「TextViewにHTMLを表示させるにはどうしたらいい?」

と聞くと、

android.text.Html#fromHtml()を使んだよ」

と教えてくれます。

でも、実はちょっと違います。
「TextViewに書式付きでテキストを表示させるなら、android.text.Html#fromHtml()を使うと手っ取り早い」
が正しいです。

どういうことかと言うと、Html#fromHtml()は制限が多すぎて、そこらにあるナマのHTMLを読み込ませても、ほとんどうまくいきません。

私が困ったことに限っても、ざっとこんな感じ。
  1. 処理できるタグの数が限られる
    特に、取り消し線の<strike><s>や、<span>、<ul><ol><li>のリスト関係、<table>関係がサポートされていません。
    またタグだけでなく、属性もものすごく限られてます。<font>のfaceとcolorのみ。
    今どき、表示に関するものはほとんどstyle属性であろうに、それは総スルーです。
  2. 処理されないタグは自分で扱えるには扱えるが、属性を見られない
    サポートされていないタグについては、それらのタグを処理するTagHandlerを自前で用意して引数に渡すと、一応処理できますが、そのTagHandler#handleTag内で要素の属性にアクセスする手段が提供されていません。
  3. 処理されるタグは一切触れられない
    <div>や<p>は独自ルールで改行に置き換えられ、それらが持つ属性に触れる機会は一切与えられません。
  4. 入れ子に対応できない
    文字の色は

    <font color="#ff0000">赤</font>

    とでもすれば、ちゃんとが反映されますが、例えば

    <font color="#ff0000">赤<font color="#0000ff">青<font color="#0000ff">緑</font></font>色</font>

    とすると、じゃなく、赤青緑色になります。

そんなわけで、シンプルなHTMLに使うか、どう表示させたいかがあって、自前でHTMLの文字列を作らないと使えないメソッドです。

まあ、それもそのはず。
普通HTMLを表示しようとしたら、TextViewじゃなくWebViewを使います。
だからTextViewでがんばる必要は無いのです。

しかし。ウィジェットになると話は別です。
ウィジェットにできるViewもまた制限があって、WebViewは使えません
なので、ホーム画面にテキストを表示しようとすると、やはりTextViewになります。
だからTextViewでがんばる必要があるのです。

で、どうがんばったかというと、ざっとこんな感じ。番号は上の番号と対応してます。

  1. Evernoteのコンテンツ(XHTMLをベースにしたENML形式のテキスト)をHtml#fromHtml()がなるべく読めるHTMLに変換。
  2. 変換したHTMLをHtml#fromHtml()で処理。このとき、自前のTagHandlerでサポート外のタグを処理。属性はリフレクションを使って強引に参照。
  3. <div>はEvernoteだと頻繁に使われて、改行されすぎになったりするから、<span>に置き換えて、自前のTagHandlerで扱えるように。
  4. 文字色の入れ子は、子の色が出て来たところで親の色をスタックに退避し、子の色が終ったら親の色を再開することで対応。

とまあ、なかなかの力技ですが、なんとかそれなりに表示できるようになりました。
こんなことは、やるもんじゃないです。





0 件のコメント:

コメントを投稿