Focusable EditText inside ListView

后端 未结 13 2351
无人共我
无人共我 2020-11-21 23:56

I\'ve spent about 6 hours on this so far, and been hitting nothing but roadblocks. The general premise is that there is some row in a ListView (whether it\'s g

相关标签:
13条回答
  • 2020-11-22 00:12

    Sorry, answered my own question. It may not be the most correct or most elegant solution, but it works for me, and gives a pretty solid user experience. I looked into the code for ListView to see why the two behaviors are so different, and came across this from ListView.java:

        public void setItemsCanFocus(boolean itemsCanFocus) {
            mItemsCanFocus = itemsCanFocus;
            if (!itemsCanFocus) {
                setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
            }
        }
    

    So, when calling setItemsCanFocus(false), it's also setting descendant focusability such that no child can get focus. This explains why I couldn't just toggle mItemsCanFocus in the ListView's OnItemSelectedListener -- because the ListView was then blocking focus to all children.

    What I have now:

    <ListView
        android:id="@android:id/list" 
        android:layout_height="match_parent" 
        android:layout_width="match_parent"
        android:descendantFocusability="beforeDescendants"
        />
    

    I use beforeDescendants because the selector will only be drawn when the ListView itself (not a child) has focus, so the default behavior needs to be that the ListView takes focus first and draws selectors.

    Then in the OnItemSelectedListener, since I know which header view I want to override the selector (would take more work to dynamically determine if any given position contains a focusable view), I can change descendant focusability, and set focus on the EditText. And when I navigate out of that header, change it back it again.

    public void onItemSelected(AdapterView<?> listView, View view, int position, long id)
    {
        if (position == 1)
        {
            // listView.setItemsCanFocus(true);
    
            // Use afterDescendants, because I don't want the ListView to steal focus
            listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            myEditText.requestFocus();
        }
        else
        {
            if (!listView.isFocused())
            {
                // listView.setItemsCanFocus(false);
    
                // Use beforeDescendants so that the EditText doesn't re-take focus
                listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
                listView.requestFocus();
            }
        }
    }
    
    public void onNothingSelected(AdapterView<?> listView)
    {
        // This happens when you start scrolling, so we need to prevent it from staying
        // in the afterDescendants mode if the EditText was focused 
        listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
    }
    

    Note the commented-out setItemsCanFocus calls. With those calls, I got the correct behavior, but setItemsCanFocus(false) caused focus to jump from the EditText, to another widget outside of the ListView, back to the ListView and displayed the selector on the next selected item, and that jumping focus was distracting. Removing the ItemsCanFocus change, and just toggling descendant focusability got me the desired behavior. All items draw the selector as normal, but when getting to the row with the EditText, it focused on the text field instead. Then when continuing out of that EditText, it started drawing the selector again.

    0 讨论(0)
  • 2020-11-22 00:12

    This helped me.
    In your manifest :

    <activity android:name= ".yourActivity" android:windowSoftInputMode="adjustPan"/>
    
    0 讨论(0)
  • 2020-11-22 00:12

    In my case, there is 14 input edit text in the list view. The problem I was facing, when the keyboard open, edit text focus lost, scroll the layout, and as soon as focused view not visible to the user keyboard down. It was not good for the user experience. I can't use windowSoftInputMethod="adjustPan". So after so much searching, I found a link that inflates custom layout and sets data on view as an adapter by using LinearLayout and scrollView and work well for my case.

    0 讨论(0)
  • 2020-11-22 00:14

    This saved my life--->

    1. set this line

      ListView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

    2. Then in your manifest in activity tag type this-->

      <activity android:windowSoftInputMode="adjustPan">

    Your usual intent

    0 讨论(0)
  • 2020-11-22 00:15

    Another simple solution is to define your onClickListener, in the getView(..) method, of your ListAdapter.

    public View getView(final int position, View convertView, ViewGroup parent){
        //initialise your view
        ...
        View row = context.getLayoutInflater().inflate(R.layout.list_item, null);
        ...
    
        //define your listener on inner items
    
        //define your global listener
        row.setOnClickListener(new OnClickListener(){
            public void onClick(View v) {
                doSomethingWithViewAndPosition(v,position);
            }
        });
    
        return row;
    

    That way your row are clickable, and your inner view too :)

    0 讨论(0)
  • 2020-11-22 00:15

    I just found another solution. I believe it's more a hack than a solution but it works on android 2.3.7 and android 4.3 (I've even tested that good old D-pad)

    init your webview as usual and add this: (thanks Michael Bierman)

    listView.setItemsCanFocus(true);
    

    During the getView call:

    editText.setOnFocusChangeListener(
        new OnFocusChangeListener(View view,boolean hasFocus){
            view.post(new Runnable() {
                @Override
                public void run() {
                    view.requestFocus();
                    view.requestFocusFromTouch();
                }
         });
    
    0 讨论(0)
提交回复
热议问题