Issues focusing EditTexts in a ListView (Android)
Asked Answered
A

2

7

I have a ListView with a few EditTexts in each item. I have no issues with a hardware keyboard, but things freak out a bit with the soft keyboard. I have two issues.

  1. When I first click on an EditText, it briefly appears to have focus but then loses focus once the keyboard has shown. I must then click the EditText again to get focus.
  2. When an EditText with focus is scrolled out of view, focus goes to... well... see the screenshot. I'm not sure what's happening.

More details on #1:

  • When the screen first loads, focus is in the "Gr High School Scale" field, but the keyboard is not shown.
  • If I immediately click on a desired EditText, its OnFocusChangeListener tells me that it receives focus and then loses focus. Visually, I see the cursor appear in the field, but when the keyboard loads the cursor jumps away (like in the screenshot) and I don't know where focus has gone.

I've played around a bit the Focusable and DescendantFocusability attributes of the ListView, but to no avail. Any advice?

Each time an EditText with focus gets scrolled out of view, another drunk cursor shows up: enter image description here

UPDATE: Relevant code.
Activity layout with ListView XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res/com.NsouthProductions.gradetrackerpro"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.NsouthProductions.gradetrackerpro.Activity_EditCourseGPA" >

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="34dp"
    android:text="Define the GPA and Percent scale for this course." />

<RadioGroup
    android:id="@+id/radioGroup1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_below="@+id/textView1"
    android:layout_marginLeft="5dp" >

    <LinearLayout
        android:id="@+id/linlay_rad_group_existing_scale"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <RadioButton
            android:id="@+id/radio0_existing_scale"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="0"
            android:checked="true"
            android:text="Existing Scale" />

        <Spinner
            android:id="@+id/spinner_existing_scales"
            android:layout_width="wrap_content"
            android:layout_height="33dp"
            android:layout_gravity="right"
            android:layout_weight="1" />

    </LinearLayout>

    <LinearLayout
        android:id="@+id/linlay_rad_group_new_scale"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <RadioButton
            android:id="@+id/radio1_new_scale"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="0"
            android:text="New Scale" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:lines="1"
            android:maxLines="1"
            android:text=" " />

        <EditText
            android:id="@+id/editText1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:inputType="textPersonName"
            android:maxLines="1"
            android:scrollHorizontally="true"
            android:text="Gr High School Scale" >

            <requestFocus />
        </EditText>

    </LinearLayout>
</RadioGroup>


 <LinearLayout
    android:id="@+id/linlay_scale_save_buttons"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true" >

    <Button
        android:id="@+id/btn_gpa_cancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

    <Button
        android:id="@+id/btn_gpa_save"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

</LinearLayout>

 <ListView
     android:id="@+id/listview_scale"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_above="@id/linlay_scale_save_buttons"
     android:layout_alignParentLeft="true"
     android:layout_below="@id/radioGroup1"
     android:focusable="true"
     android:focusableInTouchMode="true"
     android:headerDividersEnabled="true"
     android:scrollingCache="true" >

 </ListView>

List Items XML:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linlay_scale_list_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >

        <CheckBox
                android:id="@+id/checkbox_scale_item"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="A-" />

            <EditText
                android:id="@+id/et_gpa"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:enabled="true"
                android:inputType="numberDecimal"
                android:maxLength="6"
                android:text="4.000" />

            <EditText
                android:id="@+id/et_min"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:enabled="true"
                android:inputType="numberDecimal"
                android:maxLength="6"
                android:text="94.75" />

            <EditText
                android:id="@+id/et_max"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:inputType="numberDecimal"
                android:maxLength="6"
                android:text="100.0" />

Setting the view in my adapter:

