こんにちは、GANMA!のAndroidアプリを担当しているゆのうえです。
Androidで丸い画像を表示するには色々な方法があります。 RoundedImageViewやPicassoなどのライブラリを利用して表示しているケースも多いのではないでしょうか。
単に丸くするだけならこのように
class RoundImageView : ImageView {
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
this(context, attrs, defStyleAttr, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) :
super(context, attrs, defStyleAttr, defStyleRes)
private val paint = Paint().apply { isAntiAlias = true }
private var viewWidth = 0
private var viewHeight = 0
override fun onDraw(canvas: Canvas?) {
val c = canvas ?: return
(drawable as? BitmapDrawable)?.bitmap?.let { image ->
val shader = BitmapShader(
Bitmap.createScaledBitmap(image, c.width, c.height, false),
Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP)
paint.shader = shader;
val circleCenter = viewWidth.toFloat() / 2;
canvas.drawCircle(circleCenter, circleCenter, circleCenter, paint);
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
viewWidth = MeasureSpec.getSize(widthMeasureSpec)
viewHeight = MeasureSpec.getSize(heightMeasureSpec)
}
}
簡単に実装することもできます。 ただ、このサンプルや先述のライブラリはelevationに対応していません。 丸画像でelevationを表現するにはどうすればいいのでしょう?
CardViewにImageViewをネストする
elevation付きで角が丸いViewというと、Support LibraryにCardViewがあります。 CardViewでImageViewをラップしてやると、こうなります。

これで一応はelevationに対応した丸画像を表現できるのですが、画像表示にいちいちCardViewを利用するのには違和感があります。
CardViewの実装を見る
では、CardViewはどのように角丸の影を表示しているのでしょう。 CardViewの実装を見てみると、最初に背景画像としてRoundRectDrawableというDrawableを設定しています。
final RoundRectDrawable background = new RoundRectDrawable(backgroundColor, radius); cardView.setCardBackground(background);
最近のAndroidは角を丸めたDrawableを背景にすると、そのDrawableの形状に合わせてelevationに対応した影がつくようになっているようです。 ちなみにApiバージョン20以前のCardViewではDrawable上に自力で影の描画を行っています。
どうやらこれを真似してImageViewの背景にしてやれば、elevation付き丸画像が実現できそうです。
完成
実際に作成したもので表示した画像がこちらです。

分かりにくいので拡大。

うっすらとですが、ちゃんと影が付いています。
コードは後ほどライブラリとして公開予定です。