안녕하세요. 오늘은 TextInputLayout에 대해 정리하겠습니다.
1. 라이브러리 설정
먼저, TextInputLayout은 Material 라이브러리에 속해있으므로, 라이브러리를 추가해야합니다.
implementation 'com.google.android.material:material:1.2.1'
2. xml 선언
xml에 TextInputLayout과 style을 지정해 줍니다.
Hint, Helper, Icon, Error, Counter의 속성들은 TextInputLayout의 속성을 변경해주면 되고,
EditText에 있는 글씨나 배경색은 TextInputEditText의 속성을 변경해주면 됩니다.
[text_input_layout_fragment.xml]
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_main"
android:theme="@style/MaterialDarkNoActionBarTheme"
style="@style/Widget.App.TextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:counterEnabled="true"
app:counterMaxLength="4"
app:errorEnabled="true"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_main"
style="@style/TextInputEditTextStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="숫자 입력(4글자 이하)" />
</com.google.android.material.textfield.TextInputLayout>
3. Style 선언
중요한 점은 상위 theme는 MaterialComponents여야 합니다.
그러므로, 상위 theme가 AppCompat을 사용하고 있다면 MaterialComponents theme를 새로 하나 만들어서 Widget에 지정해주어야 합니다.
기본적으로 밑줄색의 unFocused의 색상은 theme의 colorControlNormal의 색을 따르고, Focused 색상은 colorContorlActivated의 색을 따릅니다.
[styles.xml]
<resources>
<style name="TextInputLayoutStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<!--FilledBox일 경우 밑줄 색상, OutlinedBox일 경우 테두리 색상-->
<item name="boxStrokeColor">@color/selector_text_input_outlined_color</item>
<!--Counter-->
<item name="counterTextAppearance">@style/CounterTextAppearance</item>
<!--EditText에 있을때의 Hint-->
<item name="android:textColorHint">@color/blue_grey</item>
<!--상단에 있을때의 Hint-->
<item name="hintTextColor">@color/blue_grey</item>
<item name="hintTextAppearance">@style/HintTextAppearance</item>
<!--Helper-->
<item name="helperTextTextAppearance">@style/HelperTextAppearance</item>
<!--Error-->
<item name="errorEnabled">true</item>
<item name="colorError">@color/orangey_red</item>
<item name="errorIconDrawable">@android:color/transparent</item>
<item name="errorTextAppearance">@style/ErrorTextAppearance</item>
</style>
<style name="ErrorTextAppearance">
<item name="android:textStyle">normal</item>
<item name="android:includeFontPadding">false</item>
<item name="android:textSize">12sp</item>
</style>
<style name="HintTextAppearance">
<item name="android:fontFamily">@font/noto_sans_kr_regular</item>
<item name="android:textStyle">normal</item>
<item name="android:includeFontPadding">false</item>
<item name="android:textSize">12sp</item>
</style>
<style name="HelperTextAppearance">
<item name="android:textStyle">normal</item>
<item name="android:includeFontPadding">false</item>
<item name="android:textSize">12sp</item>
</style>
<style name="CounterTextAppearance">
<item name="android:textStyle">normal</item>
<item name="android:includeFontPadding">false</item>
<item name="android:textSize">12sp</item>
</style>
<style name="TextInputEditTextStyle">
<item name="android:textStyle">normal</item>
<item name="android:includeFontPadding">false</item>
<item name="android:textSize">16sp</item>
<item name="android:textColor">@color/black</item>
</style>
</resources>
[selector_text_input_color.xml]
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/azure" android:state_focused="true"/>
<item android:color="@color/azure" android:state_hovered="true"/>
<item android:color="@color/azure" android:state_enabled="false"/>
<item android:color="@color/blue_grey"/> <!-- unfocused -->
</selector>
4. 코드 작성
Error 메세지 같은 경우 코드에서의 setError() 메소드를 통해 지정해주어야 합니다.
error의 값을 String으로 주면 에러메시지가 나타나고, null을 주면 에러메시지가 사라집니다.
class TextInputLayoutFragment : Fragment() {
private lateinit var binding: FragmentTextInputLayoutBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentTextInputLayoutBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView()
}
private fun initView() {
with(binding) {
etMain.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
if (s.toString().isEmpty()) {
tilMain.error = "공백은 허용하지 않습니다."
} else {
s.toString().toIntOrNull()?.let {
if (s != null) {
if (s.length > 4) {
tilMain.error = "4글자가 초과되었습니다."
} else {
tilMain.error = null
}
}
} ?: run {
tilMain.error = "숫자를 입력하세요."
}
}
}
})
}
}
}
FilledBox (Default)
Default Style인 Widget.MaterialComponents.TextInputLayout.FilledBox를 적용하면 위와 같은 형태로 나타납니다.
<style name="Widget.App.TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.FilledBox">
...
</style>
OutlinedBox
Widget.MaterialComponents.TextInputLayout.OutlinedBox를 적용하면 위와 같은 형태로 나타납니다.
<style name="Widget.App.TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
...
</style>