Drawable)を使うと文字領域の上下左右に一つずつDrawableを置くことができるが、文章の中に画像を置いたり、例えば右の領域にDrawableを二つ並べて置くということはできない。そんな時の代替手段の一つにImageSpanがある。HTMLのimgタグに相当するものだろうか。[鍵マーク]のように文字と画像とを一列に並べようとしていたところ、画像の底辺をどこに合わせるか指定する引数にALIGN_BOTTOMを選ぶ(デフォルト)と上の方に不思議な隙間ができてしまったのでどんな処理をしているのか見てみることにした。この情報にならってDynamicDrawableSpan#draw()をオーバライドして解決を試みようとしたのだが、問題はどうもDynamicDrawableSpan#getSize()の方にあるのではないかという気がした。その理由を次から説明する。Developersをみると引数についての説明がある。ここで重要なのは次の三つ。/frameworks/base/core/java/android/text/style/ReplacementSpan.javagetSize()の戻り値はintなのだが、これはdraw()で描こうとするものの幅がどれだけかという意味。getDrawable().getBounds().rightを返せばよいだけのはずなのだが、ついでに引数であるPaint.FontMetricsIntの中身を書き換えている。具体的には次に挙げる変数の値を書き換えているのだが、これはdraw()で描こうとするものの高さ方向のデータになる。グリフの中で最も足が長い文字の、ベースラインより下側の距離(正の数)ちなみにこの説明は、Paint.FontMetricsの方にしか書いてない。topやascentが負の数である理由は、スクリーンの座標系が上から下に向かって大きくなっているためらしい。ここで設定した値に応じてdraw()のtopやyやbottomの値が決まるようである。getSize()の元の処理は、ベースラインから上側の距離をDrawableの高さと等しくして、ベースラインから下の距離を0に設定している。その上でdraw()ではbottomにDrawableの底辺を揃えて、ALIGN_BASELINEの時にはさらにベースラインからdescentの分だけ上に引きあげようという計算をしている。ベースラインの上側にDrawableの高さ分のスペースを確保しているのに、それよりさらに低いbottomの位置に底辺を合わせているので、ALIGN_BOTTOMの時にはbottomの分だけDrawableの上に隙間ができるということである。その行の他の文字がベースラインの下側を使っているために、getSize()で指定したbottom=0が却下されてしまうのではないかと思われる。上の隙間をなくすには画像の領域をベースラインの上側にのみ確保しようとしているのがそもそもおかしいのではないか。したいのはALIGN_BASELINEを指定した時だけのはず。単純に次のようにしてみた。ポイントはDrawableのベースラインをどこにするか。getCachedDrawable()はprivateメソッドなので再定義する必要がある。spacingを1.5に設定すると画像が下付き文字のようになってしまうという現象が確認されているが、これはdraw()の引数であるbottomが行間の高さも含んでいるためではないかと考えられる。Paint.FontMetricsIntは行間の高さをleadingという変数名で持っている。このleadingの分だけ上に移動させてやることで意図した通りに表示できるのではないかと思われる。paint.getFontMetricsInt().leading;にするという感じ。これは手元では確認していないので間違っているかもしれない。中央揃えができたらいいなと思っている。GitHubに上がっており、そのうちマージされる予定。パッチ書いてAOSPに取り込まれるのが一番いいんだと思うんだけどいろんなケースに対応できるかどうかはちょっと自信がない。チャレンジしてみるのもいいのかな。読者になるリンクはてなブログブログをはじめる(無料)お知らせ検索はてなブログをはじめよう!akihito104さんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。