본문 바로가기
개발(Development)/Android(안드로이드)

[안드로이드] 원형 프로그레스바 동적으로 조정하는 방법

by 카레유 2021. 8. 21.

안드로이드 커스텀 원형 프로그레스바의 진행률을

동적으로 설정하는 방법을 정리한다.

 

아이디어는 간단하다.

호(Arc)를 그려 원형 프로그레스 바를 만들고,

사용자 이벤트나 진행상황에 따라 호의 각도 값을 조정하는 것이다.

 

원형 프로그레스바(도넛 그래프) 자체를 만드는 방법은 아래 글을 참고하자.

[안드로이드] 커스텀 원형 프로그레스 바(도넛 그래프) 만드는 방법


1. 커스텀뷰(원형 프로그레스바) 코드

1) numProgress 라는 변수를 만들어 그려질 호의 값도값을 관리한다.

2) canvas.drawArc() 메서드 호출시, sweepAngle 매개변수를 numProgress 변수로 설정한다.

3) setPregoress() 메서드를 따로 만들어서, numProgress 값을 업데이트하고, invalidate() 메서드를 호출해 뷰를 갱신한다.

* 참고: [안드로이드 코틀린] 커스텀 View 화면 갱신 방법(새로 그리기): invalidate()

 

class CustomCircleBarView: View {

    // 생성자
    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)

    // ARC(호)의 각도값을 관리할 변수
    var numProgress: Float = 0.0f

    // 뷰 그리기
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        val paint = Paint()

        // 1. 회색 원(배경)
        paint.color = Color.GRAY
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 40f
        canvas?.drawArc(200f, 200f, 700f, 700f, 0f, 360f, false, paint)


        // 2. 파란 원(프로그레스)
        paint.color = Color.GREEN
        // sweepAngle 매개변수 위치에 위에서 선언한 numProgress 변수를 넣어준다.
        canvas?.drawArc(200f, 200f, 700f, 700f, -90f, numProgress, false, paint)

    }


    // 함수: 프로그레스바의 각도값을 변경하는 함수
    fun setProgress(num: Float){
    
        // numProgress 값을 변경한다.
        numProgress = num
        
        // 뷰 갱신: 변경된 numProgress 값을 적용하여 뷰를 다시 그린다.
        invalidate()
    }

}

나름대로 상세하게 주석을 달아봤다.

 

 

2. 레이아웃 XML

1) 커스텀뷰 프로그레스바를 하나 넣고,

2) numProgress 값을 쉽게 세팅하기 위해 SeekBar 를 하나 추가했다.(최대값을 360으로 설정했다. 호는 360도가 최대니까.)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".CustomCircleBarActivity">

    <!-- 커스텀뷰(원형 프로그레스바)-->
    <com.example.test.CustomCircleBarView
        android:id="@+id/customCircleBarView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- SeekBar -->
    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:max="360"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="113dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
        
</androidx.constraintlayout.widget.ConstraintLayout>

* 뷰의 크기, 마진 등의 화면 구성은 상황에 맞게 세팅하자.

 

 

3. 액티비티

1) 뷰 참조: 커스텀뷰(원형 프로그레스바). seekBar 를 참조한다.

2) SeekBar 의 변경 이벤트 처리: 커스텀뷰에 만들어둔 setProgress()함수를 호출해준다.

class CustomCircleBarActivity : AppCompatActivity(), SeekBar.OnSeekBarChangeListener {

    // 뷰 참조: 커스텀뷰, seekbar 참조
    val circleBarView: CustomCircleBarView by lazy { findViewById(R.id.customCircleBarView) }
    val seekBar: SeekBar by lazy { findViewById(R.id.seekBar) }    

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.custom_circle_activity)
        
        // seekBar에 이벤트 리스너 장착
        seekBar.setOnSeekBarChangeListener(this)
    }

    // seekBar의 바를 드래그하여 조정하면 콜백
    override fun onProgressChanged(seekBar: SeekBar?, value: Int, fromUser: Boolean) {
        // 커스텀 뷰의 setProgress()메서드를 호출해준다. Float로 형변환해서 값을 넣어주었다.
        circleBarView.setProgress(value.toFloat())
    }

    override fun onStartTrackingTouch(p0: SeekBar?) {
    }

    override fun onStopTrackingTouch(p0: SeekBar?) {
    }
}

 

완성되었다.

댓글