I'm using a ListView with sections. I have a list of ArrayAdapters, one for each section.
I need to determine the right adapter on onItemClick to launch a method in the adapter.
How do I do get a reference to the the right adapter?
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id)
{
adapterList.get(x).toggleBought(position);
//need to determine x (the x'th adapter in the list
//or somehow get a reference to the adapter instead of adapterList.get(x)
}
and here's the code where the adapterlist is created:
adapterList = new ArrayList<CartRowAdapter>(); //list of ArrayAdapters
oListAdapter = new CartListAdapter(getActivity()); //BaseAdapter
for (int i = 0; i < cartLists.size(); i++)
{
adapterList.add(new CartRowAdapter(getActivity(), R.layout.cart_row,
cartLists.get(i)));
oListAdapter.addSection(cartLists.get(i).get(0).getAisle(),
adapterList.get(i));
}
listView.setAdapter(oListAdapter);
The parent AdapterView is passed in as a parameter to onItemClick() and it has getAdapter().
I ended up fixing this by writing an ugly hack.
I had another by having the item position off since each section header also counted.
Also for the adapters the first item on each adapter is position 0, so I'm calculating that as well.
Although it's an ugly hack, at least it works perfectly for what I'm doing. i is the number I was looking for.
int i = 0;
int sizes = 0;
while (true)
{
sizes += cartLists.get(i).size();
position -= 1;
if (position < sizes)
{
position -= sizes;
position += cartLists.get(i).size();
break;
}
else
{
i++;
}
}
Related
Yes,I know there is position parametar in AdapterView.OnItemClickListener callback, but this parametar return position of filtered(shown) list.
For example I have _countriesEvisitor arraylist and I would like to get selected country object by looking into position like this:
public AdapterView.OnItemClickListener setOnCitizenshipAutocompleteItemClickListener(){
return (adapterView, view, position, id) -> {
CountryEvisitor citizenship=new CountryEvisitor();
citizenship=_countriesEvisitor.get(position);
_visit.setCitizenship(citizenship);
};
}
_countriesEvisitor has 250 items, and when I start typing for example Hrvatska I get only one item, and it has position 0 (because it is first and only one in shown list) although it is 247th in the _countriesEvisitor list from which list autocomplete adapter is made of.
How to get selected country?
Just use like below code.
public AdapterView.OnItemClickListener setOnCitizenshipAutocompleteItemClickListener(){
return (adapterView, view, position, id) -> {
CountryEvisitor citizenship= (CountryEvisitor ) view.getAdapter().getItem(position);
citizenship=_citizenship.getcitizenship();
_visit.setCitizenship(citizenship);
};}
Keep a second list with the original items, and search through the list matching your search result and get the index of that item
...
_countriesEvisitor.get(position);
int result = -1;
for(int x = 0; x < originalList.size; x++) {
if (/* some check here */) {
result = x;
break;
}
}
if (result != -1) {
// check if result is not -1 and use the index
}
I am facing issue in multiselect listview and issue i am facing was when i select the first item in the listview last item also checked while scrolling and this issue happens only if i have more that 10+ items in listview. I don't know what's wrong in my code and could any one suggest me a proper solution to avoid this problem.Thanks in advance
private class MultipleChoiceClickListener implements
ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
if (questionCount > 0) {
ImageView imgTick = (ImageView) view.findViewById(R.id.imgTick);
int len = lvMultiSelect.getCount();
checked = lvMultiSelect.getCheckedItemPositions();
for (int i = 0; i < len; i++) {
if (i == position) {
if (checked.get(i)) {
lvMultiSelect.getChildAt(i).setBackgroundColor(
getResources().getColor(
R.color.listitem_onclick));
imgTick.setImageResource(R.drawable.tick_img);
} else {
lvMultiSelect.getChildAt(i).setBackgroundColor(
getResources().getColor(
R.color.default_list_background));
imgTick.setImageResource(R.drawable.not_checked_img);
}
}
}
}
Create an object to store the position of all tags something like Integer array.
In your onItemClick, try this:
checked = view.getTag();
and once you select an item, do view.setTag(positions);. But nevertheless I suggest you, switch to RecyclerView if this codebase is new / you are doing it from scratch.
I have done this using RecyclerView Multiselect using Contextual Action Mode. Check this.
In my project I have class that extends ArrayAdapter<String> and implements SectionIndexer. When implementing methods getPositionForSection and getSectionForPosition I have found some strange behaviour.
Why section indexer works properly when getSectionForPosition returns 0?
public int getSectionForPosition(int position) {
return 0;
}
this implementation is used in many tutorials, for example:
http://androidopentutorials.com/android-listview-fastscroll/
http://www.survivingwithandroid.com/2012/12/android-listview-sectionindexer-fastscroll.html
Documentation says that
Given a position within the adapter, returns the index of the
corresponding section within the array of section objects.
so if my list have 5 items starting with letter "A" and some items starting with letter "B", then getSectionForPosition(5) should return 1.
While the basic functionality of the sectionIndexer (scrolling through the section indices when pulling the scrollbar thumb) is unaffected, returning a constant in the method getSectionForPosition can lead to a misbehaviour of the scrollbar positioning when swiping through the list (e.g. the scrollbar moving out of the window on the y-axis).
Apparently this misbehaviour only occurs when the list or single sections exceed a certain length, so for shorter lists the indexer might seem to work correctly (but in fact doesn't). I experienced this misbehaviour in larger lists when returning a constant in the above method several times and fixed it by implementing getSectionForPosition in a correct way.
However, since it might be interesting for others I can provide a sample implementation of that method. Let azIndexer be a HashMap containing a correct section -> position mapping of my indices and listItems be the items arranged by the adapter. The following builds a position -> sectionIndex mapping stored in positionIndexer.
List<Integer> values = new ArrayList();
for (int i : azIndexer.values()) {
values.add(i);
}
values.add(listItems.size()-1);
Collections.sort(values);
int k = 0;
int z = 0;
for(int i = 0; i < values.size()-1; i++) {
int temp = values.get(i+1);
do {
positionIndexer.put(k, z);
k++;
} while(k < temp);
z++;
}
which will then be used in the getSectionForPosition method:
#Override
public int getSectionForPosition(int position) {
return positionIndexer.get(position);
}
Your callback method getPositionForSection(int section) needs to be implemented to give the right position which is used by setSelection to return the right position where you want to scroll on touch of SectionIndexer on rightside.
Make sure you are doing this
this.setSelection(((SectionIndexer) getAdapter()) .getPositionForSection(currentPosition));
You need to implement two callback methods
#Override
public Object[] getSections() {
Log.d("ListView", "Get sections");
String[] sectionsArr = new String[sections.length()];
for (int i=0; i < sections.length(); i++)
sectionsArr[i] = "" + sections.charAt(i);
return sectionsArr;
}
This final callback and you are done here
#Override
public int getPositionForSection(int section){
Log.d("ListView", "Get position for section");
for (int i=0; i < this.getCount(); i++) {
String item = this.getItem(i).toLowerCase();
if (item.charAt(0) == sections.charAt(section))
return i;
}
return 0;
}
I have a listView that contains lots of elements i.e. we have to scroll down to see all the elements. Now what i want to do is, click all the listView elements. How can I do that. Right now,I am using the following code but it doesn't scroll automatically. Please help.
ListView l = solo.getCurrentListViews().get(0);
assertNotNull("No list views!", l);
assertTrue("No items in list view!", l.getChildCount() > 0);
// Get the last list item
View v = l.getChildAt(l.getChildCount());
System.out.println("getChildCount: " + l.getChildCount());
int i = 1;
while (i <= l.getChildCount()) {
solo.clickInList(i);
solo.goBack();
i++;
}
I have previously used these helper functions in a slightly different state to handle most of what we need with listviews:
public View getViewAtIndex(final ListView listElement, final int indexInList, Instrumentation instrumentation) {
ListView parent = listElement;
if (parent != null) {
if (indexInList <= parent.getAdapter().getCount()) {
scrollListTo(parent, indexInList, instrumentation);
int indexToUse = indexInList - parent.getFirstVisiblePosition();
return parent.getChildAt(indexToUse);
}
}
return null;
}
public <T extends AbsListView> void scrollListTo(final T listView,
final int index, Instrumentation instrumentation) {
instrumentation.runOnMainSync(new Runnable() {
#Override
public void run() {
listView.setSelection(index);
}
});
instrumentation.waitForIdleSync();
}
With these your method would be:
ListView list = solo.getCurrentListViews().get(0);
for(int i=0; i < list.getAdapter().getCount(); i++){
solo.clickOnView(getViewAtIndex(list, i, getInstrumentation()))
}
It looks like your code, as currently implemented, is only considering the visibile list items when controlling the loop and handling the clicking. It's important to note the behavior of two things:
First, there's a concept called view recycling in Android that helps conserve memory when dealing with ListViews. Only the views that are currently on screen are created, and once they scroll off the screen they'll be repopulated with new data. Therefore, calling methods like getChildCount and getChildAt on a ListView will only perform these operations on the visible items. To find information about the data that populates the list, you can call methods such as getCount() or getItem() on the ListView's adapter.
Second, the clickInList() method is 1-indexed, relative to the current position of the list, and can only be used for visible items. As far as I know, it will never scroll your list automatically. This means that calling clickInList(2) when at the top of the list will click the second item, but then calling clickInList(2) again when the 30th item is at the top of the list will click the 32nd.
Knowing these two things, your solution will need to consider all of the list data and perhaps have a bit more precision when making clicks. Here's how I'd rewrite your while loop to ensure you'll be able to handle every item on the list, hope this helps:
ListAdapter adapter = l.getAdapter();
for(int i=0; i < adapter.getCount(); i++)
{
//Scroll down the list to make sure the current item is visible
solo.scrollListToLine(l, i);
//Here you need to figure out which view to click on.
//Perhaps using adapter.getItem() to get the data for the current list item, so you know the text it is displaying.
//Here you need to click the item!
//Even though you're in a list view, you can use methods such as clickOnText(), which might be easier based on how your adapter is set up
solo.goBack();
}
It should help you(not tested):
public void clickAllElementsOnListView(int index) {
ListView listView = solo.getCurrentListViews().get(index);
count = listView.getAdapter() != null ? listView.getAdapter().getCount() : 0;
for (int i = 0; i < count; i++) {
scrollListToLine(listView, i);
solo.clickInList(1, index);
solo.goBack();
}
}
protected void scrollListToLine(final ListView listView, final int line) {
getInstrumentation().runOnMainSync(new Runnable() {
public void run() {
listView.setSelection(line);
}
});
}
I create the below code:
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View v, int position,
long id) {
for (int i = 0; i < mListView.getCount(); i++) {
View callLogView = mListView.getChildAt(i);
mRelativeLayout = (LinearLayout)callLogView.findViewById(R.id.myShow);
if(i == position){
if(mRelativeLayout.getVisibility() == View.GONE){
mRelativeLayout.setVisibility(View.VISIBLE);
}
else{
mRelativeLayout.setVisibility(View.GONE);
}
}else{
mRelativeLayout.setVisibility(View.GONE);
}
}
}
});
I want to realize a function like when i click one item of Listview, it will show a view, and the other items of Listview will be hidden. But mListView.getChildAt(i) will have the null pointer after exceed mListView.getChildCount().
How to solve this? Thanks in advance!
AdapterView.getCount() returns the number of data items, which may be larger than the number of visible views, that's why you are getting null pointer exception, because you are trying to find views which do not exist in the current visible ListView items.
To solve this issue you will first need to find the first visible item in the ListView using getFirstVisiblePosition() and the last visible item using getLastVisiblePosition(). Change the for loop condition as:
int num_of_visible_view=mListView.getLastVisiblePosition() -
mListView.getFirstVisiblePosition();
for (int i = 0; i < num_of_visible_view; i++) {
// do your code here
}
you can not implement this in onItemClick.
As you can access only visible child not all child.
What you can do is on onItemClick
you can send the position in adapter
and then set the logic there in getView too change view
and update the adapter in listview, or notify for changes.