View v = convertView;
ViewHolder holder;

    v = inflater.inflate(R.layout.scale_list_item, 
    holder = new ViewHolder();
    holder.cb = (CheckBox) v.findViewById(R.id.checkbox_scale_item);
    holder.et_gpa = (EditText) v.findViewById(R.id.et_gpa);
    holder.et_min = (EditText) v.findViewById(R.id.et_min);
    holder.et_max = (EditText) v.findViewById(R.id.et_max);

I'm not sure what else to post. I have focus and textChange listeners, but the problem exists even if those are commented out. Let me know if anything else is needed. Thank you.

More detail about how focus is behaving when the EditText is touched:

  1. The EditText is clicked (touched)
  2. EditText Receives focus
  3. EditText loses focus
  4. ListView gains focus (and tries to set child focus view requestChildFocus... doesn't seem to succeed).
  5. ListView loses focus
  6. ListView gains focus (and tries to set child focus again).

The above is based on having listeners for both the EditText and the ListView. Note: with a hardware keyboard, the EditText gets focus and that's that. I think the soft keyboard appearing affects the focus.

FINAL UPDATE: In the end, working with the ListView was too difficult, especially because I wanted to update multiple rows based on changes to an EditText in one row. That's hard to do when the keyboard is up and the ListView only considers a few of the rows to exist at any one time.

I instead made nested LinearLayouts. Each horizontal layout was a "row" and I put them inside of an ArrayList in order to manage them and it was a piece of cake, comparatively (still not easy).

Amazement answered 23/10, 2014 at 0:10 Comment(3)
@Elltz, Which part of the code would you like to see?Amazement
xml and java..jux the portion handling the edittextYolandoyolane
@Elltz, I have updated with code. Let me know if anything else is needed. Thanks for looking at this.Amazement
C
6

You are facing ListView recycling issue. When you scroll up or down or when keyboard appears ListView again refreshes and lost your EditText's focus. So, first of all read this answer to understand ListView Recycling mechanism and then follow the suggestion from my side the solution of your current scenario in my mind.

I suggest you should use a Button on ListView Item and text of this button should be generic like Enter Student Info or what ever you'd like. After clicking on this Button open AlertDialog and set your xml view (currently your all edittexts like et_gpa, et_min, et_max etc on listview items)

For Example:

btnInfo.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {

                showStudentInfoAlert();

}

});

public void showStudentInfoAlert() 
    {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);

       LayoutInflater in = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

View v = in.inflate(R.layout.your_xml_having_edittexts, null);

EditText et_gpa = (EditText) v.findViewById(R.id.et_gpa);

//add all edit texts like this and after that just set view on alert dialog

        builder.setTitle("Enter student's info");

        builder.setView(v);

        builder.setPositiveButton("Save", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {

               //save all edittexts values and do what erver you want with those values 

            }
        });

        dialog.show();
    }
Canaanite answered 23/10, 2014 at 4:34 Comment(3)
This helped me understand the issue much better. The more I wrestle with it, the more I feel I should not use a dynamic view. My list will always be the same length. I used a ListView mainly because I knew they could be tied to ArrayLists. Is there another view that works similarly with ArrayLists that doesn't do any of this recycling or resizing? I'd rather just scroll my entire activity.Amazement
I ended up abandoning the ListView and going with a bunch of LinearLayouts that I put into an array to manage. It was much easier since the length of my list is static. I'll choose this as the best answer as it helped me understand what I was up against with the ListView.Amazement
Same here, could not get a reliable behavior with ListView. The EditTexts keep losing/taking focus multiple times. There is no recycling going on so I don't know why this happens. Anyway I think for not huge lists LinearLayout is just fine.Shirlyshiroma
Y
2

first of all when the screen loads,, focus is on the "Gr High School Scale" field, because of this <requestFocus /> in your xml. but this does no gurantee that the keyboard might show.. to make the keyboard to show use getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); also i am thinking that it looses focus immediately because the listview has taken focus away from the edittext

<ListView
 android:id="@+id/listview_scale"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_above="@id/linlay_scale_save_buttons"
 android:layout_alignParentLeft="true"
 android:layout_below="@id/radioGroup1"
 android:focusable="true" //this
 android:focusableInTouchMode="true" // and that
 android:headerDividersEnabled="true"
 android:scrollingCache="true" >

, and since none of your listview edittext is asking for focus,, the focus stays on just the listview not the edittext..so you need to re-surface the focus back to the edittext..also from the android documentation it states By default the user can not move focus to a view;.. and also it states that "if focusableInTouchMode is true for a view, that view can gain focus when clicked on, and can keep focus if another view is clicked on that doesn't have this attribute set to true. " mostly when you first create an edittext it automatically adds <requestFocus /> to it specifying that it needs to take focus, or it can take focus..but in your case and with this documentaion the edittext will never keep focus because listview is taking it away from him.. so in short try this on all views(including your edittext) you want to take focus like you did on the listview

android:focusable="true" 
android:focusableInTouchMode="true" 

so try that on the edittext and let me know if it helps..thanks for waiting

Yolandoyolane answered 23/10, 2014 at 2:45 Comment(2)
I really appreciate the help. I've verified that all views have true focusable attributes and I've removed <requestFocus/> where it shouldn't be, but I get the same results. I've tried setting the ListView's onFocusChangeListener to give a child focus, but haven't had any luck. Oddly, I find that the ListView loses and regains focus twice. See my edits above.Amazement
Also, this only happens when the soft keyboard is in use. With a physical keyboard, focus goes to the EditText and that's the end of the story. I think they showing of the soft keyboard is doing something.Amazement

© 2022 - 2024 — McMap. All rights reserved.