개발관련일지

안드로이드 java] dual/multi thumbs seekbar -> RangeSlider를 이용해 만들기 본문

개발기록/안드로이드

안드로이드 java] dual/multi thumbs seekbar -> RangeSlider를 이용해 만들기

BEECHANGBOT 2021. 1. 3. 01:03

이번 포스팅은 아래의 사진처럼 시크바에 설정가능한 버튼이 두개가 놓여져있는 시크바를 구현함

여기어때 앱에서 사용한 예시

 

seekbar란 가격 , 음량 , 시간 조절 등에 사용 되는 유아이

위의 사진 형태의 시크바는 영어로는 dual thumb로 불리는데 한국어로 커스텀시크바? , 듀얼시크바? 이런식으로 검색해서 찾았음 정확한 명칭 모르겠다.

 

1년전보다 오래된 글들을 보면 외부 라이브러리를 이용해서 사용하는 모습을 볼 수 있는데 , 작년 8월 머터리얼 디자인 컴포넌트 (MDC)에서 1.2.0 버전을 정식 출시하면서 slider , rangeSlider 이름으로 포함되어서 나왔다.

 

해당글은 커스텀부분은 제외하고 정말 기본적인 사용에 필요한 코드만 기록함.

 

먼저 라이브러리추가가 되어있는지 확인 , 프로젝트 생성하면 들어가있음

라이브러리 확인

아래의 3가지가 유저가 드래그로 끌어서 원하는 값을 선택할 수 있는 유아이다.

요번에 새로 추가된 것이 슬라이더와 레인지슬라이더 두개이다.

종류 별 예시

위의 사진에 사용된 xml 코드

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingHorizontal="15dp"
    tools:context=".DualThumbSeekbar">


<!--    SeekBar-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="SeekBar"
        android:textSize="17dp"
        android:textStyle="bold"
        android:layout_marginTop="30dp"
        />
    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

<!--    Slider-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Slider"
        android:textSize="17dp"
        android:layout_marginTop="30dp"
        android:textStyle="bold"

        android:valueFrom="0.0"
        android:valueTo="100.0"
        android:stepSize="10.0"

        />

    <com.google.android.material.slider.Slider
        android:id="@+id/slider"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
         />

<!--    RangeSlider -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="RangeSlider"
        android:textSize="17dp"
        android:layout_marginTop="30dp"
        android:textStyle="bold"

        />

    <com.google.android.material.slider.RangeSlider
        android:id="@+id/rangeSlider"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        android:valueFrom="0.0"
        android:valueTo="100.0"
        app:values="@array/initial_slider_values"
        android:stepSize="10.0"
        />

</LinearLayout>

 

RangeSlider를 보면 app:values="@array/initial_slider_values" 가 있다. 

values 디렉토리에 array.xml 이름으로 추가해주면 시작할 때의 초기값을 설정 할 수 있다. 

<resources>
    <array name="initial_slider_values">
        <item>20.0</item>
        <item>70.0</item>
    </array>
</resources>

가이드에선 이 방법으로 나와있지만 자바나 코틀린 코드로도 초기값을 설정이 가능함

차이점은 안드스튜디오로 볼때 xml이 이미지상으로 직관적인거 같음 하지만 결국 코드를 보면 개인적으론 자바코드가 더 편함

왼쪽 - 위의 코드로 xml을 설정한 경우  / 오른쪽 - 설정을 다 지운 초기의 경우

 

자바 코드로 컨트롤 

먼저 rangeSlider 객체로 사용한다.

rangeSlider = findViewById(R.id.rangeSlider);

1. 범위를 설정 하는 부분이다.

  설정되는 숫자 값들의 타입이 float이다.

//        최소값의 범위를 설정
        rangeSlider.setValueFrom(10f);
//        최대값의 범위를 설정
        rangeSlider.setValueTo(200f);

1번 = setValueFrom / 2번 setValueTo

setValueFrom가 바 전체 범위의 최소값(Min value) , setValueTo(Max value)가 바 전체 범위의 최대값을 나타낸다.

 

2. 스탭 사이즈를 설정 

움직일떄의 범위를 지정해준다 ex) 5일경우 5 10 15 .. / 15일경우 15 30 45...  씩 선택값이 움직임

//        스탭사이즈 설정
        rangeSlider.setStepSize(5f);

3. 바의 값을 지정해줌

슬라이더의 값이 20과 90으로 바뀜

//        바의 시작값을 설정 (20 ~ 90) 으로 범위가 잡힘
        rangeSlider.setValues(20f, 90f);

 

기본적인 값 선택은 이렇게하면 가능하다.

 

4. 값이 변할때 마다 유저가 선택한 값을 리스너를 통해서 전달 받는다.

리스너를 선언하고 add해준다.

시작할떄 리스너와 끝날때 리스너가 두가지가있는데 대부분 상황이면 onStopTrackingTouch(멈출떄)를 사용할 것이다.

유저가 선택한 값을 가져오고싶으면 getValue를 사용하면되고 리턴타입은 List<Float> 이다. 

값을 사용하는 부분은 숫자범위나 타입상황에 맞게 변형해서 사용하면 될 것이다.

