AndroidでItemDecorationを使ってみた


目的

  • ItemDecorationを使ってみる。
    題材:カレンダー(Grid形式)
       下記で作成したカレンダーを改造し、月毎のヘッダをItemDecorationで実現する。

ポイント

RecyclerView.ItemDecorationでできることは、大きく2つ。
- getItemOffsets
 itemの位置を移動する
- onDraw、onDrawOver
 itemの下または上に描画を行う

実装内容

  1. getItemOffsetsで、「月の一週目」の表示位置を100下方に移動します。
  2. onDrawOverで、1で移動した部分にヘッダーの背景とテキスト(月、西暦)を描画します。
DateItemDecoration.kt
class DateItemDecoration: RecyclerView.ItemDecoration() {
    companion object {
        private const val HEADER_HEIGHT = 100
        private val headerBackGroundPaint = Paint().apply {
            color = Color.GRAY
            alpha = 200
        }
        private val headerTextPaint = Paint().apply {
            textSize = 65f
            color = Color.WHITE
        }
    }

    override fun getItemOffsets(
            outRect: Rect,
            view: View,
            parent: RecyclerView,
            state: RecyclerView.State
    ) {
        super.getItemOffsets(outRect, view, parent, state)
        if ((parent.getChildViewHolder(view) as DateAdapter.DateAdapterHolder).isFirstWeek) {
            outRect.top = HEADER_HEIGHT
        } else {
            outRect.top = 0
        }
    }

    override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDrawOver(c, parent, state)
        val size = state.itemCount
        for (i in 0 until size step 7) {
            drawHeader(parent, c, i, i + 7)
        }
    }

    private fun drawHeader(parent: RecyclerView, c: Canvas, prev: Int, now: Int) {
        val prevView = parent.getChildAt(prev)
        val prevHolder =
                if (prevView == null) {
                    return
                } else {
                    parent.getChildViewHolder(prevView) as DateAdapter.DateAdapterHolder
                }
        if (prevHolder.isFirstWeek) {
            c.drawRect(
                    0f,
                    prevView.y - HEADER_HEIGHT,
                    parent.width.toFloat(),
                    prevView.y,
                    headerBackGroundPaint
            )
            c.drawText(
                    "${prevHolder.month} ${prevHolder.year}",
                    0f,
                    prevView.y,
                    headerTextPaint
            )
        }
    }
}

コードの詳細は下記参照:
https://github.com/yoshihiro-kato/android-samples/tree/b8bb2489ffb113de50df947400a640fc357a0801/KotlinSampleApplication