LoginSignup
3

More than 3 years have passed since last update.

Android Pieから影を自由に描画しやすくなってた

Last updated at Posted at 2020-12-10

「年末でめっちゃ忙しいんだわ、3行で頼む」人向け

  • Android Pie (9.0) から hardware-accelerated な描画方法が若干増えた :clap:
  • 影の描画もお手軽にできるようになったので Neumorphism でもやってみましょ
  • サンプルコードはこちら android-neumorphism-demo

はじめに

冒頭でも書きましたが 公式ページ によると Android Pie から実はグラフィックス周りが若干強化されました。個人的に setShadowLayer がサポートされたところが大きいと感じていて、非マテリアルデザインで影を多用するアプリの実装がとても容易になりそうだ、と考えています。

Neumorphism の描画を簡単に実装してみた

最近ちらほら見かける Neumorphism が影を多用したUIということなのでまずは こちらのサイト の模倣を早速実装してみました。サンプルコードは冒頭にリンクを用意してありますのでよかったらみてみてください。

コードの解説とポイント

本当はボタンなどのコンポーネントも作りたかったのですが時間が確保できなかったため、最も基本的なViewのみ作りました。

NeumorphismView

上にも貼った uxdesign.cc のページ から画像を拝借 :pray:
Shape

上記表示を実現するためのパラメータとして下記を用意しています:

名前 説明
bgColor Int 上図の Main Background 、fillColor と同じに設定するのが基本そう
fillColor Int 上図の Shape Background
size Int neumorphism.io での Size パラメータ
shadowOffset Int neumorphism.io での Distance パラメータ
roundCornerRadius Int neumorphism.io での Radius パラメータ、 cornerRadius としたかったのですが XML のカスタム属性を設定しようとしたところ、名前がコンフリクトしたので round をつけました
shadowRadius Int neumorphism.io での Blur パラメータ
lightShadowColor Int 上図 Light Shadow の色
lightShadowColor Int 上図 Dark Shadow の色
borderColor Int 上図 Optional Border の色
lightShadowColor Int 上図 Light Shadow の色

これらを使って角丸矩形を描画するだけです:

override fun onDraw(canvas: Canvas?) {
    canvas ?: return
    canvas.drawRect(0f, 0f, width + 0f, height + 0f, backgroundPaint)

    val cornerRadius = roundCornerRadius + 0f
    canvas.drawRoundRect(rect, cornerRadius, cornerRadius, lightShadowPaint)
    canvas.drawRoundRect(rect, cornerRadius, cornerRadius, darkShadowPaint)
    canvas.drawRoundRect(rect, cornerRadius, cornerRadius, borderPaint)
}

影は setShadowLayer を使うだけですね:

private fun updateLightShadow() {
    lightShadowPaint.color = fillColor
    lightShadowPaint.setShadowLayer(shadowRadius + 0f, 0f -shadowOffset, 0f -shadowOffset, lightShadowColor)
    invalidate()
}

ViewModel と ViewBinding を活用できるようカスタム属性も定義したので、今回のように動的にパラメータを切り替えるのも簡単です:

<jp.cubenoy22.neumorphism.NeumorphismView
    android:id="@+id/neumorphismView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:size="@{ viewModel.size }"
    app:shadowOffset="@{ viewModel.distance }"
    app:shadowRadius="@{ viewModel.blur }"
    app:roundCornerRadius="@{ viewModel.radius }"
    />

パフォーマンスについて

RecyclerView で NeumorphismView を敷き詰めてみました:

程よいミドルレンジであろう Pixel 3a@Android 11 で試したところ、約30ぐらいのビューが存在している状態になりましたがスクロールしても特に負荷が上がった様子は見られませんでした :sparkles:

また軽く既存の Android 向け Neumorphism のライブラリの実装を探ってみたのですがOreo (8.1) 以下をサポートするためにビューごとに Bitmap へ描画して表示するという手法が取られていましたが、ビューの数が多いとメモリを多く消費しそうな予感がしました (*1, *2) 。最近はRAMをたくさん積んでるから大丈夫なのでしょうか。

ちなみにビットマップ上でのぼかし(blur)についてもいろいろやり方がありますが、今回 StackBlur という軽量(らしい)アルゴリズムを使ってCPUで演算しているライブラリがちょこちょこあるのに気づけたのも面白い発見でした:

最後に

もっと世の中に Android Pie 以降のデバイスが普及してリッチな描画ができたら幸せになれそうと感じました。終わり。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3