본문 바로가기
Project/안드로이드 프로젝트(RandomColorChart)

Android Studio, Kotlin] 1. SpannedGridLayout (OpenSource)

by 김마리님 2021. 1. 7.

랜덤 컬러차트는 몬드리안의 「빨강 파랑 노랑의 구성」 처럼 다양한 사각형의 크기를 입히고 싶었다.

 

 

그러나 이런 디자인은 기존의 리스트뷰나 리사이클러뷰로는 구현할 수 없다. 

그래서 이런 레이아웃을 찾다가 SpannedGridLayout을 찾았다. 이제 사용할건데... 이걸 도저히 구현할 용기가 안나서 ㅠ (주니어 개발자) 오픈소스를 사용하기로 했다.

 

github.com/Arasthel/SpannedGridLayoutManager

 

Arasthel/SpannedGridLayoutManager

Android RecyclerView.LayoutManager that resizes and reorders views based on SpanSize - Arasthel/SpannedGridLayoutManager

github.com

이 소스의 장점은.. 정말... 진짜 구현도 쉽고 디자인도 예쁘게 빠진다. 

 

결과물부터 보이면 이렇다..

 

정말.. 원하는 사각형으로 모양이 잡히는데, 단점도 존재한다.

이 레이아웃같은 경우는 빈 칸을 가능하다면 무조건 채운다~ 라는 느낌의 오픈소스이기 때문에 순서를 중요시 한다면 이 오픈소스를 사용하지 않기를 권장한다.

여기에서도 그런데,

 

        MainColor(6, "Flame", 239, 86, 45),
        MainColor(7, "Pink Yarrow", 209, 48, 118),
        MainColor(8, "Niagara", 85, 135, 162),
        MainColor(9, "Kale", 92, 113, 72),

더미데이터들과 비교해봤을 때 레이아웃이 다음과 같이 잡히고, 이 순서는 변경할 수 없다. 따라서 순서를 중요시 한다면 사용을 피하자.

 

 

늘 그렇지만 깃허브의 오픈소스를 처음 사용할때는 반드시 README를 숙지해야한다. 

먼저 의존성을 부여한다. 모듈 수준의 gradle에서 

 

    implementation 'com.arasthel:spannedgridlayoutmanager:3.0.2'

 

를 부여한다. 동기화가 끝나면, viewHolder에 들어갈 view를 만든다.

 

 

- view_holder_color_chart.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <View
        android:id="@+id/viewColor"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>

 

이제 이 뷰를 등록할 뷰홀더와 어댑터를 만든다. 여기까지는 그냥.. 일반 리사이클러뷰와 동일하다.

 

 

-MainColorViewHolder.kt

package com.mary.kotlinprojectstudy.main.adapter.item


import android.graphics.Color
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.mary.kotlinprojectstudy.R
import com.mary.kotlinprojectstudy.bean.MainColor

class MainColorViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

    var view : View = itemView
    var viewColor : View = view.findViewById(R.id.viewColor)

    fun updateView(item : MainColor) {

        viewColor.setBackgroundColor(Color.rgb(item.red,item.green,item.blue))
    }

}

 

- MainColorAdapter.kt

package com.mary.kotlinprojectstudy.main.adapter

import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.mary.kotlinprojectstudy.R
import com.mary.kotlinprojectstudy.bean.MainColor
import com.mary.kotlinprojectstudy.main.adapter.item.MainColorViewHolder

class MainColorAdapter : RecyclerView.Adapter<MainColorViewHolder>() {

    var list : List<MainColor> = listOf()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainColorViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.view_holder_color_chart, parent, false)
        return MainColorViewHolder(view)
    }

    override fun onBindViewHolder(holder: MainColorViewHolder, position: Int) {
        val item = list[position]

        holder.apply {
            updateView(item)
        }

    }

    override fun getItemCount(): Int {
        Log.d(TAG, "getItemCount: " + list.size)
        return list.size
    }

    companion object {
        private const val TAG = "MainColorAdapter"
    }
}

 

마지막으로 이걸 recyclerView에 붙여주기만 하면 된다.

 

- MainActivity.kt

package com.mary.kotlinprojectstudy.main

import android.os.Bundle
import android.widget.Space
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.mary.kotlinprojectstudy.R
import com.mary.kotlinprojectstudy.bean.MainColor
import com.mary.kotlinprojectstudy.main.adapter.MainColorAdapter
import com.mary.kotlinprojectstudy.ui.SpanSize
import com.mary.kotlinprojectstudy.ui.SpannedGridLayoutManager
import com.mary.kotlinprojectstudy.ui.exception.SpaceItemDecorator

class MainActivity : AppCompatActivity() {

    lateinit var mainColorAdapter: MainColorAdapter

    val recyclerView: RecyclerView by lazy { findViewById(R.id.recyclerView) }

    private val list: List<MainColor> = listOf(
        MainColor(1, "Primrose Yellow", 246, 210, 88),
        MainColor(2, "Pale Dogwood", 239, 206, 197),
        MainColor(3, "Hazelnut", 209, 175, 148),
        MainColor(4, "Island Paradise", 151, 213, 224),
        MainColor(5, "Greenery", 136, 177, 75),
        MainColor(6, "Flame", 239, 86, 45),
        MainColor(7, "Pink Yarrow", 209, 48, 118),
        MainColor(8, "Niagara", 85, 135, 162),
        MainColor(9, "Kale", 92, 113, 72),
        MainColor(10, "Lapis Blue", 12, 76, 138)
    )


...

    private fun initRecyclerView() {

        mainColorAdapter = MainColorAdapter()
        mainColorAdapter.list = list

        val layoutManager = SpannedGridLayoutManager(
            orientation = SpannedGridLayoutManager.Orientation.VERTICAL,
            spans = 6
        )
        
        layoutManager.itemOrderIsStable = true
        recyclerView.addItemDecoration(SpaceItemDecorator(left = 5, top = 5, right = 5, bottom = 5))

        recyclerView.layoutManager = layoutManager
        recyclerView.adapter = mainColorAdapter

        layoutManager.spanSizeLookup = SpannedGridLayoutManager.SpanSizeLookup { position ->

            when (position % 9) {
                0 ,6 -> {
                    SpanSize(4, 4)
                }

                3 -> {
                    SpanSize(2, 1)
                }

                4 -> {
                    SpanSize(4, 1)
                }

                7, 8 -> {
                    SpanSize(1, 2)
                }

                else -> {
                    SpanSize(2, 2)
                }
            }


        }


    }


...

}

 

val layoutManager = SpannedGridLayoutManager(
orientation = SpannedGridLayoutManager.Orientation.VERTICAL,
spans = 6
)

 

레이아웃 매니저를 정의하면서 호출할때, 가로인지 세로인지 방향을 설정하고(가로영역은 Horizantal), 고정영역을 몇 개의 span으로 나눌 지 결정한다(수직정렬이면 가로 고정, 수평졍렬이면 세로 고정)

 

recyclerView.addItemDecoration(SpaceItemDecorator(left = 5, top = 5, right = 5, bottom = 5))

이건 요소 사이의 간격을 결정한다.

 

layoutManager.spanSizeLookup = SpannedGridLayoutManager.SpanSizeLookup { position ->

 

으로 각 포지션 별 span의 크기를 결정할 수 있다. 여기서는 9개의 요소가 반복적으로 나타나므로 포지션을 9개로 나누어 각 요소마다의 크기를 부여한다.

반응형