androidandroid-textinputlayoutandroid-motionlayoutandroid-textinputedittext

TextInputLayout crash measure and focus when animating (MotionLayout)


Have MotionLayout, which has many ConstraintLayout inside him, some of the ConstraintLayout has TextInputLayout.

1-when using android studio XML design preview: on starter "ideal/landing" state no error, when I start animating to ConstraintLayout(start showing the view) which has TextInputLayout inside him, The view crash and render problem appears, with onMeasure error (details: java.lang.NullPointerException)

2-When I run the app (real device): animation work fine and no error but the problem is: TextInputLayout does not focus(at all) on tap/click and the keyboard appears normally, when I try to force focus like spamming taps/clicks nothing happens, but when I use the keyboard to write some text, the text appears inside TextInputLayout but no focus at all, after that if I tap/click again (after some text is written), TextInputLayout get focus.

fragment XMl file:

<androidx.constraintlayout.motion.widget.MotionLayout
    android:id="@+id/secondProfileLayout"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_marginTop="@dimen/my25dp"
    app:layoutDescription="@xml/fragment_dashboard_profile_scene"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintHorizontal_chainStyle="spread"
    app:layout_constraintTop_toBottomOf="@id/user_access">


    <androidx.constraintlayout.widget.ConstraintLayout
    >
      this ConstraintLayout 1
   
    </androidx.constraintlayout.widget.ConstraintLayout>

    <androidx.constraintlayout.widget.ConstraintLayout
    >
     this ConstraintLayout 2

    </androidx.constraintlayout.widget.ConstraintLayout>

    <androidx.constraintlayout.widget.ConstraintLayout 
    >

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/my35dp"
            android:layout_marginTop="@dimen/my10dp"
            android:layout_marginEnd="@dimen/my35dp"
            android:hint="@string/worker_code"
            app:errorContentDescription="@string/wrong_code"
            app:errorEnabled="false"
            app:hintAnimationEnabled="true"
            app:hintEnabled="true"


           layout_constraint...
            >

            <com.google.android.material.textfield.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:imeOptions="actionDone"
                android:importantForAutofill="auto"
                android:inputType="text" />

        </com.google.android.material.textfield.TextInputLayout>


    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.motion.widget.MotionLayout>

Java Code: not interesting, only this 2 line: 1- bind.motionLayout.transitionToEnd(); 2- bind.textLayoutInput.getEditText().getText().toString();

Note: when I remove TextInputEditText from TextLayoutInput ( leave it empty), no error appears (no render problem), maybe the problem related to TextInputEditText.

Note2: if I remove this attrs from TextLayoutInput:

app:errorContentDescription="@string/wrong_code"
app:errorEnabled="false"
app:hintAnimationEnabled="true"
app:hintEnabled="true"

this problem appears, in addition, to render problem on measure error:

java.lang.NullPointerException
at android.content.res.Resources_Delegate.getResourceInfo(Resources_Delegate.java:144)
at android.content.res.Resources_Delegate.getResourceName(Resources_Delegate.java:743)
at android.content.res.Resources.getResourceName(Resources.java:2064)
at androidx.constraintlayout.widget.ConstraintLayout.setChildrenConstraints(ConstraintLayout.java:1170)
at androidx.constraintlayout.widget.ConstraintLayout.updateHierarchy(ConstraintLayout.java:1143)
at androidx.constraintlayout.widget.ConstraintLayout.onMeasure_Original(ConstraintLayout.java:1703)
at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java)
at android.view.View.measure_Original(View.java:24552)
at android.view.View_Delegate.measure(View_Delegate.java:80)
at android.view.View.measure(View.java:24516)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure_Original(View.java:24552)
at android.view.View_Delegate.measure(View_Delegate.java:80)
at android.view.View.measure(View.java:24516)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:735)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:481)
at android.view.View.measure_Original(View.java:24552)
at android.view.View_Delegate.measure(View_Delegate.java:80)
at android.view.View.measure(View.java:24516)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure_Original(View.java:24552)
at android.view.View_Delegate.measure(View_Delegate.java:80)
at android.view.View.measure(View.java:24516)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.measureView(RenderSessionImpl.java:638)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.doLayout(RenderSessionImpl.java:406)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.renderAndBuildResult(RenderSessionImpl.java:546)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.render(RenderSessionImpl.java:449)
at com.android.layoutlib.bridge.BridgeRenderSession.render(BridgeRenderSession.java:123)
at com.android.ide.common.rendering.api.RenderSession.render(RenderSession.java:143)
at com.android.ide.common.rendering.api.RenderSession.render(RenderSession.java:125)
at com.android.tools.idea.rendering.RenderTask.lambda$null$11(RenderTask.java:966)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1604)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

