Search code examples
androidkotlinandroid-jetpackandroid-architecture-navigationinput-mask

Android Jetpack Navigation Component issue with edit text masks and error messages


I'm trying to use android-input-mask by RedMadRobot in my Android Kotlin project. But currently, I'm dealing with very strange behavior. The library only works when I disable the Android Navigation Component.

My activity_main.xml layout has the following fragment:

<fragment
    android:id="@+id/nav_host"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="androidx.navigation.fragment.NavHostFragment"
    app:navGraph="@navigation/navigation"
    app:defaultNavHost="true"/>

Then, in the start destination defined in the navigation component I have:

<EditText
    android:id="@+id/test"
    android:inputType="number"
    android:digits="1234567890+-() "
    { omitted for sake of simplicity } />

Finally, in the the SignUpFragment.kt file I have these lines of code:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val listener = MaskedTextChangedListener.installOn(
        test,
        "+7 ([000]) [000]-[00]-[00]",
        object : MaskedTextChangedListener.ValueListener {
            override fun onTextChanged(maskFilled: Boolean, extractedValue: String, formattedValue: String) {
                Log.d("TAG", extractedValue)
                Log.d("TAG", maskFilled.toString())
            }
        }
    )
    test.hint = listener.placeholder()
}

But it does not works, as you can see in the following image:

Mask is not applyed

However, when I hard code the signup fragment in the activity_main.xml file all works fine:

<fragment
    android:id="@+id/fragment"
    android:name="my.app.SignUpFragment"
    { omitted for sake of simplicity } />

mask is applyed

My question is: is there any plausible explanation for this "bug"? Am I making some confusion? How can I solve it?

Thanks for the help.

EDIT:

Same behavior for error messages. If I put this line of code:

test.error = "Error message"

using Android Navigation Component no error message is shown. However, if I hard code the fragment in the main activity layout, the error message is displayed.


Solution

  • Ok, after a lot of time spent in searching for answers, I found that my issue is related to the Android Data Binding Library. More specifically, I need to set listeners and the error message in the binding object created in the onCreateView of my SignUpFragment, as follows:

    private lateinit var binding: FragmentSignUpBinding
    
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_sign_up, container, false)
    
        // saving the instance of FragmentSignUpBinding
        binding = DataBindingUtil.setContentView(activity!!, R.layout.fragment_sign_up)
    
        binding.signupViewModel = signUpViewModel
    
        binding.lifecycleOwner = this
    
        setObservers()
    
        return view
    }
    

    then, in the onViewCreated:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    
        super.onViewCreated(view, savedInstanceState)
        MaskedTextChangedListener.installOn(
            binding.editCpf, // insted of simply edit_cpf
            "[000].[000].[000]-[00]",
            object : MaskedTextChangedListener.ValueListener {
                override fun onTextChanged(maskFilled: Boolean, extractedValue: String, formattedValue: String) {
                    Log.d("TAG", extractedValue)
                    Log.d("TAG", maskFilled.toString())
                }
            }
        )
    
    }
    

    and then it works fine.