69

I have listview with custom adapter (base adapter). I want to get view from listview by position. I tried mListView.getChildAt(position) , but it is not working. How can i get item view by position?

alashow
  • 2,495
  • 3
  • 17
  • 44
  • 4
    You need to explain what "not working" means in your situation. Also post the relevant code which isn't working and any error messages you might have. – codeMagic Jul 17 '14 at 19:13
  • 2
    get view like this `listView.getChildAt(pos - listView .getFirstVisiblePosition());` – AZ_ Apr 15 '15 at 03:17

6 Answers6

253

Use this :

public View getViewByPosition(int pos, ListView listView) {
    final int firstListItemPosition = listView.getFirstVisiblePosition();
    final int lastListItemPosition = firstListItemPosition + listView.getChildCount() - 1;

    if (pos < firstListItemPosition || pos > lastListItemPosition ) {
        return listView.getAdapter().getView(pos, null, listView);
    } else {
        final int childIndex = pos - firstListItemPosition;
        return listView.getChildAt(childIndex);
    }
}
VVB
  • 6,526
  • 7
  • 39
  • 71
  • 6
    Please add header count: final int childIndex = pos + getHeaderViewsCount() - firstListItemPosition; – iwind Nov 16 '14 at 17:22
  • @iwind Can you plz elaborate why to add this? – VVB Nov 17 '14 at 04:47
  • 1
    @RIT If the ListView has header views, child will start from header views. So ItemChildIndex= HeadersCount + ItemPosition. – iwind Nov 17 '14 at 10:12
  • 6
    When you pass null to getView method, you will force it to create a new view, it won't use the already existing one. – frankish Jan 20 '15 at 08:05
  • This line is useless it will never run `if (pos < firstListItemPosition || pos > lastListItemPosition ) { return listView.getAdapter().getView(pos, null, listView);` – AZ_ Apr 15 '15 at 03:18
  • Perfect answer. Got the perfect position when scrolling. – Pankaj Aug 18 '15 at 08:03
  • And use it by: `ImageView bak = (ImageView) getViewByPosition(wantedPos, listView).findViewById(R.id.gas_gauge);` – Iman Marashi Mar 30 '16 at 15:31
  • Perfection incarnate, thank you so much! I used this on a `ListView` for an `ArrayList` which had my view in the adapter class, so it was not accessible from the `MainActivity`. – Azurespot May 16 '16 at 02:54
  • 2
    perhaps i'm not understanding the question... but he seems to be looking for a childview within the list view item by position... so onItemClick(AdapterView>) adapter, View v, int pos, long id){ VIEWTYPE mView = (VIEWTYPE) v.findViewById(R.id.desiredview)}... maybe he is asking for a non-user interaction approach? – me_ Dec 15 '16 at 12:29
  • @C0D3LIC1OU5 That built in way is `getChildAt` which is a part of the `ListView`. It seemed like you were trying to imply that answer was some roundabout way to avoid a `ClickListener` when there was no indication in the question that a click was even being issued. There is no need to be rude about it. – Abandoned Cart May 16 '19 at 14:32
14

You can get only visible View from ListView because row views in ListView are reuseable. If you use mListView.getChildAt(0) you get first visible view. This view is associated with item from adapter at position mListView.getFirstVisiblePosition().

Matt Twig
  • 354
  • 1
  • 6
4

Preferred way to change the appearance/whatever of row views once the ListView is drawn is to change something in the data ListView draws from (the array of objects that is passed into your Adapter) and make sure to account for that in your getView() function, then redraw the ListView by calling

notifyDataSetChanged();

EDIT: while there is a way to do this, if you need to do this chances are doing something wrong. While are few edge cases I can think about, generally using notifyDataSetChanged() and other built in mechanisms is a way to go.

EDIT 2: One of the common mistakes people make is trying to come up with their own way to respond to user clicking/selecting a row in the ListView, as in one of the comments to this post. There is an existing way to do this. Here's how:

mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    /* Parameters
    parent:     The AdapterView where the click happened.
    view:       The view within the AdapterView that was clicked (this will be a view provided by the adapter)
    position:   The position of the view in the adapter.
    id:         The row id of the item that was clicked. */
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        //your code here
    }
});

