본문 바로가기
⛏️ | 개발 기록/🪐 | Cosmic Detox

[Android] custom NumberPicker를 string array와 함께 사용하기

by immgga 2024. 8. 28.

출처: unsplash.com

 

내일배움캠프 최종 프로젝트 기록 3

 

 

서론

어제까지는 BottomSheet의 height를 설정하기 위해 삽질한 것을 포스팅했는데,

오늘은 Bottom Sheet에 NumberPicker를 써서 구현한 것을 포스팅해보려 한다.

추가적으로 NumberPicker에 string.xml에서 정의한 string array도 함께 사용했다.

 

 

NumberPicker 구현

우선은 NumberPicker에 사용할 전용 Theme를 만들어 보겠다.

NumberPicker에서는 Picker의 text의 색과 size 등등 몇 개의 설정이 불가하기 때문에, Theme로 구현해 줘야 한다.

<style name="AppTheme.NumberPicker" parent="">
    <item name="android:textColorPrimary">@color/white</item>
    <item name="android:textSize">24sp</item>
    <item name="colorControlNormal">@color/white</item>
</style>

textColor와 size 설정은 1, 2번째 줄에서 이루어지고, colorControlNormal은 NumberPicker에서 선택된 항목과 선택되지 않은 항목의 구분선의 색을 설정할 수 있다.

 

NumberPicker를 xml에서 사용해 보자.

<NumberPicker
    android:id="@+id/number_picker_hour"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="12dp"
    android:layout_marginEnd="24dp"
    android:theme="@style/AppTheme.NumberPicker"
    app:layout_constraintEnd_toStartOf="@+id/number_picker_minute"
    app:layout_constraintHorizontal_chainStyle="packed"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

속성이 많아 보이지만 margin으로 위치 조정하고 constraintLayout 속성밖에 없어서 실제로 설정하는 속성은 theme를 설정한 속성밖에 없다.

결론은 그냥 theme 속성에 이전에 만든 theme를 넣어주면 된다.

 

NumberPicker 커스터마이징은 여기까지이다. 아예 새롭게 커스터마이징을 하고 싶으면 마음에 드는 라이브러리를 찾아보거나 직접 만들어서 사용해야 한다.

 

 

NumberPicker에 string-array 사용

이제 numberPicker에 데이터를 넣어 줘야 한다.

내 경우에는 한글/영어 설정에 따라 numberPicker의 데이터가 달라져야 했기 때문에 string.xml에 따로 string-array를 생성해 주었다. 굳이 한/영 전환 때문이 아니어도 string-array를 생성해서 쓰는 게 개인적으로는 좋다고 생각한다.

activity, fragment에 list를 생성하는 코드가 들어가지 않기 때문이다.

<string name="number_picker_unit_hour">시간</string>
<string name="number_picker_unit_minute">분</string>
<string-array name="number_picker_hour">
    <item>0</item>
    <item>1</item>
    <item>2</item>
    <item>3</item>
    <item>4</item>
    <item>5</item>
    <item>6</item>
</string-array>
<string-array name="number_picker_minute">
    <item>05</item>
    <item>10</item>
    <item>15</item>
    <item>20</item>
    <item>25</item>
    <item>30</item>
    <item>35</item>
    <item>40</item>
    <item>45</item>
    <item>50</item>
    <item>55</item>
</string-array>

내가 쓸 numberPicker의 데이터는 시간과 분 데이터가 필요하기 때문에 string-array를 정의해 준다.

텍스트 시간(hr), 분(min)을 설정하기 위한 string도 추가해 준다.

 

사용할 string-array를 이제 dialogFragment에 생성해 준다. lazy를 이용해 초기화했다.

private val hourArray by lazy { resources.getStringArray(R.array.number_picker_hour) }
private val minuteArray by lazy { resources.getStringArray(R.array.number_picker_minute) }

 

이제 numberPicker에 데이터를 넣어 준다.

modalContentSetUseTimeBinding.numberPickerHour.apply {
    val hourList = hourArray.map { "${it}${getString(R.string.number_picker_unit_hour)}" }
        .toTypedArray()

    minValue = 0
    maxValue = hourList.lastIndex
    wrapSelectorWheel = true
    displayedValues = hourList
}

우선 위에서 선언한 hourArray를 그대로 사용해도 되지만, 단위가 적혀있지 않아서 혼동이 올 수 있어서 따로 단위를 추가해 주는 작업을 진행했다.

map을 이용해 string-array와 함께 생성한 단위를 getString으로 불러와서 합쳐 주었다.

minValue와 maxValue는 hourList의 0번째 index와 마지막 index를 정의하고

wrapSelectorWheel을 true로 설정했다. 이 속성은 스크롤의 끝인 hourList의 0번째, 마지막 index에 도달했을 때도 처음 또는 마지막 item이 다시 보이게 되는 속성이다.

displayedValues에 string array의 넣어서 데이터를 불러온다.

 

구현 결과

꽤 그럴싸하게 구현되었다.

 

 

정리

기존에 있는 NumberPicker가 잘 만들어져 있어서 잘 사용하고 있다.

커스터마이징이었다면 머리가 많이 아팠을 텐데. 다행이다.

큰 문제없이 구현해서 기쁘다.

728x90