다음과 같은 텍스트 입력란을 개발할 일이 생겨 개발하던 도중 Cursor 의 색상이 바뀌지 않는 이슈를 겪어 이를 해결한 방법을 공유하도록 해보겠다.
처음엔 TextInputLayout과 그 디자인이 너무나도 달라, 텍스트 입력 뷰 자체를 커스텀해야겠다는 생각이 들었으나, TextInputLayout의 Style을 잘 지정해주면 커스텀하지 않아도 만들 수 있을 것 같아 시도해보았고 성공적으로 만들 수 있었다.
<style name="Widget.Eggeum.TextInputLayout.OutlinedBox" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="shapeAppearance">@style/ShapeAppearance.MediumComponent</item>
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="boxCornerRadiusTopEnd">8dp</item>
<item name="boxCornerRadiusTopStart">8dp</item>
<item name="boxCornerRadiusBottomEnd">8dp</item>
<item name="boxCornerRadiusBottomStart">8dp</item>
<item name="boxStrokeWidthFocused">1dp</item>
<item name="boxStrokeColor">@color/gray_500</item>
<item name="boxStrokeWidth">1dp</item>
<item name="boxBackgroundColor">@color/white</item>
<item name="endIconMode">custom</item>
<item name="errorIconDrawable">@null</item>
<item name="errorTextAppearance">@style/TextXsRegular</item>
<item name="errorTextColor">@color/error_500</item>
<item name="hintEnabled">false</item>
</style>
<style name="Widget.Eggeum.TextInputEditText.OutlinedBox" parent="Widget.MaterialComponents.TextInputEditText.OutlinedBox">
<item name="android:paddingStart">12dp</item>
<item name="android:paddingTop">14dp</item>
<item name="android:paddingBottom">14dp</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:textAppearance">@style/TextLRegular</item>
<item name="android:textColor">@color/gray_900</item>
<item name="android:textColorHint">@color/gray_400</item>
</style>
첫번째 문제는 이제 커서의 색상이 변하지 않는다는 것이었는데
https://thgus13.tistory.com/24
여러 글을 통해 확인해본 해결 방법들을 적용해보았으나, Widget.Design.TextInputLayout에서는 적용되는 해결방법(TextCursorDrawable 속성 적용)이 Widget.MaterialComponents.TextInputLayout.OutlinedBox 에서는 적용되지 않아 다른 방법들을 찾아보았지만 역시나 실패하였다.
최후의 방법은 Theme 의 colorAccent 속성을 내가 지정하려고 하는 색상으로 지정하는 것인데 Cursor 의 색상이 기본적으로 colorAccent 의 색상으로 지정되기 때문이다.
하지만 나는 TextInputLayout 내에서만 커서를 변경 시키고 싶은 것이고 colorAccent 색상 자체를 변경할 경우 다른 Side Effect 가 발생할 수 있기 때문에 이를 반려하였고 다른 해결방법을 찾을 수 있었다.
https://github.com/material-components/material-components-android/issues/820
윗 글의 erick-aguero22 님의 말씀대로
Cursor의 색상을 별도의 style로 빼내어(ThemeOverlay.MaterialComponents.TextInputLayout 에서 가져온)
이를 OulineBox 내의 android:theme 속성으로 지정해주면 되는 것이였다. (뭐 이리 번거로운지)
<style name="ThemeOverlay.Eggeum.TextInputLayout.CursorColor" parent="ThemeOverlay.MaterialComponents.TextInputEditText.OutlinedBox">
<item name="colorControlActivated">@color/teal_500</item>
</style>
<style name="Widget.Eggeum.TextInputLayout.OutlinedBox" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="shapeAppearance">@style/ShapeAppearance.MediumComponent</item>
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="boxCornerRadiusTopEnd">8dp</item>
<item name="boxCornerRadiusTopStart">8dp</item>
<item name="boxCornerRadiusBottomEnd">8dp</item>
<item name="boxCornerRadiusBottomStart">8dp</item>
<item name="boxStrokeWidthFocused">1dp</item>
<item name="boxStrokeColor">@color/gray_500</item>
<item name="boxStrokeWidth">1dp</item>
<item name="boxBackgroundColor">@color/white</item>
<item name="endIconMode">custom</item>
<item name="errorIconDrawable">@null</item>
<item name="errorTextAppearance">@style/TextXsRegular</item>
<item name="errorTextColor">@color/error_500</item>
<item name="hintEnabled">false</item>
<item name="android:theme">@style/ThemeOverlay.Eggeum.TextInputLayout.CursorColor</item>
</style>
해당 속성 colorControlActivated 를 TextInputLayout Style 내부에 직접 지정하면 반영이 안된다
위의 방법처럼 andorid:theme 속성을 통해 우회해야지만 커서 색상이 변경됨을 확인할 수 있었다..
두번째 문제는 boxStrokeColor, OutlinedBox 의 테두리의 색상 변경이었다.
boxStrokeColor 옵션에 원하는 색상을 지정하면 state_focused 상태일때, 즉 TextInputLayout를 클릭하여 입력하려할때만 색상이 변하는 것을 확인할 수 있었다.
마찬가지로 이를 해결하기 위해 구글링을 하였고 다음 글을 찾을 수 있었다.
https://github.com/material-components/material-components-android/issues/1492
gabrielemariotti 님의 말씀처럼
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_200" android:state_focused="true"/>
<item android:color="@color/gray_200" android:state_hovered="true"/>
<item android:color="@color/gray_200" android:state_enabled="false"/>
<item android:color="@color/gray_200"/> <!-- unfocused -->
</selector>
다음과 같은 각 상황별 색상을 지정하는 selector 를 만들어 이를 TextInputLayout 의 옵션에 color 속성으로 추가해주면 된다.
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_register_cafe_area"
style="@style/Widget.Eggeum.TextInputLayout.OutlinedBox"
android:layout_marginTop="4dp"
app:boxStrokeColor="@drawable/selector_box_stroke_color"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_register_cafe_area">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tiet_register_cafe_area"
style="@style/Widget.Eggeum.TextInputEditText.OutlinedBox"
android:ellipsize="end"
android:hint="@string/select_cafe_area"
android:inputType="text"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
이처럼 테두리 박스의 색상만 다르고 나머지는 같은 경우가 존재할 수 있으므로 확장성을 고려할때, 색상과 관련한 변할 수 있는 값은 Style 속성 내에서 제거하고 직접 사용하는 곳에서 지정하는게 좋을 것 같다. 글자색도 그렇고
결론) 깃허브에 이슈로 올라온 글들을 확인하는 습관을 들이자. 그게 최신 정보라면 더더욱
참고 문서)
https://github.com/material-components/material-components-android/issues/820
https://medium.com/omisoft/textinputlayout-styling-8b36a5e0d73c
https://github.com/material-components/material-components-android/issues/1492
https://github.com/material-components/material-components-android/issues/593