ListView has a lot of build-in functionality and there is no need to reinvent the wheel for simpler cases. Since ListView extends AdapterView, you can set the same Listeners, such as OnItemClickListener as in the example above.

C0D3LIC1OU5
  • 8,018
  • 2
  • 35
  • 43
  • 2
    You are extremely wrong my friend :) You can get the child by providing the id of child on which click is performed, the following line will return you child on which click is performed. Once you get that child you can change whatever you want and then you need to call `refreshDrawableState()` on that view to update it :) `listView.getChildAt(pos - listView .getFirstVisiblePosition());` – AZ_ Apr 15 '15 at 03:15
  • There is no need to do that if all you want is to get the view on which user clicked. See edits to the post. – C0D3LIC1OU5 Jul 16 '15 at 19:27
  • Please provide link to the post to see! – AZ_ Jul 17 '15 at 06:38
  • Look at the EDIT 2 of my answer – C0D3LIC1OU5 Jul 17 '15 at 14:14
  • I am socked how many people are down voting this. I am going to include questions that explore this and similar ListView functionality on coding interviews to be able to screen them out! – C0D3LIC1OU5 Mar 24 '16 at 14:44
  • 1
    Your answer is very good. Just doesn't answers my question exactly. In fact, your answer is more accurate. I mean, changing view state/style by getting item view is wrong. If you change item view state/style by getting item view, changes will be gone in next redraw/scroll. I'm sorry that people misunderstand you and down voting you for this. – alashow Jun 08 '16 at 22:01
  • `notifyDataSetChanged()` might cause lose of click events from UI elements within each row. This is annoying user experience as touch is not as excepted some times. If there is no event handler attached to any element of the row, and that's fine. But this is not an efficient way for updating just one element. – albert Mar 16 '17 at 04:15
2
workignHoursListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent,View view, int position, long id) {
        viewtype yourview=yourListViewId.getChildAt(position).findViewById(R.id.viewid);
    }
});
Geshode
  • 2,498
  • 5
  • 15
  • 24
Mohamed Ayed
  • 417
  • 5
  • 7
0

This is the Kotlin version of the function posted by VVB. I used it in the ListView Adapter to implement the "go to next row first EditText when Enter key is pressed on the last EditText of current row" feature in the getView().

In the ListViewAdapter class, fun getView(), add lastEditText.setOnKeyListner as below:

lastEditText.setOnKeyListener { v, keyCode, event ->
    var setOnKeyListener = false
    if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
        try {
            val nextRow = getViewByPosition(position + 1, parent as ListView) as LinearLayout
            val nextET = nextRow.findViewById(R.id.firstEditText) as EditText
            nextET.isFocusableInTouchMode = true
            nextET.requestFocus()
        } catch (e: Exception) {
            // do nothing
        }
        setOnKeyListener = true
    }
    setOnKeyListener
}

add the fun getViewByPosition() after fun getView() as below:

private fun getViewByPosition(pos: Int, listView: ListView): View? {
    val firstListItemPosition: Int = listView.firstVisiblePosition
    val lastListItemPosition: Int = firstListItemPosition + listView.childCount - 1
    return if (pos < firstListItemPosition || pos > lastListItemPosition) {
        listView.adapter.getView(pos, null, listView)
    } else {
        val childIndex = pos + listView.headerViewsCount - firstListItemPosition
        listView.getChildAt(childIndex)
    }
}
-4
Listview lv = (ListView) findViewById(R.id.previewlist);

    final BaseAdapter adapter = new PreviewAdapter(this, name, age);

    confirm.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub


            View view = null;

            String value;
            for (int i = 0; i < adapter.getCount(); i++) {

                view = adapter.getView(i, view, lv);

                Textview et = (TextView) view.findViewById(R.id.passfare);


                value=et.getText().toString();

                 Toast.makeText(getApplicationContext(), value,
                 Toast.LENGTH_SHORT).show();
            }



        }
    });
arjun
  • 1
  • 3