Search code examples
androidkeyboardandroid-edittextgrid-layout

setNextFocusDownId(...) Not Doing as Expected


I am attempting to add multiple EditTexts to a GridLayout and want to be able to specify which EditText is focused when the user clicks the "Next" button on the keyboard.

I thought this was going to be as simple as setting the setNextFocusDownId(...) method on the each EditText but unfortunately this doesn't seem to work.

My Layout file simply consists of a GridLayout with an EditText at the bottom:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <android.support.v7.widget.GridLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:grid="http://schemas.android.com/apk/res-auto"

        android:id="@+id/Grid"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"
        grid:columnCount="2">

    </android.support.v7.widget.GridLayout>

    <EditText
        android:id="@+id/Last"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="Last"/>
</LinearLayout>

And the code in my MainActivity.java file dynamically adds 10 EditTexts and attempts to assign the 'NextFocus' appropriately:

public class MainActivity extends AppCompatActivity
{
    final Context context = this;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        GridLayout grid = (GridLayout) findViewById(R.id.Grid);
        int N=10;
        grid.setRowCount((N+1)/2);

        EditText prev = null;

        for (int i=0 ; i<N ; i++)
        {
            EditText t = new EditText(context);
            t.setInputType(InputType.TYPE_CLASS_TEXT);
            t.setMaxLines(1);
            t.setHint("" + i);
            grid.addView(t);

            if (prev != null)
                prev.setNextFocusDownId(t.getId());

            prev = t;
        }
    }
}

This does indeed create a grid with two columns of 5 elements however, clicking in the top cell and clicking Next arrow (">") on the keyboard takes you down a row rather then to the expected "NextFocused" ExitText.

Starting in the '0th' cell the "next" button takes you successively through the 'default' sequence: '0' > '2' > '4' > '6' > '8' > "Last" (rather than the expected '0' > '1' > '2' > ... > '9' > "last").

Interestingly though, setting the NextFocused to findViewById(R.id.Last).getId() (instead of t.getId()) does cause focus to jump to "Last" from every cell in the grid. Any idea why this isn't working for t.getId().

The answer to this question seems to suggest simply setting 'setNextFocusDownId(...)' should do the trick however it's not working for me. Is there something different about accessing ID's of dynamically created View's that is different from XML defined Views that I don't quite understand?

Thanks, Slarti.


Solution

  • Huh-harr, worked it out!

    I didn't realise it but when a view is created dynamically it's ID is always created with a value if '-1'. One can however assign an ID to a view using the View's setId(int). From API level 17 onward one can generate an ID to use for this purpose using generateViewId() but prior to API 17 you have to come up with your own ID. Fortunately, according to this post, R.id... values are all greater than 0x00FFFFFF, so simply creating dynamic ID's by counting up from '0' should keep you well clear of the previously defined values.

    Therefor, adding the line t.setId(i); as soon as the TextView is created in the example above resolves the problem nicely.

    For another well answered question regarding dynamically assigned ID check out this question.

    Cheers, Slarti.