//        rangeSlider 상태의 변화를 감지하는 리스너
        rangeSlider.addOnSliderTouchListener(rangeSliderTouchListener);
    //      rangeSlider 사용할떄 사용되는 리스너
    private final RangeSlider.OnSliderTouchListener rangeSliderTouchListener =
            new RangeSlider.OnSliderTouchListener() {
                @Override
                public void onStartTrackingTouch(RangeSlider slider) {
//                    바가 시작하면 동작하는 부분
                }

                @Override
                public void onStopTrackingTouch(RangeSlider slider) {
//                    유저가 바에서 손을 떄었을때 동작하는 함수
//                    slider.getValues() 값이 [0.0, 5.0]처럼 배열로 값이 들어있다.
                    int miniNumber = Float.toString(slider.getValues().get(0)).indexOf(".");
                    int maxNumber = Float.toString(slider.getValues().get(1)).indexOf(".");
                    String minVal = Float.toString(slider.getValues().get(0)).substring(0, miniNumber);
                    String maxVal = Float.toString(slider.getValues().get(1)).substring(0, maxNumber);

                    Log.d("DualThumbSeekbar ", "onStopTrackingTouch minPrice : " + minVal);
                    Log.d("DualThumbSeekbar ", "onStopTrackingTouch maxPrice : " + maxVal);
                }
            };

 

 

범위를 고려하지 않으면 에러가 발생한다.

예를 들면

전체범위가 10 ~ 50인데 setValues를 [0~20] 이렇게 하면 10보다 아래인 수가 설정되므로 범위 에러가뜬다.

전체범위가 10 ~ 60인데 setStepSize를 15로 해도 에러가 발생한다, 왜냐하면 10부터 시작했을 경우 25 40 55 스탭의 값이 최대값인 60에 안맞아 떨어지기 때문이다.

 

 

아래서 부터 전체 코드

activity_dual_thumb_seek_bar.xml

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingHorizontal="15dp"
    tools:context=".DualThumbSeekbar">


<!--    SeekBar-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="SeekBar"
        android:textSize="17dp"
        android:textStyle="bold"
        android:layout_marginTop="30dp"
        />
    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

<!--    Slider-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Slider"
        android:textSize="17dp"
        android:layout_marginTop="30dp"
        android:textStyle="bold"


        />

    <com.google.android.material.slider.Slider
        android:id="@+id/slider"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        />

<!--    RangeSlider -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="RangeSlider"
        android:textSize="17dp"
        android:layout_marginTop="30dp"
        android:textStyle="bold"

        />

    <com.google.android.material.slider.RangeSlider
        android:id="@+id/rangeSlider"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

</LinearLayout>

DualThumbSeekBarActivity

DualThumbSeekBarActivity

public class DualThumbSeekBarActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dual_thumb_seek_bar);

        rangeSliderInit();
    }


//    rangeSlider = rangeSlider를 설정하는 변수
//    상태값을 관찰하는 리스너는 rangeSliderTouchListener 이다
    private RangeSlider rangeSlider;

    private void rangeSliderInit() {
        rangeSlider = findViewById(R.id.rangeSlider);
//        초기값 설정
//        최소값의 범위를 설정
        rangeSlider.setValueFrom(10f);
//        최대값의 범위를 설정
        rangeSlider.setValueTo(300f);
//        스탭사이즈 설정
        rangeSlider.setStepSize(10f);
//        바의 시작값을 설정 (10 ~ 60) 으로 범위가 잡힘
        rangeSlider.setValues(10f, 60f);

//        rangeSlider 상태의 변화를 감지하는 리스너
        rangeSlider.addOnSliderTouchListener(rangeSliderTouchListener);
    }

    //      rangeSlider 사용할떄 사용되는 리스너
    private final RangeSlider.OnSliderTouchListener rangeSliderTouchListener =
            new RangeSlider.OnSliderTouchListener() {
                @Override
                public void onStartTrackingTouch(RangeSlider slider) {
//                    바가 시작하면 동작하는 부분
                }

                @Override
                public void onStopTrackingTouch(RangeSlider slider) {
//                    유저가 바에서 손을 떄었을때 동작하는 함수
//                    slider.getValues() 값이 [0.0, 5.0]처럼 배열로 값이 들어있다.
                    int miniNumber = Float.toString(slider.getValues().get(0)).indexOf(".");
                    int maxNumber = Float.toString(slider.getValues().get(1)).indexOf(".");

                    String minVal = Float.toString(slider.getValues().get(0)).substring(0, miniNumber);
                    String maxVal = Float.toString(slider.getValues().get(1)).substring(0, maxNumber);
                    Log.d("DualThumbSeekbar ", "onStopTrackingTouch minPrice : " + minVal);
                    Log.d("DualThumbSeekbar ", "onStopTrackingTouch maxPrice : " + maxVal);
                }
            };
}

 

 

 

참고한 사이트 :

material.io/components/sliders/android

 

Material Design

Build beautiful, usable products faster. Material Design is an adaptable system—backed by open-source code—that helps teams build high quality digital experiences.

material.io

github.com/material-components/material-components-android/blob/master/catalog/java/io/material/catalog/slider/SliderMainDemoFragment.java

github.com/material-components/material-components-android/blob/master/docs/components/Slider.md

 

material-components/material-components-android

Modular and customizable Material Design UI components for Android - material-components/material-components-android

github.com

www.youtube.com/watch?v=IibybM4oM1w

DualThumbSeekBardfdssdfActivityDualThumbSeekBarActivity

 

DualThumbSeekBarActivity