Images: after animation end and I tap/click the TextInputEditText one time

after one tap, I try to force write with no focus but the text is written

after some text is written, I tap again and I get focus

if I delete the text, focus lose and we back to the start of the problem

Update

after some test and try to figure solution, found a solution for the Render error "onmeasure()", but it is not effective (crash steal exists if I use the old code), but the TextInputLayout does not receive focus at all.

Note: TextinputLayout is a child of ConstraintLayout with id 'second_layout'

The animation was simple Left to Right transition, this is my old MotionLayout layout Description looks like:

    <Transition
    android:id="@+id/transition_a_to_b"
    motion:constraintSetEnd="@id/b_end"
    motion:constraintSetStart="@id/b_start"
    motion:duration="200" />

<ConstraintSet android:id="@+id/b_start">
    <Constraint
        android:id="@id/first_layout"
        android:layout_width="0dp"
        android:layout_height="0dp"

        motion:layout_constraintHeight_default="percent"
        motion:layout_constraintHeight_percent="1"
        motion:layout_constraintStart_toStartOf="parent"
        motion:layout_constraintWidth_default="percent"
        motion:layout_constraintWidth_percent="1" />


    <Constraint
        android:id="@id/second_layout"
        android:layout_width="0dp"
        android:layout_height="0dp"

        motion:layout_constraintEnd_toStartOf="parent"
        motion:layout_constraintHeight_default="percent"
        motion:layout_constraintHeight_percent="1"
        motion:layout_constraintWidth_default="percent"
        motion:layout_constraintWidth_percent="1" />
</ConstraintSet>

<ConstraintSet android:id="@+id/b_end">
    <Constraint
        android:id="@id/first_layout"
        android:layout_width="0dp"
        android:layout_height="0dp"

        motion:layout_constraintHeight_default="percent"
        motion:layout_constraintHeight_percent="1"
        motion:layout_constraintStart_toEndOf="parent"
        motion:layout_constraintWidth_default="percent"
        motion:layout_constraintWidth_percent="1" />

   
    <Constraint
        android:id="@id/second_layout"
        android:layout_width="0dp"
        android:layout_height="0dp"

        motion:layout_constraintHeight_default="percent"
        motion:layout_constraintHeight_percent="1"
        motion:layout_constraintStart_toStartof="parent"
        motion:layout_constraintWidth_default="percent"
        motion:layout_constraintWidth_percent="1" />
</ConstraintSet>

the Solution is to change the transition from Left to Right to Right To Left, so i just changed the code to be like this:

   <Transition
    android:id="@+id/transition_a_to_b"
    motion:constraintSetEnd="@id/b_end"
    motion:constraintSetStart="@id/b_start"
    motion:duration="200" />

<ConstraintSet android:id="@+id/b_start">
    <Constraint
        android:id="@id/first_layout"
        android:layout_width="0dp"
        android:layout_height="0dp"

        motion:layout_constraintHeight_default="percent"
        motion:layout_constraintHeight_percent="1"
        motion:layout_constraintStart_toStartOf="parent"
        motion:layout_constraintWidth_default="percent"
        motion:layout_constraintWidth_percent="1" />


    <Constraint
        android:id="@id/second_layout"
        android:layout_width="0dp"
        android:layout_height="0dp"

        motion:layout_constraintStart_toEndOf="parent"
        motion:layout_constraintHeight_default="percent"
        motion:layout_constraintHeight_percent="1"
        motion:layout_constraintWidth_default="percent"
        motion:layout_constraintWidth_percent="1" />
</ConstraintSet>

