読者です 読者をやめる 読者になる 読者になる

woshidan's blog

そんなことよりコードにダイブ。

枠ぎりぎりまでImageViewやTextViewが表示される角丸のCardViewを作る

表題のことを仕事でしようと思ったら、かなりぐったりしたので、供養代わりにメモ。

辿りきれてないところもありますが...

内容

  • CardViewのサポートライブラリについて
    • 影の設定
    • 角丸の設定
  • ImageViewについて
    • onDraw()でマスクを抜く
    • setImageDrawableで角丸Bitmapを作る
  • TextViewなどについて
    • 角丸の背景用shapeを用意する

CardViewのサポートライブラリについて

一般的なViewの影を表現しようと思ったらそのために shape 要素を用意したり、画像を用意したりと大変です*1が、CardViewはサポートライブラリのものを使う場合、card_view:cardElevation 属性である程度やってくれます*2

このとき、注意するのは以下の3点です。

  • API21以上とそれ以下のバージョンで影の設定方法を揃えるために card_view:cardUseCompatPaddingtrueにする
    • たぶんこっちの方が指定が1つでいいので楽です
    • ただ、影の分marginが必要なので、最終的にちょうどいい間隔にするためにCardView要素のmarginを調整する必要があります
  • API20以下のバージョンでCardViewに枠線をつけないためcard_view:cardPreventCornerOverlapfalse にする
  • 影を表示するためには CardView 要素の周りにmargin を設定する必要がある*3

上記のようにCardViewを角丸に設定しても、影しか角丸にならない場合があります。

たとえばFrameLayout等を使ってその中にImageViewTextViewを置くと、しっかりこれらの子要素の角が出ます。なので、これら子要素も角丸にします。

ImageViewについて

ImageView についてはデフォルトで角を丸くする設定がありませんでした。まだ開発者になって一週間目ですし、とりあえず、下記の2つのアプローチを実装してみました。

  • onDraw()でマスクを抜く*4
  • setImageDrawableで角丸Bitmapを作る*5

onDraw()でマスクを抜く

API21で動作させたら、Canvas#saveLayer メソッドで渡すフラグをCanvas.ALL_FLAGにしないとAPI21だけ、マスク用画像の背景が黒色となって乗算されてしまっていたので、若干慌てました。

setImageDrawable.. の記事の方で述べられている通り、やや重いらしくてonDraw()の処理の間0.3sくらいマスク用画像が表示されています。幸いにしてマスク用画像(shape?)は何色でもよいみたいなので、それらしい色にしてごまかして進めています。

画像処理が速いライブラリを使ってonDraw()でやっていることを入れ替えたら速くなるかもしれないですが、まだ試せていません。

TextViewなどについて

角丸の指定をするcornersを子要素に持つshape要素を背景にします。shape要素については

ShapeDrawable | Android Developers

をご参照ください。

正直、苦戦していた理由とGeny Motionに見捨てられた低いバージョンのSDKAndroid Emulatorにインストールが速やかに行えないことと10mmくらい関係ある気がします。

低いバージョンとの互換性についてSuportLibrary で救われる部分と救われない部分がありますが、使った方が記述が簡単で済むので SupportLibrary だけは出るたびにチェックしよう、と思ったのでした。