ㅋㅋ
오늘은 토글 버튼 그룹을 적어보려고 합니다
그냥 평면적으로 있는 토글그룹은 아니구요
중복선택이 아니라, 마치 스위치 형식으로 하나만 선택되는 형식으로요.
근데? 인디케이터가 버튼위에서 동작하는 느낌인거죠. (대신 버튼은 Text는 보임)
누르면 애니메이션으로 인디케이터가 누른걸로 선택되는 겁니다. 근데 인디케이터가 버튼 위에있어요. 왔다 갔다 좌우로 움직이는 인디케이터를 화면 전체로 움직이는 거죠
암튼 한 마디로 말해서
TabLayout, Switch 형식이 결합된. 버튼 딸깍딸깍 (??)
암튼 시작.
먼저 찾아보니까 ButtonToggleGroup이라는 view가 있더라구요. 그 안에 버튼2개를 넣어줬습니다.
0. 사전 참고
알아야할 사실
개발환경 : Android33, MateralDesign 의존성 추가가 필요한지는 확실치않은데 기본 내장이었던 듯함. 미리 drawable에는 background 속성에 넣을 xml이 존재(bkgnd_stroke_pure_grey_12dp)
Fragment의 ConstraintLayout안에서 사용했습니다. 제 기억상 현재 설명하는 토글그룹버튼의 가장 부모인 FrameLayout은 필수가 아니었던 것 같아요.
1. xml 구현
<FrameLayout
...>
<ConstraintLayout
...>
...
<FrameLayout
android:id="@+id/FrameLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent">
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/btnToggleGroup"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/@drawable/bkgnd_stroke_pure_grey_12dp"
android:backgroundTint="@color/subColor100"
android:padding="6dp"
app:singleSelection="true">
<Button
android:id="@+id/btn1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:backgroundTint="@color/transparent"
android:insetTop="0dp"
android:insetBottom="0dp"
android:textColor="@color/DeepGrey"
android:textSize="18dp"
android:visibility="visible"
app:cornerRadius="8dp" />
<Button
android:id="@+id/btn2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:backgroundTint="@color/transparent"
android:insetTop="0dp"
android:insetBottom="0dp"
android:textColor="@color/DeepGrey"
android:textSize="18dp"
app:cornerRadius="8dp" />
</com.google.android.material.button.MaterialButtonToggleGroup>
<View
android:id="@+id/toggleIndicator"
android:layout_width="wrap_content"
android:layout_height="54dp"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="@drawable/bkgnd_stroke_pure_grey_12dp"
android:backgroundTint="@color/white" />
</FrameLayout>
<TextView
android:id="@+id/tvbtn1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="1번 버튼"
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintEnd_toEndOf="@+id/btnToggleGroup"
app:layout_constraintStart_toStartOf="@+id/btnToggleGroup"
app:layout_constraintTop_toBottomOf="@+id/btnToggleGroup"
app:layout_constraintBottom_toBottomOf="@+id/btnToggleGroup">
<TextView
android:id="@+id/tvbtn2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="2번 버튼"
app:layout_constraintHorizontal_bias="0.8"
app:layout_constraintEnd_toEndOf="@+id/btnToggleGroup"
app:layout_constraintStart_toStartOf="@+id/btnToggleGroup"
app:layout_constraintTop_toBottomOf="@+id/btnToggleGroup"
app:layout_constraintBottom_toBottomOf="@+id/btnToggleGroup">
일단 토글 그룹으로 버튼을 묶어서 ? 해당 view에서 제공하는 interface를 편하게 쓰려고 묶었는데 위 xml의 토글그룹에서
<Button
...
android:layout_weight="1"
android:backgroundTint="@color/transparent" ... />
말고는 중요한게 없다는 점 ㅋㅋ 어차피 안보이거든요
중요한건 indicator역할을 하는 view.. 이 친구도 높이만 맞추고 width값은 어차피 코드에서 통제하기에 기본적으로만 세팅하면 됩니다.
그리고 indicator때문에 Button이 가려지는 문제를 해결하기 위해서 ! Button의 text를 대신 할 TextView를 bias를 통해 대칭에 맞게 위치만 조절합니다.
app:layout_constraintHorizontal_bias="0.3" // 왼쪽꺼 버튼1번
app:layout_constraintHorizontal_bias="0.8" // 오른쪽꺼 버튼2번 ㅋㅋ
저의 경우는 화면 width는 parent에 걸려있었기 때문에(화면 전체임) 이정도가 적절하더라구요. 웒하는 만큼 조절 ㄱㄱ
2. 기능 구현
// ------! 하단 버튼토글 그룹 시작 !------
binding.btnToggleGroup.check(R.id.btg1)
binding.btnToggleGroup.addOnButtonCheckedListener{ _, checkedId, isChecked ->
if (isChecked) {
when (checkedId) {
R.id.btg1 -> {
animateIndicator(true)
// 하고싶은 동작 넣기
}
R.id.btg2 -> {
animateIndicator(false)
// 하고싶은 동작 넣기
}
}
}
}
binding.btg1.setOnClickListener { binding.btnToggleGroup.check(R.id.btg1) }
binding.btg2.setOnClickListener { binding.btnToggleGroup.check(R.id.btg2) }
binding.btnToggleGroup.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener{
override fun onGlobalLayout() {
initToggleIndicator()
binding.btnToggleGroup.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
// ------! 하단 버튼토글 그룹 끝 !------
com.google.android.material.button.MaterialButtonToggleGroup 는
addOnButtonCheckedListener
addOnGlobalLayoutListener
를 사용했습니다. viewTreeObserver를 통해 레이아웃을 inflate할 때 같이 토글을 init하는 거죠.
사실 버튼을 넣었지만 토글그룹으로 할 필요도 없을 것 같지만 그렇지 않으면 ButtonCheckListener같은 리스너를 내가 일일이 만들어야 하기때문에 ^^
버튼토글그룹을 썼구요. (버튼은 실제로 보이지도 않음)
이러면 화면이 전환하며 Fragment의 화면들이 만들어질 때 이 토글버튼그룹과 그 외 따까리들도 같이 만들어지더라구요.
그럼 그위 토글인디케이터는 ?
3. 토글 인디케이터 구현
private fun initToggleIndicator() {
val buttonWidth = binding.btnToggleGroup.width / 2
val params = binding.toggleIndicator.layoutParams
params.width = buttonWidth - 36
params.height = binding.btnToggleGroup.height - 36
binding.toggleIndicator.layoutParams = params
// 초기 위치 설정
binding.toggleIndicator.x = 24f
}
private fun animateIndicator(toLeft: Boolean) {
val animator = ValueAnimator.ofFloat(
binding.toggleIndicator.x,
if (toLeft) 24f else (binding.btnToggleGroup.width - binding.toggleIndicator.width - 24f)
)
animator.addUpdateListener { animation ->
binding.toggleIndicator.x = animation.animatedValue as Float
}
animator.duration = 250
animator.start()
animator.addListener(object: Animator.AnimatorListener{
override fun onAnimationStart(animation: Animator) {}
override fun onAnimationEnd(animation: Animator) {
when (toLeft) {
true -> {
setToggleText(R.color.deep_gray, R.color.pure_gray)
}
false -> {
setToggleText(R.color.pure_gray, R.color.deep_gray)
}
}
}
override fun onAnimationCancel(animation: Animator) {}
override fun onAnimationRepeat(animation: Animator) {}
})
}
val buttonWidth = binding.btnToggleGroup.width / 2
val params = binding.toggleIndicator.layoutParams
params.width = buttonWidth - 36
params.height = binding.btnToggleGroup.height - 36
binding.toggleIndicator.layoutParams = params
// 초기 위치 설정
binding.toggleIndicator.x = 24f
당연히 layout을 코드로 통제하기 위해 layoutParams를 건드렸고,
ToggleIndicator인 view를 btnToggleGroup의 width의 절반으로 만들고, view에 마진값을 넣기 위해 -36
binding.toggleIndicator.x = 24f 를 통해 btn1위에 위치되게 했습니다. 물론
ViewCreated에서 초기 버튼은 1번이 활성화 돼 있거든요
그리고 애니메이션을 통해 슬라이딩 되면서 ToggleIndicator가 움직이게 했고,
애니메이션이 종료되면 textView2개의 색을 조절 ㅋㅋ
끗
사실 예전 NestedScrollView를 건드려서 화면 screen.Y값을 어쩌구.. 하는 것보다 훨 간단했거든여
이 형태는 사실 기능 구현은 문제가 아니라, view들을 어떻게 배치해야할지의 싸움 ㅋㅋ
만들다보니 사실 더 간소하게 만들 수도 있을 것 같은데, 뭐 잘 동작하면 땡이라서 해결완료
개발자 SardineSpicySalad
'개발 > android_kotlin' 카테고리의 다른 글
[ Kotlin ] 뱃지 읽음 감지 / 최초 실행 접근 (0) | 2024.11.10 |
---|---|
[ Kotlin ] 안드로이드 바차트 MPAndroidchart BarChart Round Shape (0) | 2024.10.12 |
[ Kotlin ] Adapter 뿌셔보기 1 ( 내 머리가 부셔짐 ) (0) | 2024.08.05 |
[ Kotlin ] 탭했을 때 view가 상단화면으로 scroll 되게 하기 (UX 개선) (2) | 2024.06.05 |
[ Kotlin ] 타이머 Runnable (0) | 2024.05.25 |