Rob Droid
Rob Droid

Reputation: 173

Android Lollipop Soft Keyboard Hides User Inputs in DialogFragment

I am writing my first real Android application. I have an Android DialogFragment that I am displaying to allow users to add or edit details of a selected item. The DialogFragment pops up and displays fine in full screen mode. However, on the Lollipop emulator when I click on EditText widgets that are lower on the screen, the soft keyboard covers up the widget, rather than scrolling the screen up so that the user may see what they are typing. I do NOT experience this behavior in the pre-Lollipop emulator. On the KitKat emulator, the screen adjusts so that the EditText is still visible. StackOverflow will not let me post pictures yet. So, you'll have to use your imagination. :-( I have tried different ways to overcome this issue. Unfortunately, none have worked for Lollipop.

UPDATE - I have tested this on a Sony Xperia Z3 Compact running Android 5.0.2, and the DialogFragment does not scroll or adjust the screen when selecting the lower EditText widgets.

Here are the styles in use:

<!-- Base application theme. -->
<style name="AppTheme" parent="AppTheme.Base">
    <!-- Customize your theme here. -->
</style>

<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:textColorPrimary">@color/colorPrimaryText</item>
    <item name="android:textColorSecondary">@color/colorSecondaryText</item>
    <item name="android:dialogTheme">@style/DialogTheme</item>
    <item name="android:actionBarStyle">@style/AppActionBarTheme</item>
    <item name="actionBarStyle">@style/AppActionBarTheme</item>"
    <item name="actionBarTheme">@style/AppActionBarTheme</item>
    <item name="actionBarPopupTheme">@style/AppActionBarOverflowMenuTheme</item>
    <item name="windowActionModeOverlay">true</item>
</style>

<style name="DialogTheme" parent="Theme.AppCompat.Light.Dialog">
    <item name="android:clickable">true</item>
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowSoftInputMode">stateHidden|adjustResize</item>
    <item name="windowActionModeOverlay">true</item>
</style>

As you can see in the DialogTheme, I have included the android:windowSoftInputMode attribute. I have also tried using that attribute in the AndroidManifest.xml file under the Activity that ultimately contains the DialogFragment. Here is the XML layout file for the DialogFragment:

<?xml version="1.0" encoding="utf-8"?>
<com.ahappydevelopment.android.fishtales.views.LogEditView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="@dimen/dialog_margin_top"
    android:background="@color/background_material_light"
    android:theme="@style/DialogTheme">

    <include
        android:id="@+id/app_bar"
        layout="@layout/app_bar_edit" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/app_bar">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="@dimen/activity_vertical_margin"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingRight="@dimen/activity_horizontal_margin"
            android:paddingTop="@dimen/activity_vertical_margin">

            <Button
                android:id="@+id/btnCatchDate"
                style="?android:attr/borderlessButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:textAllCaps="false" />

            <Button
                android:id="@+id/btnCatchTime"
                style="?android:attr/borderlessButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_alignParentTop="true"
                android:textAllCaps="false" />

            <EditText
                android:id="@+id/editLatitudeLabel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_below="@id/btnCatchDate"
                android:ems="10"
                android:hint="@string/label_latitude"
                android:inputType="numberDecimal" />


            <EditText
                android:id="@+id/editLongitudeLabel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_below="@id/editLatitudeLabel"
                android:ems="10"
                android:hint="@string/label_longitude"
                android:inputType="numberDecimal" />

            <ImageView
                android:id="@+id/imgCatchPicture"
                android:layout_width="75dp"
                android:layout_height="75dp"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_alignTop="@id/editLatitudeLabel"
                android:background="@android:color/darker_gray"
                android:contentDescription="@string/imgcatchpicture_contentdescription"
                android:scaleType="centerInside"
                android:src="@android:drawable/ic_menu_camera" />

            <Spinner
                android:id="@+id/spinnerLocation"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_below="@id/editLongitudeLabel" />

            <TextView
                android:id="@+id/txtFishHeader"
                style="?android:attr/listSeparatorTextViewStyle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_below="@id/spinnerLocation"
                android:text="@string/section_fish" />

            <Spinner
                android:id="@+id/spinnerSpeciesType"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_below="@id/txtFishHeader" />

            <EditText
                android:id="@+id/editLengthLabel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_below="@id/spinnerSpeciesType"
                android:ems="5"
                android:hint="@string/hint_length"
                android:inputType="numberDecimal" />

            <EditText
                android:id="@+id/editWeightLabel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_below="@id/spinnerSpeciesType"
                android:ems="5"
                android:hint="@string/hint_weight"
                android:inputType="numberDecimal" />

            <EditText
                android:id="@+id/editLengthLabel2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_below="@id/editLengthLabel"
                android:ems="5"
                android:hint="@string/hint_length"
                android:inputType="numberDecimal" />

            <EditText
                android:id="@+id/editWeightLabel2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_below="@id/editWeightLabel"
                android:ems="5"
                android:hint="@string/hint_weight"
                android:inputType="numberDecimal" />

        </RelativeLayout>

    </ScrollView>

