开发者

onItemClick gives index/ position of item on visible page ... not actual index of the item in list ..issue on enabling setTextFilterEnabled

开发者 https://www.devze.com 2022-12-25 04:27 出处:网络
I am creating a list .. the elements of the list are drawn from sqlite database .. I populate the list using ArrayList and ArrayAdapter ...upon clicking the items on the list I want to be able to fire

I am creating a list .. the elements of the list are drawn from sqlite database .. I populate the list using ArrayList and ArrayAdapter ...upon clicking the items on the list I want to be able to fire an intent containing info about the item clicked ... info like the index number of the item ..

using the method: onItemClick(AdapterView av, View v, int index, long arg)

I do get index of the item clicked . however it is of the list currently displayed . the problem comes when I do setFilterTextEnabled(true) , and on the app type in some text to to search some item ..and then click it ..rather than giving me the index of the item on the original list it gives me the index on filtered list..

following is the snippet of code:

myListView.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> av, View v, int index, long arg) {
            Intent lyricsViewIntent = new Intent(iginga.this, LyricsPage.class);

            lyricsViewIntent.putExtra("title", songList.get((int)arg).getTitle());
            lyricsViewIntent.putExtra("id", songL开发者_如何学JAVAist.get((int)arg).getSongId());
            startActivity(lyricsViewIntent);
        }
    });

    myListView.setTextFilterEnabled(true);

Is there any way I can get the original index /position of the item instead of the one showing in filtered text ...when filtered.


I had a bit of a wrestle with this problem recently, and the solution turns out to be fairly simple. You can retrieve the "visible list" by using getListAdapter() on the ListActivity, which reflects the current filtered view of the list.

For example, in your ListActivity subclass's onCreate():

final ListView listView = getListView();
final ListAdapter listAdapter = getListAdapter();

listView .setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        MyClass item = (MyClass) listAdapter .getItem(position);
        // now do something with that item
    }
});

So, ignore the "original" list that you put into the list adapter, and instead ask for the list from the adapter each time the event comes in.


Abhinav I completely understand your problem as I have been struggling with the same issue for the past two days. I didn't realize the values of "int position" and "int id" change as you use the soft keyboard to filter data until I started using breakpoints on the debugger. Hope this code can give you a better idea of how to fix your issues. I ended up writing a for loop so that I could match the toString() of the filtered list with the toString() of the unfiltered list. This way I could retrieve/correct the "int position" value.

public class FacultyActivity extends ListActivity
{   
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        // Retrieves the array stored in strings.xml
        final String[] facultyList1 = getResources().getStringArray(R.array.professor_name);
        final String[] facultyList2 = getResources().getStringArray(R.array.professor_email);

        // Develop an array based on the list_view.xml template
        setListAdapter(new ArrayAdapter<String>(this, R.layout.faculty, facultyList1));
        final ListView lv = getListView();

        // Allow the user to filter the array based on text input
        lv.setTextFilterEnabled(true);

        // Handle the user event where the user clicks on a professor's name
        lv.setOnItemClickListener(new OnItemClickListener() 
        {
          public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
          {

              /* Filtering text changes the size of the array[index].  By clicking on a filtered 
               * entry the int position and long id does not correlate to the original array list.
               * This block of code will search the original array based on the toString() function
               * and for loop the orignial array to find the matching string, retrieving the 
               * correct index/position.
               */
              String name = lv.getItemAtPosition(position).toString();

              for (int index = 0; index < facultyList1.length; index++)
              {
                  if (name.equals(facultyList1[index]))
                  {
                      position = index;
                      break;
                  }
              }

              Bundle bundle = new Bundle();
              bundle.putString("email", facultyList2[position]);
              startActivity(new Intent(FacultyActivity.this, EmailActivity.class).putExtras(bundle)); 
          }
        });  
    }
}


One of the ways of doing this could be Tagging the view with its index when drawing them View#setTag() and reading them when ever you want with View#getTag()


I think that this is a bug that should be fixed: if you click (with the mouse) on entry number 150 for instance, you get back the name of entry 150 and an id of 150. But if you type in characters that give you entry 150 back and it's the first of three with the same characters you've typed in, you get back 0 and the name of entry 0 (which of course in your original list is not what you want). This should return the id and name for entry 150 if filtered and to have to do what abhinav did above (albeit, useful and worked for me), is kludgy in my not so humble opinion.


In Adapter class, override the following methods with the following code.

@Override
public long getItemId(int position) {       
    return position;
}

@Override
public int getPosition(StateFlower item) {
    return allItemsArray.indexOf(item);
}


@Override
public StateFlower getItem(int arg0) {
    return allItemsArray.get(arg0);
}


I just found a simple solution for this same problem. First question, in your adapter, are you using an ArrayList < String> or String[] ?
Try to create a class to hold the desired information.
And then, use ArrayList< DataHoldingClass > in your adapter.
For example :

public class DataHoldingClass {
private Integer id;
private String name;

     public DataHoldingClass(Integer id,String name){
       this.id=id;    
       this.name=name;
      }
       public Integer getDataId(){
         return id;
       }

      @Override
  public String toString() {
    return name;
  } 
 //implements getters and setters to name and other fields if you want

 }

Is necessary to override toString() method to adapter know what information show at the List. Then,somewhere in the code :

ArrayList< DataHoldingClass> info = new ArrayList<DataHoldingClass>();
  info.add( new DataHoldingClass(id,name) ) //here you populate the ArrayList with the desired informations to be showed at List


  adapter = new ArrayAdapter< DataHoldingClass>(context,
           android.R.layout.simple_dropdown_item_1line, info);`

And finnaly:

`@Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
Log.d(" arg2 ="+arg2+" arg3="+arg3+" Real id ="+((DataHoldingClass)arg0.getAdapter().getItem(arg2)).getDataId(),"");
}

It worked for me. Hope i helped you.


I spent hours trying to find a solution for this filter problem, so in case anyone else is struggling, this is a quick writeup of what worked for me.

Use some of the code from Arthur's answer:

      public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

          String name = lv.getItemAtPosition(position).toString();
          for (int index = 0; index < facultyList1.length; index++)
          {
              if (name.equals(facultyList1[index]))
              {
                  position = index;
                  break;
              }
          }
      }

and combine it with the best answer here to create this functional code within the same onItemClick:

            /* Filtering text changes the size of the array[index]. By clicking on a filtered
             * entry the int position changes, taking you to the details of food in the original
             * list's details. This block of code will take FoodsData, which contains all of the
             * textviews within a list item, and compare the contents of the chosen filtered list item
             * with every food name within foodsArray by using a loop, retrieving the correct index/position.

             * But this was the most important answer that helped me get it working in my code:
             * https://stackoverflow.com/questions/11164543/how-to-extract-objects-from-listview-getitematposition-wont-work
             */

            FoodsData chosenFilteredListItem = (FoodsData) (lv.getItemAtPosition(position));
            String chosenFilteredListItemFoodName = chosenFilteredListItem.getFoodName();

            for (int index = 0; index < foodsArray.length; index++)
            {
                if (chosenFilteredListItemFoodName.equals(foodsArray[index]))
                {
                    position = index;
                }
            }

As my comment within the code says, this takes the class called FoodsData, which describes the various textviews within a single list item, and compares the contents of the clicked list item with all the names in an array by using a for loop. This retrieves the correct position of the clicked item in the filtered search list, instead of incorrectly opening the details of the original list's item in the same position.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号