0

The custom TextInputLayout results in the below exception when trying to achieve errorState.

 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.res.ColorStateList.isStateful()' on a null object reference at com.google.android.material.textfield.TextInputLayout.setBoxStrokeColorStateList(TextInputLayout.java:1103) at tech.********.platform.components.MyCustomTextInput.setErrorEnabled(MyCustomTextInput.kt:81) at com.google.android.material.textfield.TextInputLayout.<init>(TextInputLayout.java:786) at com.google.android.material.textfield.TextInputLayout.<init>(TextInputLayout.java:422) at tech.********.platform.components.MyCustomTextInput.<init>(MyCustomTextInput.kt:38) 

XML code to switch app:errorEnabled with binding

<MyCustomTextInput> android:id="@+id/inputPassword" ... app:errorEnabled="@{condition ? true: false}" <MyCustomTextInput/> 

trying to achieve error stoke colour without error text as below:

override fun setErrorEnabled(enabled: Boolean) { if (enabled) setBoxStrokeColorStateList(errorColor) else setBoxStrokeColorStateList(defaultColor) super.setErrorEnabled(false) } 

complete Layout code below:

class MyCustomTextInput : TextInputLayout { constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( context, attrs, defStyleAttr ) /** * Color states for the default scenario. */ private var defaultColor = ColorStateList( arrayOf( intArrayOf(-R.attr.state_focused, R.attr.state_enabled), intArrayOf(R.attr.state_focused, R.attr.state_enabled), ), intArrayOf(Color.parseColor("#CCCCCC"), Color.parseColor("#164A9C")) ) /** * Color states for the error scenario. */ private var errorColor = ColorStateList( arrayOf( intArrayOf(-R.attr.state_focused, R.attr.state_enabled), intArrayOf(R.attr.state_focused, R.attr.state_enabled) ), intArrayOf(Color.RED, Color.RED) ) init { setBoxStrokeColorStateList(defaultColor) // edit text stroke hintTextColor = defaultColor // edit text content } override fun setErrorIconDrawable(errorIconDrawable: Drawable?) { super.setErrorIconDrawable(null) } override fun setErrorIconTintList(errorIconTintList: ColorStateList?) { super.setErrorIconTintList(errorColor) } override fun setErrorEnabled(enabled: Boolean) { if (enabled) setBoxStrokeColorStateList(errorColor) else setBoxStrokeColorStateList(defaultColor) super.setErrorEnabled(false) } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) } } 

Using the same colorState as used in the init().

3
  • Did you solve a crash ? Commented Jun 18, 2021 at 18:22
  • No, tried calling setErrorEnabled() from the third constructor, didn't help! Commented Jun 19, 2021 at 11:22
  • Did you see my explanation ? And I added sample of solution at the end (just now). Commented Jun 19, 2021 at 12:11

1 Answer 1

0

Problem in your overriding of setErrorEnabled method: TextInputLayout call to them from constructor but variables in MyCustomTextInput (child class) not initialized because first the runtime execute a Parent constructor and then child initializers and constructor.

See simple sample bellow. Parent.java:

public class Parent { public Parent() { System.out.println("Parent constructor execution."); System.out.println("Parent call to printErrorMessageLength."); printErrorMessageLength("Parent error."); } public void printErrorMessageLength(String message) { System.out.println("Parent printErrorMessageLength execution."); System.out.println(message.length()); } } 

Test.kt:

fun main() { Child() } class Child : Parent { var childErrorMessage = "Child Error" init { println("Child.init, childErrorMessage = $childErrorMessage") } constructor() : super() {} // just for sample override fun printErrorMessageLength(inputMessage: String?) { println("Child printErrorMessageLength execution with inputMessage = $inputMessage") println("${childErrorMessage.length}") super.printErrorMessageLength(inputMessage) } } 

result of main executiong:

Parent constructor execution. Parent call to printErrorMessageLength. Child printErrorMessageLength execution with inputMessage = Parent error. Exception in thread "main" java.lang.NullPointerException at Child.printErrorMessageLength(Test.kt:16) at Parent.<init>(Parent.java:6) at Child.<init>(Test.kt:12) at TestKt.main(Test.kt:2) at TestKt.main(Test.kt) Process finished with exit code 1 

How I can solve this problem ? - initialize variable if it a null:

/** * Color states for the default scenario. */ private var defaultColor = createDefaultColor() private fun createDefaultColor(): ColorStateList = ColorStateList( arrayOf( intArrayOf(-R.attr.state_focused, R.attr.state_enabled), intArrayOf(R.attr.state_focused, R.attr.state_enabled), ), intArrayOf(Color.parseColor("#CCCCCC"), Color.parseColor("#164A9C")) ) /** * Color states for the error scenario. */ private var errorColor = createErrorColor() private fun createErrorColor(): ColorStateList = ColorStateList( arrayOf( intArrayOf(-R.attr.state_focused, R.attr.state_enabled), intArrayOf(R.attr.state_focused, R.attr.state_enabled) ), intArrayOf(Color.RED, Color.RED) ) override fun setErrorEnabled(enabled: Boolean) { if (enabled) setBoxStrokeColorStateList(errorColor?:createErrorColor()) else setBoxStrokeColorStateList(defaultColor?:createDefaultColor()) super.setErrorEnabled(false) } 

Or u can use method like getDefaultColor() instead using variable defaultColor:

private fun getDefaultColor(): ColorStateList { if(defaultColor == null) { defaultColor = createDefaultColor() } return defaultColor } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.