프로그래스바는 작업 진행률을 나타내기 위해 사용하는 뷰 위젯이다. 안드로이드의 프로그레스바는 진행 상태를 표시함에 있어 두 가지 모드를 지원하는데, 불확정적(indeterminate) 상태 표시 모드와 확정적(determinate) 상태 표시 모드이다. 이 두 가지 모드를 구분하는 기준은, 진행 상태를 표시할 때 명확한 수치 또는 범위 값을 지정하여 현재의 진행 단계를 표시할지(=determinate), 아니면 명확한 수치 또는 범위 값을 사용하지 않고 막연히 작업이 진행되고 있음을 표시할지(=indeterminate)여부이다.
불확정적 상태 표시 모드가 프로그래스바의 기본 동작 모드이며, 화면에 표시될 때 특정 값을 표시하지 않고 반복적인 애니메이션을 통해 어떠한 작업이 진행 중임을 보여준다.
화면 중앙에 배치하기 위해 progressLayout의 layout_width와 layout_height을 wrap_content로 변경해주었다.
*3초간 프로그래스바가 돌아간 뒤 사라지는 코드
package com.example.myapplicationkotlin
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.example.myapplicationkotlin.databinding.ActivityMainBinding
import kotlin.concurrent.thread
class MainActivity : AppCompatActivity() {
val binding by lazy { ActivityMainBinding.inflate(layoutInflater)}
//Activity가 가지고 있는 property를 넘김
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root) //binding이 생성되면 항상 해줘야하는 부분분
with(binding){
/// <- 메인스레드
thread(start=true){ /// -> 서브스레드
Thread.sleep(3000) //3초간 sleep
//화면에 영향을 미치는 코드는 메인스레드로 다시 보내야 한다.
runOnUiThread{
showProgress(false)
}
} /// <- 서브스레드
/// <- 메인스레드드
}
//현재 코드는 화면을 그려주는 mainThread와 함께 있음.
//이때 sleep함수를 써버리면 그 코드까지 멈춰버리는 상황이 생김.
//이를 방지하기 위해 thread를 사용한다.
//start=true로 인해, 이 코드를 만난 순간 바로 실행이 된다.
//start=true를 주지 않으면, thread블럭 마지막에 .start()를 붙여야 실행됨
}
fun showProgress(show: Boolean){
binding.progressLayout.visibility = if(show) View.VISIBLE else View.GONE
//화면에서 다운로딩할 땐 View.VISIBLE, 다운로드가 끝나면 GONE
}
}
ViewBinding을 사용해 layout에 있는 위젯들을 사용하였다.
with함수 안에 thread블럭을 사용하지 않고 코드를 짜는 경우, 메인 스레드가 진행되는 과정에서 sleep코드와 progressLayout.visibility 코드가 다 진행되버리므로, 화면에 프로그래스바가 보이기도 전에 visibility가 GONE이 되버린다.
이를 방지하기 위해 코틀린에서 제공하는 thread라이브러리를 사용해 서브 thread를 만들고, 그 안에 코드를 구현해주었다. 이 때, 프로그래스바가 사라지는 코드는 화면에 즉, UI에 영향을 미치는 코드이므로 runOnUiThread블럭 내부에서 코드를 구현해주었다.
추가로,
thread(start=true) {}
서브 thread를 실행시키는 방법으로는 다음과 같은 start=true를 지정해주는 방법이있고,
thread(){
//코드
}.start()
이런식으로, 블럭 마지막에 .start()를 붙여서 실행시킬 수도 있다.
2. SeekBar
시크바는 드래그 가능한 기능을 추가한 프로그래스바의 확장과 같다. 사용자는 손가락으로 시크바를 터치해 왼쪽이나 오른쪽으로 드래그하여 현재 진행 수준을 설정하거나 화살표 키를 사용할 수 있다.
시크바는 볼륨 조절 컨트롤러에서 가장 많이 쓰이며, 음악 플레이어에서 구간을 찾아갈때도 사용한다.
textView와 seekBar를 한 개씩 배치시킨 layout
progressBar의 수치 최대값은 attributes의 max속성을 통해 조절할 수 있다. 디폴트 값은 100이다.
package com.example.myapplicationkotlin
import android.os.Bundle
import android.widget.SeekBar
import androidx.appcompat.app.AppCompatActivity
import com.example.myapplicationkotlin.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
val binding by lazy { ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
with(binding){
seekBar.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
//progress는 현재 탐색 구간값이 넘어옴.
//fromUser는 시크바를 내가 터치해서 탐색할 수도있지만 코드에 의해 움직일 수도 있다.
//fromUser가 true이면 사람이 터치하고 있는 것.
if(fromUser) {//사람이 터치로 동작시킬 때만 실행하는 코드
textView.text = "$progress"
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
}
}
}
시크바의 경우, 람다함수로 만들어진 setOn~Listener가 없기 때문에 object키워드를 붙이고 OnSeekBarChangeListener를 사용해주어야 한다. 이때, OnSeekBarChangeListener인터페이스에 구현된 함수 3개를 모두 구현해 주어야 하는데 다음과 같다.
onProgressChanged : 시크 바를 조작하고 있는 중 작동
onStartTrackingTouch : 시크 바를 조작하기 시작했을 때 작동
onStopTrackingTouch : 시크 바 조작을 마무리했을 때 작동
시크바 코드 AVD 돌린 모습
3. RatingBar
레이팅바는 별 등급을 표시하는 시크바 및 프로그래스바의 확장 버전이다. 사용자는 레이팅바를 사용할 때 터치 또는 드래그 또는 화살표 키를 사용하여 등급을 설정할 수 있다.
ratingBar와 textView를 하나씩 배치한 모습
ratingBar의 경우, numStart속성을 통해 별 개수를 바꿀 수 있다. (디폴트는 5개이다)
rating 속성을 통해 원하는 만큼 별을 미리 채워둘 수 있다.
stepSize 속성을 통해 rating step을 지정할 수 있는데, 0.1로 변경하면 점수를 좀 더 디테일하게 줄 수 있다. (디폴트는 0.5이므로 점수를 0부터 0.5간격으로 줄 수 있다.)stepSize를 0.1로 했을 때 결과
*사용한 코드