• スポンサードリンク

TextureViewに枠を付けた〜い(^o^)/

Android

事の発端は…

今更ながら、AndroidでViewの外枠を付ける方法をグルグル先生に聞いてみました。
Google Group:Android Developers:Border around a LinearLayout / rounded edges
SE奮闘記【Android開発】スタイルにborderがないけど枠線を表示したい
yokkongの日記:TextViewに枠線を付ける&背景色を変更する
とかとかヒットしました。元ネタは一番上みたい。

XMLで四角のDrawableを作って枠線を指定して、枠線を付けたいViewのbackground属性(Javaから指定するならばView#setBackgroundResource)にそのDrawableを指定すればいいらしいです。Drawable矩形の中は塗っても塗らなくてもOKみたい・・・と言うか必要なければ塗らない方が描画負荷が少しでも減るかもですね。

おぉ〜簡単じゃんってことで、とりあえず下のようにコピペして試してみました(border.xml)

後は、レイアウトファイル内で、Viewのandroid:background属性に上のborder.xmlを指定するだけ。普通のView、例えばTextViewとかImageView, EditTextはもちろん、LinearLayoutとかのViewGroupにも枠を表示することが出来ました。SurfaceViewでもGLSurfaceViewでも出来ます。

でもでもでもでもそんなの関係ねー

これで\(^o^)/ってなればよかったんだけど、肝心のTextureViewには表示できません(泣)。
Eclipseのレイアウトエディタでは一見外枠が付いているように見えるんだけどなぁ(´・ω・`)…
色々試してみたんだけど、TextureViewにはbackgroundを指定しても無駄って感じです。

そもそも上のXMLで何をしているかと言うと、枠線(stroke)を持つ四角のdrawableを生成して、そのままだと上に表示されるViewに全面覆われてしまって見えなくなるのをpaddingを指定してViewを一回り小さくすることで、まるでViewに枠が付いているかのように見えるってトリックですよね。
ところが、TextureViewではbackgroundもpaddingとかもまるっきり無視して常にView全面に描画するようです。なのでいくら背景にdrawableを指定しようとも上に完全に覆いかぶさって見えないんですよね。またまたがっかり。

むむむっ、あっ、paddingの代わりにTextureViewを一回り小さく表示すればいいんだ(^o^)/っと思ってTextureView#setScaleX/setScaleYで0.9fを指定して1割小さくしてみました。すると確かに表示内容は小さくなったんだけど・・・ご丁寧に空いたところは黒で塗りつぶしてくださいました。
SDKのTextureViewのソース、AOSPのTextureViewのJNI側の実装(android_view_TextureView.cpp)も追っかけてみましたが、更にもう一層以上下のレベル(GLConsumerかな?)で全面に描画しているみたいでした。
我が道を行くTextureView様です(´・ω・`)

結論?

ということで結論、「TextureViewに枠線は付けれない」、です。backgroundを指定する方法ではだめってことですけどね。(-_-;)
えっこの結論じゃだめ?いやいやそれじゃ話にならんでしょうってことで、ごまかす方法を考えてみました。

  1. 枠を付けたいTextuewViewと同じ大きさの透明な別のViewを上に載せてそのViewに枠を描画
  2. TextureViewをViewGroup(LinearLayoutとかRelativeLayoutとか)に入れてそれに枠を付ける
  3. TextureViewの表示内容として自前で枠線を描く
1.上に別のViewを被せる

TextureViewをRelativeLayoutに入れといて、上に別のViewを載せて、上に載せたViewで外枠を表示するようにします。例えば下のような感じ。

この例ではImageViewを使ってみました。ImageViewだとandroid:srcに外枠表示用のXMLで生成したdrawableを指定できます。
大事なのは、上のXMLレイアウトファイルのように、RelativeLayoutに入れて、layout_alignTop, layout_alignBottom, layout_alignLeft, layout_alignRightにTextureViewを指定することですね。こうすれば自動的にTextureViewの大きさ・位置に合わせてImageViewの大きさ・位置を変更してくれます。
これが一番簡単かなぁ。\(^o^)/
2014/06/15追記:このままだとSC-06D(Android4.1.2)ではImageViewが透過せず下のTextureViewが見えませんでした。機種依存なのか、GPUによるのか、GPUのドライバによるのか、Androidのバージョンなのか・・・は不明ですが、border.xmlを次のように変更するとOKになりました。

結局のところsolid項目未指定の場合の挙動が違う時が有るみたいなので、透過指定しないとダメみたいです。

または

のどちらでも大丈夫でした。
あ、そうそう、@color/GRAYは#ff808080, @color/TRANSPARENTは#00000000です。
もしかすると、@nullを指定するほうが機種依存が少ないのかなぁ?
いや〜自分でも一日近く悩んでしまいました。プログラム的には全て正常に走っているのに画面だけ出ない機種があるって・・・(-_-;)

2.TextureViewの親ViewGroupに枠を付ける

これは、TextureViewが親ViewGroup全体を専有する場合のみ可能です。もしTextureViewが親ViewGroupの一部分しか占めていないのであれば、TextureViewを一旦別のViewGroup内に入れる必要があります。
例えばこんな感じ。

TextureViewが親ViewGroup全面に無いのであればViewの階層が1層増えてしまうのが欠点。

3.TextureViewの表示内容として自前で枠線を描く

これはもう、線でも点線でも花飾りでも月桂樹でもなんでも好きに描画してください。
OpenGLだと外枠を引くのは意外と面倒だったりするけど。

まとめ

どれでもお好きなのをどうぞ(^_^)。RelativeLayout内に入れないとダメですが、特に問題なければ1の方法がお勧めなのかなぁ(1のようにViewの数が増えるよりも、2のようにViewの階層が増える方が処理が重くなるから)
ちなみに、他の種類のViewやViewGroupでも使えますが、TextureView以外ではあえて使う必要もないトリックですね(^_^;)
そうそう、上にImageViewを被せてても(ImageViewのonTouchEventとかで)余計なことをしなければタッチイベントとかは普通に下のTextureViewへ行きますからね。

相変わらずピンポイントなネタを記事にしてるなぁ〜(^_^;)
と言うことでおしまい。お疲れ様でした。

« »

  • スポンサードリンク

%d人のブロガーが「いいね」をつけました。