본문 바로가기
안드로이드 개발

안드로이드 - 버튼 Tint 색 전환 부드러운 애니메이션 적용하기

by 아이엔 / ienground 2021. 3. 20.

그냥 혼자서 정리하는 글 - 버튼 Tint 색을 부드럽게 전환하는 코드에 관한 내용입니다. 보통은 버튼을 자기 멋대로 만들어서 켜기 / 끄기 용으로 쓸 때, 색상으로 구분했을 때 색깔을 회색 <-> 색상으로 전환할 수 있게 할 텐데, 그거에 관하여 간략하게 메모하고자 합니다.

 

XML

버튼은 대충 이렇게 생겼는데요, Google Home 앱에서 이런 모양의 버튼을 찾을 수 있을 겁니다. 별 건 아니지만 버튼 하나의 코드를 가져오면 이렇게 생겼습니다.

<androidx.constraintlayout.widget.ConstraintLayout
  android:id="@+id/app_select"
  android:layout_width="0dp"
  android:layout_height="wrap_content"
  android:layout_marginStart="@dimen/usual_margin"
  android:layout_marginEnd="@dimen/usual_margin"
  android:layout_marginTop="@dimen/usual_margin"
  app:layout_constraintStart_toStartOf="parent"
  app:layout_constraintEnd_toEndOf="parent"
  app:layout_constraintTop_toTopOf="parent">

  <de.hdodenhof.circleimageview.CircleImageView
    android:id="@+id/bg_bp"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:src="@color/blogPlannerColor"
    android:alpha="0.2"
    android:background="?attr/selectableItemBackgroundBorderless"
    android:clickable="true"
    android:focusable="true"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

  <ImageView
    android:id="@+id/ic_bp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_icon_blogplanner"
    app:tint="@color/blogPlannerColor"
    app:layout_constraintStart_toStartOf="@id/bg_bp"
    app:layout_constraintEnd_toEndOf="@id/bg_bp"
    app:layout_constraintTop_toTopOf="@id/bg_bp"
    app:layout_constraintBottom_toBottomOf="@id/bg_bp" />
    
</androidx.constraintlayout.widget.ConstraintLayout>

참고로 CircleImageView는 나중에 한번 라이브러리를 소개할 건데, 별 건 없고 원 모양 이미지뷰입니다. 커스텀 라이브러리에요. 굳이 라이브러리를 불러오지 않아도 drawable에서 shape를 oval로 하셔도 비슷한 효과가 날 거에요 (원).

 

이렇게 배경은 bg_bp라는 이미지뷰를, 그 위의 아이콘은 ic_bp라는 이미지뷰를 만들어 두었습니다.

 

애니메이션 전환 코드

 

if (isNotSelected) {
  val before = binding.icBp.imageTintList?.defaultColor
  val current = ContextCompat.getColor(this, R.color.disabled)

  ValueAnimator.ofObject(ArgbEvaluator(), before, current).apply {
    duration = 250
    addUpdateListener { 
      binding.bgBp.setImageDrawable(ColorDrawable(it.animatedValue as Int))
      binding.icBp.imageTintList = ColorStateList.valueOf(it.animatedValue as Int)
  	}
  }.start()
} else {
  val before = binding.icBp.imageTintList?.defaultColor
  val current = ContextCompat.getColor(this, R.color.blogPlannerColor)

  ValueAnimator.ofObject(ArgbEvaluator(), before, current).apply {
    duration = 250
    addUpdateListener {
      binding.bgBp.setImageDrawable(ColorDrawable(it.animatedValue as Int))
      binding.icBp.imageTintList = ColorStateList.valueOf(it.animatedValue as Int)
    }
  }.start()
}

영상처럼 색 전환이 되고, 코드를 간략하게 설명하면 다음과 같습니다. 일단 이 코드는 각각 버튼의 OnClickListener 내에 있는 부분이고, 만약 선택이 안 된 상태로 전환되었다면, 그 전 색에서 disabled 색으로 변경합니다. before는 icBp의 imageTintList에서 색을 가져오고, current는 직접 색을 지정해 주었습니다. 이 애니메이션은 before에서 current로 색이 변환되고, 길이는 250밀리초 (0.25초) 입니다. 그래서 색이 바뀌는 동안 bgBp에 ColorDrawable을 만들어 drawable로 넣어주고, icBp는 imageTintList로 컬러 스테이트 리스트로 넣어줍니다.

 

반대도 같은데, 단지 current 색이 활성화된 색으로 바뀌었다는 사실만 다릅니다.

끝!