<ConstraintSet android:id="@+id/b_end">
    <Constraint
        android:id="@id/first_layout"
        android:layout_width="0dp"
        android:layout_height="0dp"

        motion:layout_constraintHeight_default="percent"
        motion:layout_constraintHeight_percent="1"
        motion:layout_constraintEnd_toStartOf="parent"
        motion:layout_constraintWidth_default="percent"
        motion:layout_constraintWidth_percent="1" />

   
    <Constraint
        android:id="@id/second_layout"
        android:layout_width="0dp"
        android:layout_height="0dp"

        motion:layout_constraintHeight_default="percent"
        motion:layout_constraintHeight_percent="1"
        motion:layout_constraintStart_toStartof="parent"
        motion:layout_constraintWidth_default="percent"
        motion:layout_constraintWidth_percent="1" />
</ConstraintSet>

after many hours of attempts to solve this problem(crash), the problem was generated by TextInputEditText, because if i remove it from TextInputLayout the old animation work normally.

finally, Iam using the latest versions of androidX, material Design and constraintLayout


Solution

  • The Problem

    TextInputLayout will not be drawn properly so will not receive the focus, The reason is the Constraint of his parent (Constraint of ConstraintSet of Transition).

    Note: my animation is in-animation, and secound_layout is the parent of TextInputLayout.

    // This Constraint is child of ConstraintSet of end transition
    <Constraint
        android:id="@id/second_layout"
    
        // attrs are correct but the problem generated by them
        // this is attrs are the problem of bad drawn
        ​
       ​android:layout_width="0dp"
       ​android:layout_height="0dp"
    
       ​motion:layout_constraintStart_toStartof="parent"
       ​
       ​// this is attrs are the problem of bad drawn
       ​motion:layout_constraintHeight_default="percent"
       ​motion:layout_constraintHeight_percent="1"        
       ​motion:layout_constraintWidth_default="percent"
       ​motion:layout_constraintWidth_percent="1" />
    

    The Solution

    use:

    android:layout_width="match_parent
    android:layout_height="match_parent"
    

    in Constraint of the parent of TextInputLayout, in start or end ConstraintSet of the transition(depend on your situation).

    So if your animation is "IN" set Constraint of the parent width & height to "match_parent" in ConstraintSet of the end, Or if the animation is "OUT", set Constraint of the parent width & height to "match_parent" in ConstraintSet of start.

    In my situation, The parent of TextInputLayout is "second_layout" and the animation is "IN", so the width and height Constraint of "second_layout" in the ConstraintSet of end should be set to "match_parent". The code will be :

        <Transition
        android:id="@+id/transition_a_to_b"
        motion:constraintSetEnd="@id/b_end"
        motion:constraintSetStart="@id/b_start"
        motion:duration="200" />
    
    <ConstraintSet android:id="@+id/b_start">
        <Constraint
            android:id="@id/first_layout"
            android:layout_width="0dp"
            android:layout_height="0dp"
    
            motion:layout_constraintHeight_default="percent"
            motion:layout_constraintHeight_percent="1"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintWidth_default="percent"
            motion:layout_constraintWidth_percent="1" />
    
    
        <Constraint
            android:id="@id/second_layout"
            android:layout_width="0dp"
            android:layout_height="0dp"
    
            motion:layout_constraintStart_toEndOf="parent"
            motion:layout_constraintHeight_default="percent"
            motion:layout_constraintHeight_percent="1"
            motion:layout_constraintWidth_default="percent"
            motion:layout_constraintWidth_percent="1" />
    </ConstraintSet>
    
    <ConstraintSet android:id="@+id/b_end">
        <Constraint
            android:id="@id/first_layout"
    android:layout_width="0dp"
            android:layout_height="0dp"
    
            motion:layout_constraintHeight_default="percent"
            motion:layout_constraintHeight_percent="1"
            motion:layout_constraintEnd_toStartof="parent"
            motion:layout_constraintWidth_default="percent"
            motion:layout_constraintWidth_percent="1"
            
        />
    
       
        <Constraint
            android:id="@id/second_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </ConstraintSet>
    

    This problem should be informed to Material Design Team because the problem exists in the other implementation.