본문 바로가기

OS/Android

Android DatePicker Custom

반응형

앱 종료시간을 유저가 자유롭게 선택할 수 있도록 DatePicker를 사용하려고 했는데 기존 DatePicker는 유아이 컬러나 버튼 위치를 내 마음대로 변경하기 어려워서 커스텀해서 사용하기로 했다.

먼저 DatePicker를 뜯어보니 기본적으로 NumberPicker라는 위젯을 사용하고 있어서 그대로 구현해보기로 하였다. 

 

XML dlg_custom_datepicker

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@color/wallet_holo_blue_light"
    android:layout_gravity="center"
    android:layout_marginLeft="30dp"
    android:layout_marginRight="30dp"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:textColor="@color/real_white"
            android:textSize="20sp"
            android:textStyle="bold"
            android:text="종료시간을 선택하시오."
            />
    </LinearLayout>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="150dp">

        <NumberPicker
            android:id="@+id/npHour"
            android:layout_width="50dp"
            android:layout_height="150dp"
            android:theme="@style/CustomNumberPicker"
            android:layout_marginRight="20dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/textView2"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="1.0">

        </NumberPicker>

        <TextView
        	android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginBottom="8dp"
            android:text=":"
            android:textSize="30sp"
            android:textColor="@color/real_white"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <NumberPicker
            android:id="@+id/npMinute"
            android:layout_width="50dp"
            android:layout_height="150dp"
            android:layout_marginLeft="20dp"
            android:theme="@style/CustomNumberPicker"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@+id/textView2"
            app:layout_constraintTop_toTopOf="parent" />
    </android.support.constraint.ConstraintLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:background="@drawable/dlg_fav_bottom_shape"
        >

        <Button
            android:id="@+id/btnCancel"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:textColor="@color/real_white"
            android:background="@color/transparent"
            android:text="취소"
            />

        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:layout_marginTop="1dp"
            android:background="@color/real_white"
            />

        <Button
            android:id="@+id/btnOk"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:textColor="@color/real_white"
            android:background="@color/transparent"
            android:text="확인"
            />

    </LinearLayout>

</LinearLayout>

 

화면

 

코틀린 CustomDatePicker

class CustomDatePicker(var act: Activity) : YKDialog(act) , View.OnClickListener
{
    lateinit var btnCancel      : Button   // 닫기
    lateinit var btnOk          : Button   // 확인

    lateinit var npHour         : NumberPicker //시간 넘버픽커
    lateinit var npMinute       : NumberPicker //분 넘버 픽커

    lateinit var mDisplayedValuesHr     : MutableList<String>
    lateinit var mDisplayedValuesMin    : MutableList<String>

    override fun onClick(v: View)
    {
        when (v.id)
        {
            R.id.btnCancel          ->  mDialogResult?.let { it.onDialogResult(this, Const.RES_CANCEL, null) } //취소
            R.id.btnOk              ->
            {
                var nResult = (npHour.value * 60) + npMinute.value
                mDialogResult?.let { it.onDialogResult(this, Const.RES_OK, nResult.toString()) }
            }
        }
    }

    init
    {
        setContentView(R.layout.dlg_custom_datepicker)
        initViewSetting()
        initNumberPicker()
    }

    fun initViewSetting()
    {
        npHour = findViewById(R.id.npHour)
        npMinute = findViewById(R.id.npMinute)
        btnOk = findViewById(R.id.btnOk)
        btnCancel = findViewById(R.id.btnCancel)

        btnOk.setOnClickListener(this)
        btnCancel.setOnClickListener(this)
    }

    fun initNumberPicker()
    {
        npHour.minValue = 0
        npHour.maxValue = 23
        npHour.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS

        mDisplayedValuesHr = mutableListOf()
        for(i in 0 until 24)
        {
            mDisplayedValuesHr.add(String.format("%02d", i)) //1 -> 01로 표시 
        }
        npHour.displayedValues = mDisplayedValuesHr.toTypedArray()
        
        //시간 넘버픽커에 최소, 최대값 설정한 후 그 중간값들을 세팅해주는 작업
        // 0~23까지 리스트에 넣어줌
        
        

        npMinute.minValue = 0
        npMinute.maxValue = 59
        npMinute.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
        mDisplayedValuesMin = mutableListOf()
        for(i in 0 until 60)
        {
            mDisplayedValuesMin.add(String.format("%02d", i)) //1 -> 01로 표시 
        }
        npMinute.displayedValues = (mDisplayedValuesMin.toTypedArray())
        // 분 넘버픽커에 최소, 최대값 설정한 후 그 중간값들을 세팅해주는 작업
        // 0~59까지 리스트에 넣어줌
        

        setDividerColor(npHour, act.resources.getColor(R.color.real_white))
        setDividerColor(npMinute, act.resources.getColor(R.color.real_white))

        npHour.value    = 0
        npMinute.value  = 30
        
        // 처음 세팅값 00 : 30
    }

    private fun setDividerColor(picker: NumberPicker, color: Int) //픽커 글자 컬러를 변경
    {
        val pickerFields = NumberPicker::class.java.declaredFields
        for (pf in pickerFields) {
            if (pf.name == "mSelectionDivider")
            {
                pf.isAccessible = true
                try
                {
                    val colorDrawable = ColorDrawable(color)
                    pf.set(picker, colorDrawable)
                } catch (e: IllegalArgumentException)
                {
                    e.printStackTrace()
                } catch (e: Resources.NotFoundException)
                {
                    e.printStackTrace()
                } catch (e: IllegalAccessException)
                {
                    e.printStackTrace()
                }
                break
            }
        }
    }

    override fun onBackPressed()
    {
        mDialogResult?.let {
            it.onDialogResult(this, Const.RES_CANCEL, null)
        }
        super.onBackPressed()
    }


}
반응형