AndroidDev
AndroidDev

Reputation: 21247

actionNext Won't Scroll to Reveal the Last TextInputLayout

I have a ConstraintLayout that contains 8 TextInputLayout fields, each in a vertical orientation (like a vertical LinearLayout). Each has this line in its TextInputEditText:

android:imeOptions="actionNext"

The constraint layout is contained in a NestedScrollView.

This is supposed to act as a simple form to capture registration data. As the user finishes each field, they tap the Next button and the form scrolls vertically to the next field.

This all works fine until the user finishes the second to last field. At that point, when the user taps next, the form neither scrolls nor does it give the focus to the final field. That field is hidden behind the soft keyboard so the user does not know it is there. I can manually scroll the form to reveal it, but that is not the behavior that I am trying to achieve.

Here is the relevant parts of the xml:

Activity:

<androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <fragment
        android:id="@+id/onboarding_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:defaultNavHost="false"
        app:navGraph="@navigation/onboarding_nav_graph" />

</androidx.core.widget.NestedScrollView>

And then in the fragment, here are the last two TextInputLayouts. The others follow a similar structure, so I'm omitting them, at least for now, for brevity:

<com.google.android.material.textfield.TextInputLayout
            android:id="@+id/password_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            app:errorTextAppearance="@style/error_appearance"
            app:layout_constraintTop_toBottomOf="@id/cell_layout"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintWidth_percent="0.8"
            app:passwordToggleEnabled="true"
            app:passwordToggleTint="@color/colorAccent"
            style="@style/MyTextInputLayout">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/reg_password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/enter_password"
                android:maxLines="1"
                android:inputType="textPassword"
                android:imeOptions="actionNext"
                android:text="@{registrationData.password}"
                bind:regularTypeface='@{"raleway"}'
                style="@style/MyTextInputEditText"/>

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

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/password_confirm_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            app:errorTextAppearance="@style/error_appearance"
            app:layout_constraintTop_toBottomOf="@id/password_layout"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintWidth_percent="0.8"
            app:passwordToggleEnabled="true"
            app:passwordToggleTint="@color/colorAccent"
            style="@style/MyTextInputLayout">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/reg_password_confirm"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/password_confirmation"
                android:maxLines="1"
                android:inputType="textPassword"
                android:imeOptions="actionDone"
                bind:regularTypeface='@{"raleway"}'
                style="@style/MyTextInputEditText"/>

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

Finally, in the AndroidManifest, the activity is declared like this:

<activity
    android:name=".activities.OnboardingActivity"
    android:theme="@style/AppTheme.NoActionBar"
    android:windowSoftInputMode="adjustResize"/>

Cannot figure out what I am missing. How can I get the scroll view to reveal the last field without the user having to scroll the field manually?

Upvotes: 2

Views: 407

Answers (1)

AndroidDev
AndroidDev

Reputation: 21247

I figured out what the issue was. Notice that the last two TextInputLayout fields were for passwords, and the app:passwordToggleEnabled are set to true on both.

Given this state, when the Next button gets tapped on the first TextInputEditText field (reg_password), I expected that the next object to take the focus would have been reg_password_confirm. But when I turned on Show Layout Bounds in the emulator settings and examined it closely, what I noticed was that the object that had the focus was the toggle to the right of reg_password (the icon shaped like an eye).

The fix is very simple. Instead of android:imeOptions="actionNext in the reg_password block, I used android:nextFocusForward="@id/reg_password_confirm". This overrides the algorithm and explicitly switches the focus to reg_password_confirm.

That also results in the scroll view moving down to reveal that TextInputLayout field.

I hope this helps someone.

Upvotes: 2

Related Questions