Drawble Selector를 이용한 Button 만들기
왜 기본 Button이 있는데, Selector?
우리가 일반적으로 사용하는 Button은 다양한 제약을 받으며, 이를 피하기 위해 Custom해서 사용해야 한다. 버튼 또는 이미지가 터치 됐을 때, 터치됐다는 느낌을 주고싶다면, 혹은 한 버튼의 현재 상태에 따른, 예를 들면 포커스 됐을 때, 체크 됐을 때, 선택 되었을 때 등 여러 상태에 따라 커스텀하고 싶을 때 Drawble Selector를 이용해서 만들면 편리하다.
Drawble Selector
먼저 Drawble Selector를 이용해 이미지로 버튼을 클릭했을 때, 클릭하지 않았을 때의 이미지를 다르게 만들어보겠다.
- res/drawable 폴더에 클릭 됐을 때, 클릭이 안됐을 때(true와 false일 때) 이미지를 넣어준다.
- drawable 폴더에 우클릭 후 New / Drawable Resorce File을 선택해 Root element를 Selector로 지정한 후 버튼이 클릭됐을 때 할 행동을 Seletor XML을 만들어준다.
- 예제에서는 클릭됐을 때, 클릭되지 않았을 때 두 가지 예시로만 만들었다.
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/press"/> <item android:state_pressed="false" android:drawable="@drawable/not_pressed"/> </selector>
- 사용할 버튼의 background에 적용해준다.
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/clicked" android:text="버튼 클릭" />
이런 식으로 적용해 주면 ?
안된다
왜 안될까? 특정 버전의 안드로이드 스튜디오는 프로젝트 생성시에
- Theme.MaterialComponents.DayNights.DarkActionBar를 디폴트 테마로 설정한다.
- 해당 테마에서 Button 생성시 MaterialButton을 생성한다.
- MaterialButton의 background는 자체적인 background를 가지고 있어, android:background 속성의 설정 값을 무시한다!
이를 수정하기 위해서 2가지 방법이 있다.
- 일반 Button 대신 androidx.appcompat.widget.AppCompatButton 을 사용한다.
<androidx.appcompat.widget.AppCompatButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/clicked"
android:text="버튼 클릭" />
- res/values/themes/themes.xml 에서 상단의 parent="Theme.MaterialComponents.DayNight.DarkActionBar" 부분을
parent="Theme.AppCompat.DayNight.DarkActionBar"로 바꾸어 준다.
이렇게 둘중 하나를 적용해주면 아래와 같이 버튼을 클릭했을 때와 클릭하지 않았을 때 다른 이미지를 볼 수 있다.
ImageView 또는 TextView에서의 Selector
그렇다면 ImageView 또는 TextView에서도 똑같이 가능할까? ImageView나 TextView에서는 다르게 적용해준다. 상단에 RelaytiveLayout으로 TextView 또는 ImageView를 감싸준 뒤 clickable="true"로 설정해준다. 그리고 background 속성에 동일하게 drawable을 설정해준다.
이런식으로 설정하지 않고 TextView에 clickable 속성을 줄 경우 Text를 정확하게 클릭하지 않으면 이미지가 바뀌지 않기 때문이다.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/clicked"
android:clickable="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</RelativeLayout>
<androidx.appcompat.widget.AppCompatButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/clicked" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/clicked"
android:clickable="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/clicked" />
</RelativeLayout>
</LinearLayout>
6가지 상태
버튼이 클릭 됐을 때 이외에도 다양한 옵션을 줄 수 있다.
android:state_enable : 사용 가능 상태
android:state_selected : 선택 상태
android:state_pressed : 클릭 상태 (눌려있는 경우)
android:state_focused : 포커스 상태
android:state_checked : 체크된 상태
android:state_checkable : 체크할 수 있는지
다양한 옵션 모두 실행해보길 바란다.
Selector가 enabled, selected 등 여러 속성에 따른 이미지가 다른 경우(속성이 겹칠 경우) 맨 마지막 속성의 이미지가 표시된다.
정리
- Drawable Selector를 이용할 땐 true와 false 모두 설정해주기(false 값이 기본 값이다.)
- 기존의 Button은 Default값 때문에 바뀌지 않으니 Appcompat의 Button 사용하기( 또는 theme에서 설정 값 바꿔주기)
- ImageView 또는 TextView에서 Selector를 이용할 땐 뷰 그룹안에 넣은 뒤 Clickable을 True로 해준 뒤 사용하기