개발 마스터 김규규
Background resource의 동적 color 변경 본문
(문제가 된 부분)
디바이스가 사용가능한지에 대한 유무를 보여주는 state circle을 구현할 때 약간 버벅였다.
circle의 형태이기 때문에 xml에서 background 속성을 이용하여 shape나 vector resource를 지정해주어야했다.
그러나 디바이스의 상태에 따라 동적으로 녹색, 회색으로 state circle의 색을 변경시켜야하는데 이 또한 background 속성을 사용하여야 했다.
<View
android:id="@+id/view_state_circle"
android:layout_width="10dp"
android:layout_height="10dp"
android:background="@drawable/circle_background"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
state circle 을 위와 같이 정의해주었다.
viewStateCircle.setBackgroundResource(
when (data.isAvailable) {
true -> R.color.stateGrean
else -> R.color.gray
}
)
그런데 이렇게 setBackgroundResource()
를 사용하여 컬러를 변경시키면 당연히 기존의 @drawable/circle_background
는 날아간다.
view 객체에 대한 다른 메서드가 없을까 하고 둘러보니 setBackgroundColor()
라는 메서드를 발견하였다.
Background resource랑 background color는 다르지 않을까?
public void setBackgroundColor(@ColorInt int color) {
if (mBackground instanceof ColorDrawable) {
((ColorDrawable) mBackground.mutate()).setColor(color);
computeOpaqueFlags();
mBackgroundResource = 0;
} else {
setBackground(new ColorDrawable(color));
}
}
그러나 메서드를 뜯어본 결과 ColorDrawable
객체를 생성하여 똑같이 setBackground()
를 호출하고 있었다..
도대체 어떻게 background와 color를 동시에 지정해줄 수 있을까?
메서드를 또 둘러보니 xml에서 backgroundTint 라는 속성을 발견했다.
공식 문서에는 그저 View에 Tint를 적용해주는 속성이라고만 설명이 되어있다.
(그래서 Tint가 뭔데요..!)
그리고 backgroundTintMode에 대한 설명도 바로 아래에 있었다.
위 설명을 보니 Tint가 어떠한 filter 역할을 하는 것 같아보인다.
그렇다면 background resource의 컬러를 흰색으로 두고 background tint를 동적으로 변경하여 background resource의 컬러에 필터를 씌어주는 방법을 사용하면 되지 않을까?
그러나 위 사진에서 보다시피 setBackgroundTint()
메서드는 ColorStateList
타입을 파라미터로 받는다.ColorStateList.valueOf(int color)
메서드를 활용하면 될 것 같은데 Color resource에 있는 색상 값을 어떻게 ColorInt로 넘겨줄 수 있을까?
이럴 때는 ContextCompat.getColor()
메서드를 사용하면 된다.
최종적으로
viewStateCircleItem.backgroundTintList = when (data.isAvailable) {
true -> ColorStateList.valueOf(ContextCompat.getColor(this.root.context, R.color.stateGrean))
else -> ColorStateList.valueOf(ContextCompat.getColor(this.root.context, R.color.gray))
}
이렇게 코드를 작성하였고 원하는 결과대로 state circle이 표시됨을 확인할 수 있었다.