일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 자바
- 코루틴
- 디자인패턴
- 코틀린
- Compose
- theming
- Gradle
- viewmodel
- android
- Coroutine
- 알고리즘
- 책
- 스레드
- 병럴프로그래밍
- Rxjava
- 안드로이드강좌
- k8s
- mockito
- 알게되는
- 글또
- 회고
- 병렬프로그래밍
- g 단위테스트
- ReactiveProgramming
- kotlin강좌
- Kotlin
- 커스텀상태
- 안드로이드스튜디오
- 안드로이드
- 테스트
- Today
- Total
선생님, 개발을 잘하고 싶어요.
[Custom View] 안드로이드 커스텀 뷰, 커스텀 상태 state 선언하고 사용하기 본문
도입
뷰를 enabled, checked 여부에 따라서 다른 리소스를 사용해서 보여줘야 하는 경우가 많다. 이런 경우 우리는 selector를 활용한다. enabled, checked와 같이 안드로이드 플랫폼에서 미리 정의된 상태에 대해서는 이미 편하게 selector를 만들고 사용하지만 개발을 하다보면 새로운 요구 사항을 만족하는 화면을 그려야 할 때가 있다. 가령 예를 들어 TextField의 내용에 에러가 있을 때는 빨간 테두리를 그려주고 그러지 않을 때는 검은 테두리를 그려야 하는 요구사항이 있을 수 있다. 하지만 state_enabed는 있어도 state_error와 같은 커스텀 상태는 존재하지 않는다.
이번 포스팅에서는 이러한 커스텀 상태를 정의하고 사용하는 가이드를 보여주려고 한다.
작업하기
우선 추가하고 싶은 state를 custom attribute로 추가해야한다.
<!-- res/values/state_attrs.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="state_error" format="boolean" />
</resources>
이렇게 추가한 custom state는 app name space를 통해서 접근할 수 있다. android:state_enabled와 마찬가지로 접근하면 된다.
이 selector는 state_error drawableState가 true일 때는 빨강을, 그러지 않을 때는 검정색을 노출하는 selector다.
<!-- res/color/selector_black_red.xml -->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:color="#ff0000" app:state_error="true" />
<item android:color="#000000" />
</selector>
커스텀 state를 활용한 color라고 독특한 사용법이 있는 것은 아니다. 평소에 color resource 사용하는 대로 사용한다.
error 상태에 따라서 border를 빨갛게 그릴지 검게 그릴지 지정한다.
<!-- error_aware_border.xml -->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="2dp"
android:color="@color/selector_black_red" />
</shape>
이제 진짜 CustomView가 selector가 알아먹을 수 있는 error state를 가지도록 설정해보자.
- 추가 할 custom attr의 intArray를 선언한다. 이게 drawableState에 포함되면 해당 view는 state_error=true 상태가 된다.
- onCreateDrawableState(...)를 재정의한다. CustomView는 isError 속성에 따라서 drawableState에 custom state인 error를 추가할 지 말지 선택하게 된다.
- 실제로 CustomView의 property인 isError가 세팅되는 시점에 drawableState를 갱신한다. 이를 위해서 refreshDrawableState() 함수를 호출하자.
class CustomView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
companion object {
private val ERROR_STATE_SET = intArrayOf(R.attr.state_error)
}
override fun onCreateDrawableState(extraSpace: Int): IntArray {
val drawableState = super.onCreateDrawableState(extraSpace + 1)
if (isError) {
mergeDrawableStates(drawableState, ERROR_STATE_SET)
}
return drawableState
}
var isError: Boolean = false
set(value) {
if (field == value) return
field = value
refreshDrawableState()
}
}
테스트 과정에서 쉽게 결과를 확인할 수 있도록 styleable attr를 추가하자. 이를 추가하면 xml 상에서 state_error 값을 설정할 수 있다.
<!-- res/values/state_attrs.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="state_error" format="boolean" />
<declare-styleable name="CustomView">
<attr name="state_error" />
</declare-styleable>
</resources>
실제로 xml에 선언된 state_error 값을 읽어서 CustomView의 초기값에 반영하도록 한다. 이 경우 isError setter가 호출되며 refreshDrawaleState가 호출되고 isError 속성에 따라서 적절한 drawableState가 생성되게 된다.
init {
context.withStyledAttributes(attrs, R.styleable.CustomView, defStyleAttr) {
isError = getBoolean(R.styleable.CustomView_state_error, false)
}
}
지금까지 정의한 것들을 확인하기 위해서 sample_layout.xml을 작성했다.
custom state인 state_error에 따라서 border가 다르게 그려진 것을 layout editor를 통해서 쉽게 확인할 수 있다.
'개발 > android 개발' 카테고리의 다른 글
[OAuth] 카카오 로그인 안드로이드 kotlin, coroutine 구현 가이드, 플랫폼 설정 부터 coroutine utility 까지 (5) | 2022.06.03 |
---|---|
[안드로이드 잡학] File 저장하기 (internal , external storage) (0) | 2022.03.14 |
[Compose] 소프트 키보드 닫기 (0) | 2022.02.27 |
[Android] Styling, Style과 Theme 바로알기 좋은 자료 (0) | 2022.01.23 |
URL 구조와 OkHttp3를 이용한 URL 생성 및 파싱 (0) | 2022.01.16 |