</com.ahappydevelopment.android.fishtales.views.LogEditView>

As you can see, my layout does include a ScrollView. I have even defined the android:theme="@style/DialogTheme" in the layout. I have tried setting android:fillViewport="true" on the ScrollView, as I saw in another StackOverflow posting.

On the Java side of things, I have an override for the onCreateDialog method defined as such:

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Dialog dialog = new Dialog(getActivity(), R.style.DialogTheme);
    //set to adjust screen height automatically, when soft keyboard appears on screen
    dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
    return dialog;
}

The Fragment that initiates the DialogFragment has a method that looks like this:

public void addLogButtonOnClickEvent() {
    LogEditFragment addLog = LogEditFragment.get(0l);
    if(mIsLargeLayout) {
        // The device is using a large layout, so show the fragment as a dialog
        addLog.show(getFragmentManager(), "AddLog");
    } else {
        // The device is smaller, so show the fragment fullscreen
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        // For a little polish, specify a transition animation
        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        // To make it fullscreen, use the 'content' root view as the container
        // for the fragment, which is always the root view for the activity
        transaction.add(android.R.id.content, addLog).addToBackStack(null).commit();
    }
}

As I said, this is working fine for the KitKat emulator. This is NOT working for the Lollipop emulator. You can see that I am trying very hard to get the DialogFragment to do adjust resize. :-) Does anyone see what I am missing or doing wrong? Also, if there is code that I have neglected to include that would help to find a solution, the please let me know, and I will post that as well. Thank you for any insight you can provide.

Upvotes: 2

Views: 1320

Answers (1)

Rob Droid
Rob Droid

Reputation: 173

It took a while before I discovered this answer. I had actually refactored my DialogFragment to be an AppCompatActivity. I then began to think that perhaps the Navigation Drawer set up for Android Lollipop was perhaps to blame for the problems I was experiencing with the DialogFragment. My MainActivity layout file for API level 21 and above uses a DrawerLayout widget with a ScrimInsetsFrameLayout for the Navigation Drawer view. So, both the DrawerLayout and the ScrimInsetsFrameLayout utilize android:fitsSystemWindows="true" in their definition as part of achieving the Material Design UI specification for a Navigation Drawer. That android:fitsSystemWindows="true" in the DrawerLayout definition was interfering with the android:windowSoftInputMode="stateHidden|adjustResize" defined for the MainActivity in the AndroidManifest.xml file to cause the dialog to adjust and resize when the soft keyboard is launched. Here is the XML layout of the MainActivity:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <!-- The Main Content View -->
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <include
            android:id="@+id/app_bar"
            layout="@layout/app_bar_main" />

        <FrameLayout
            android:id="@+id/fragment_main_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/app_bar" />

    </RelativeLayout>

    <!-- The Navigation Drawer View -->
    <com.ahappydevelopment.android.fishtales.widgets.ScrimInsetsFrameLayout
        android:id="@+id/scrimInsetsFrameLayout"
        android:layout_width="@dimen/navigation_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:elevation="10dp"
        android:fitsSystemWindows="true"
        app:insetForeground="#4000">

        <FrameLayout
            android:id="@+id/fragment_drawer_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </com.ahappydevelopment.android.fishtales.widgets.ScrimInsetsFrameLayout>

</android.support.v4.widget.DrawerLayout>

When telling the FragmentManager to add the DialogFragment, I was using the android.R.id.content as the view container, which is prescribed by the documentation. By experimenting with which view container to use, I was able to find one that gave the expected results. In my case, it is the DrawerLayout view defined in the MainActivity layout file.

LogEditFragment addLog = LogEditFragment.get(0l);
if(mIsLargeLayout) {
    // The device is using a large layout, so show the fragment as a dialog
    addLog.show(getFragmentManager(), "AddLog");
} else {
    // The device is smaller, so show the fragment fullscreen
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    // For a little polish, specify a transition animation
    transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    // To make it fullscreen, use the 'drawer_layout' view 
    // as the container for the fragment
    transaction.add(R.id.drawer_layout, addLog).addToBackStack(null).commit();
}

Once I had made these changes and refactored my LogEditFragment class to once again extend DialogFragment, both the dialog and the navigation drawer behaved as expected.

Upvotes: 3

Related Questions