Logo
Published on
·7 min read

Color Picker(ambilwarna) 라이브러리 사용하여 색상 변경(안드로이드)

개요

sosone 프로젝트의 스마트 탁상 시계(안드로이드)에 배경색과 텍스트색을 사용자가 직접 지정하는 기능을 추가하였습니다.

색상 선택은 Android Color Picker(ambilwarna) 라이브러리를 사용했습니다.

서비스 바로가기

스마트 탁상 시계

화면 미리보기

동작 화면은 아래 이미지와 같습니다.

이미지 좌측의 색상 버튼을 클릭하면, 우측의 색상 선택 Dialog가 표시됩니다.

color picker 동작화면

작업 간략 소개

build.gradle(Module)에 라이브러리 추가

implementation 'com.github.yukuku:ambilwarna:2.0.1'

Layout 부분

  • 색상 버튼 추가

Kotlin 코드 부분

  • 버튼 클릭 시 색상 선택 Dialog 호출 및 선택 시 Listener 설정

layout

fragment_setting.xml

  • 색상 버튼을 표시하는 설정 레이아웃 중 색상 선택 버튼 부분입니다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ... 생략 ...>

	<!-- 생략 -->

    <LinearLayout
        android:id="@+id/view_custom_colors"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:visibility="gone"
        android:baselineAligned="false"
        >
        <LinearLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:layout_marginEnd="2dp"
            android:orientation="vertical">
            <com.google.android.material.textview.MaterialTextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/background_color" />
            <com.google.android.material.button.MaterialButton
                android:id="@+id/btn_custom_background_color"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:backgroundTint="@color/default_background_color"
                app:strokeColor="@color/teal_700"
                app:strokeWidth="4dp" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:layout_marginStart="2dp"
            android:orientation="vertical">
            <com.google.android.material.textview.MaterialTextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/text_color" />
            <com.google.android.material.button.MaterialButton
                android:id="@+id/btn_custom_text_color"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:backgroundTint="@color/default_text_color"
                app:strokeColor="@color/teal_700"
                app:strokeWidth="4dp" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

Kotlin Source (Fragment)

SettingFragment.kt

코드 내 주석을 참고해 주세요.

package kr.sosone.clock

import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import kr.sosone.clock.common.EnumFont
import kr.sosone.clock.common.Util
import kr.sosone.clock.common.Util.Companion.marginPixel
import kr.sosone.clock.common.Util.Companion.presetSize
import kr.sosone.clock.databinding.FragmentSettingBinding
import kr.sosone.clock.viewmodels.ClockViewModel
import kr.sosone.clock.viewmodels.ClockViewModelFactory
import yuku.ambilwarna.AmbilWarnaDialog

class SettingFragment : Fragment() {

    private var _binding : FragmentSettingBinding? = null
    private val binding get() = _binding!!

    // 설정한 Data는 viewMode에서 관리
    private val viewModel: ClockViewModel by activityViewModels{
        ClockViewModelFactory(
            (activity?.application as ClockApplication).database.settingDao()
        )
    }

    // ...생략...

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // 버튼 색상 지정
        // 저장된 색상은 String이므로 Color.parseColor 이용하여 Int로 변경
        binding.btnCustomBackgroundColor.setBackgroundColor(Color.parseColor(viewModel.customBackgroundColor.value))
        binding.btnCustomTextColor.setBackgroundColor(Color.parseColor(viewModel.customTextColor.value))

		// 색상 버튼 클릭 시 loadColorPicker 함수 호출
        binding.btnCustomBackgroundColor.setOnClickListener {
            loadColorPicker(viewModel.customBackgroundColor.value ?: Util.defaultBackgroundColor, true)
        }

        // 색상 버튼 클릭 시 loadColorPicker 함수 호출
        binding.btnCustomTextColor.setOnClickListener {
            loadColorPicker(viewModel.customTextColor.value ?: Util.defaultTextColor, false)
        }
    }

    // Color Picker 라이브러리가 호출 되는 부분
    private fun loadColorPicker(defaultColor: String, isBackgroundColor: Boolean){
        val color = Color.parseColor(defaultColor)
        AmbilWarnaDialog(requireActivity(), color,
            object : AmbilWarnaDialog.OnAmbilWarnaListener {
                override fun onCancel(dialog: AmbilWarnaDialog?) {

                }

                // 색상 변경 시 처리 내용
                override fun onOk(dialog: AmbilWarnaDialog?, color: Int) {
                	// Int형인 color를 String형인 ViewModel에 저장하기 위한 변환 코드
                    val hexColor = String.format("#%06X", 0xFFFFFF and color)
                    if(isBackgroundColor){
                        viewModel.changeCustomBackgroundColor(hexColor)
                        binding.btnCustomBackgroundColor.setBackgroundColor(color)
                    }else{
                        viewModel.changeCustomTextColor(hexColor)
                        binding.btnCustomTextColor.setBackgroundColor(color)
                    }

                }
            }).show()
    }
}

라이브러리에 대한 더 자세한 내용은 yukuku/ambilwarna github을 참고하세요.

덧붙이는 내용

어떤 라이브러리를 사용할까 검색을 하고 처음에는 ColorPickerView를 사용하기로 했습니다.

현재(2023)까지도 업데이트가 활발한 것으로 보이고, 디자인도 좋고, 사용법도 간단합니다.

하지만 회전 시 Dialog 크기가 맞지 않아 포기했습니다. ㅠㅠ
커스텀이 가능하시거나, 회전이 필요 없다면 해당 라이브러리도 좋아 보입니다.

(제가 사용한 AmbilWarna 라이브러리는 최종 업데이트가 꽤 오래된 것으로 보입니다.
하지만 저의 프로젝트 버전인 compileSdk 33, targetSdk 33 버전에도 잘 동작했습니다.
디자인과 업데이트는 조금 별로이긴 하지만, 기능상의 문제는 없었기 때문에 선택했습니다.)