Népszerű és mindenképp használatra javasolt komponens Androidon a ListView. Gyakorlatilag a legtöbbet használt UI elem, bárhmely programot használunk, rendszeresen feltűnik különböző formákban. Lényege, hogy a képernyőn megjelenő elemeket egy listába rendezzük, és ezt a listát görgethetjük le-fel ha nem fér ki minden elem a képernyőre. Használata relative egyszerű, amíg nem akarunk egyedi megjelenést, például Button vagyCheckbox komponenseket belerakni, mert ekkor azonnal beleütközünk a problémába, a ListView onItemClickevent handler nem hívódik meg kattintáskor.
Az Internet tele van a problémával, de teljes egészében leírt megoldást ritkán találni. Általában utalások vannak rá, hogy tároljunk ID-t a Tag mezőben, vagy írjuk át az Adapter-t, de mik is ezek az utalások tulajdonképpen?
A feladat amit kitaláltam egy olyan ListView megjelenítés, ami a SimpleAdaptert-t használja adatforrásnak, így a layout betölthető XML-ből egyszrűen. A layout tartalmaz egy gombot, amit megnyomva az Activity onClick metódusa hívódik meg. A probléma itt következik: az onClick az onItemClick-el ellentétben nem kapja meg melyik soron kattintottunk. Valahonnan pedig illene tudni, hiszen nem minden soron ugyanazt szeretnénk végrehajtani.
Az ötelt a fent amlített netes leírások alapján adja magát, tároljuk le az onClick-et meghívó View Tag-jében (View.setTag(Object o)) a szükséges azonosítót, így az onClick-ben a paraméterként megkapott View-tól le tudjuk kérdezni.
Minden ListView a lista elemeit egy Adapter osztálytól kapja (ListView.setAdapter()) a getView() metóduson keresztül. Az adapter kis átírásával megoldható, hogy a lista elemeibe bekerüljön a az Id a megfelelő Tag property-be, amikor a ListView meghívja a getView()-t. Leszármaztattam hát a SimpleAdaptert-t:
public class ClickableButtonListAdapter extends SimpleAdapter {
private static final String HASHMAP_ID = "_id";
public ClickableButtonListAdapter(Context context,
List<? extends Map<String, ?>> data, int resource, String[] from,
int[] to) {
super(context, data, resource, from, to);
}
@SuppressWarnings("unchecked")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
setViewTag(view, ((HashMap<String,String>) getItem(position)).get(HASHMAP_ID) );
return view;
}
private void setViewTag(View view, Object tag) {
view.setTag(tag);
if (view instanceof ViewGroup) {
for (int i=0; i < ((ViewGroup) view).getChildCount(); i++) {
setViewTag(((ViewGroup) view).getChildAt(i), tag);
}
}
}
}
A példában a lista elemei HashMap-ek, így ebből szedem ki az Id-t. A HahMap-ben az Id mező az “_id” elemben van, így ezt keresem ki, és rakom a Tag-be. A setViewTag() rekurzív metódus végigmegy az összes megjelenítendő View elemen és beállítja a Tag-et, így bármelyikre definiálhatjuk majd az onClick-et, mindig megkapjuk a Tag-ben a kiválasztott sor Id-ját.
Az Activity-ben az onClick() igen egyszerű:
public void onClick(View v) {
Toast.makeText(this, "onClick id: " + v.getTag(), Toast.LENGTH_SHORT).show();
}
Nem mondom, hogy szép megoldás, de használható. Jobban tetszene, ha az Android megfelelően támogatná az egyedi ListView létrehozását esetleg azzal, hogy az onItemClick meghívódna, és eldönthetném, hogy mit akarok kezdeni az eseménnyel.
Címkék: android, fejlesztés, java, Mobil
Hey, buddy. I’ve encountered the same problem recently.
Fortunately, I figured out the reason after checking the source code of android.
Because if the one child of ListView returns true when calling its “hasFocusable()” method, Android will ignore the click on the list item. Instead, Android will call the child’s or the child’s child etc. “onClick()” method, in order to make sure “Focusable” objects like Button will work properly.
If you have other problems, send email and let me know~ Peace~
Thank you very much, this is exactly what I was looking for!
I encountered the same problem recently.
I have solved the problem such that I used the listview position variable as setTag parameter.
Example:
public View getView(int position, View convertView, ViewGroup parent) {
view.setTag(position);
view.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String pos=v.getTag().toString();
Toast.makeText(Sehir.this, “clicked “+pos , 0).show();
}
});
}
Hi Guys,
I am having a problem here .
What I want is to have a button on every listview, and also when i click the button it will show a toast containing the writing on that specific view and do the same for every single one of them.
can someone help me please..
Thanks
I have had a similar problem: This hint could be useful:
=== part of OnCreate method of the ListActivity class ===
cursor = baza.rawQuery(“SELECT ClientName_id as _id, City, Street, HomeNr, ScanDate, Notes FROM Klienci ORDER BY ClientName_id”,null);
startManagingCursor(cursor);
adapter = new SimpleCursorAdapter(
this,
R.layout.list_name,
cursor,
new String[] { “_id”, “City”, “Street”, “HomeNr”, “ScanDate”, “Notes” },
new int[] { R.id.clientname, R.id.city, R.id.street, R.id.homenr, R.id.scanDate, R.id.notes });
this.setListAdapter(adapter);
ListView lv = getListView();
lv.setOnItemClickListener(
new OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
// When clicked, show a toast with the text of a TextView with id ‘clientname’
String txt = ((TextView)view.findViewById(R.id.clientname)).getText().toString();
Toast.makeText(getApplicationContext(), txt, Toast.LENGTH_SHORT).show();
}
});
Rest of the code should be clear. Cheers!
There is a much easier way to do the same.
In your ListAdapter getView method:
Button b = (Button) v.findViewById(R.id.myButton);
b.setId(item.getEntityValues().getAsInteger(“LIST_ID”));
My list items are Entity.
Define onClick event in your layout xml, and then in the Activity class in the onClick method:
public void buttonClick(View v) {
int myButtonID = v.getId();
}
For me works fine.
Thanks, I’m checking. First look I think it isn’t good because
ListAdapter.getView()will run on all list element which is on the screen sov.getId()will be the id of the last button not what you clicked.The point there is only one button in the memory and UI redraw it for all list element. You can’t use this button properties only it’s parent.
int myButtonID = v.getId()will return the last drawn button id not what you clicked.But I will check…