AdapterView.OnItemClickListener with more ListView - android

I have 2 ListView on a single fragment and I wonder if I can set for both same class that implements AdapterView.OnItemClickListener.
I mean, Android Documentation says:
public abstract void onItemClick (AdapterView<?> parent, View view, int position, long id)
Added in API level 1
Callback method to be invoked when an item in this AdapterView has been clicked.
Implementers can call getItemAtPosition(position) if they need to access the data associated with the selected item.
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.
So I suppose that I can choose different ListView that invoked onClick by Parent (AdapterView where click happened)..
Now how can I identify ListView? is there a way to swicth / case? or I need to create different class (can also be anonymous I know) that implements onItemClickListener and set to differents ListView differents AdapterView.onItemClickListener?

Ok I resolved:
private class myClass implements AdapterView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// TODO Auto-generated method stub
switch(parent.getId()) {
case R.id.listview1:
break;
case R.id.listview2:
break;
}
}
}

Related

Get id / position of ListView row

I have an Android ListView with a bunch of rows. Each row contains an image and some text. If I click on the image of a row, I want to perform action A, if I click on any other place in the row, I want to perform action B. Both of these actions need the id of the ListView item to work.
So far, for action B, I simply used listview's onItemClick, where I got the id from the parameter. However, as far as I know, the only way to find out on which view in the row itself the user clicked, is to add an onClick event handler to the ImageView that triggers action A. In that case, I only get the View that was clicked, though - not the id of the row that the ImageView is in.
My question is - how do I go from a View object to getting the id of the parent row within the ListView?
The onItemClickListener method has an onClick interface already with the view and position passed into it: You can get check which view has been clicked by doing a switch statement and performing a dedicated action when the specific view has been clicked.
E.g.
listView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
String item = listView.getItemAtPosition(position);
Toast.makeText(this,"You selected : " + item,Toast.LENGTH_SHORT).show();
}
});
as shown in How to create listview onItemclicklistener
You'll see that in the onItemClick interface it has the View view as a parameter and int position as a parameter, perform the action inside the listener using both of those parameters. Like i mentioned before you can use a switch statement.
listView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
String item = listView.getItemAtPosition(position);
switch(view.getId()) {
case R.id.imageView:
//perform action for imageView using the data from Item (if you have used an MVC pattern)
break;
// you can do this for any widgets you wish to listen for click actions
}
}
});
Update: All credit for this goes to wwfloyd in How to know which view inside a specific ListView item that was clicked
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.one_line, parent, false);
}
// This chunk added to get textview click to register in Fragment's onItemClick()
// Had to make position and parent 'final' in method definition
convertView.findViewById(R.id.someName).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((ListView) parent).performItemClick(v, position, 0);
}
});
// do stuff...
}
in your adapter apply a click listener to the element and then trigger the interface method, so that you can identify the registered widget that has been clicked and then in your onItemClick do:
public void onItemClick(AdapterView adapterView, View view, int position, long id) {
long viewId = view.getId();
switch (viewId) {
case R.id.someName:
//widget has been clicked
break;
default:
//row has been clicked
break;
}
}
if you aren't using tag, then you can
int itemId=...;
OnClickListener customOnClick=...;
imageView.setTag(itemId);
imageView.setOnClickListener(customOnClick);
and inside your custom OnClickListener
int itemId = (Integer) view.getTag();
note that you can set "any" Object as tag, so you may even set your whole custom object, not only id
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long id)
in this method View arg1 gives you Item view and you can find the item content by this arg1.findViewById(R.id.content);. Here position gives you the item position of list view
You can set click listeners for each view in a row from the getView() method in the adapter.
You can impliment it in getView() method of adapter of listview.

How can I handle onListItemClick(...) based on what view inside the row was clicked?

Question
I have a listView inside a DialogFragment and I want to fire certain callbacks only when certain particular items inside a row are fired. How can I do that?
Basically, I want to do something like this
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final int viewId = view.getId();
if ((viewId == R.id.textView1) || (viewId == R.id.textView2)) {
// do something...
}
which I can't. Read further if you don't know why.
What I tried
I tried to look into the documentation, but the OnItemClickListener callback doesn't offer as a parameter the exact clicked view (the View you can see in the signature is the whole row).
Also, I tried to set a simple onClick callback on the single view in the adapter, but this overrides the listSelector and other behavior a list should have. Reading in the documentation, I found it's explicitly written that we should set callbacks via the onListItemClick(...) method (not via onClick(...)), so I'm looking for a way to do that, using this method, not to override any default list behavior.
I was trying to get this done by working on the xml. To my surprise, I found that if I set a view android:clickable property to true, the onListItemClick callback won't fire (I thought it was the opposite),
so a partial solution would be to set to android:clickable=true every view in the row apart from the one I want to fire the callback, but that is not a solution because if the user clicks where there is padding or white space, the callback will fire. Also, I found that if I set the parent of the row's view to android:clickable=true and the child views I want to handle with the callback to android:clickable=false, this won't work, because apparently the property is not overwritten.
EDIT Sorry for the really bad title this question had before, I didn't even noticed I submitted the question.
new Answer, hope I understood now :)
In your adapters getView, attach an OnClickListener to any view in your layout you want to fire. (more pseudocode)
public class Adapter extends ArrayAdapter<XYZ> {
private int resource;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null) convertView = ((LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(this.resource, parent, false);
((Button)convertView.findViewById(R.id.YOUR_BUTTON_IN_LAYOUT)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
DOSTUFF();
}
});
return convertView ;
}
}
old Answer:
The position indicates where you are in the list (pseudocode).
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, final int position,long arg3) {
YOUR_ITEM_BACKED_BY_ADAPTER item = listView.getItemAtPosition(position);
if(item==THE_FIRST_ITEM_IN_LIST) doSomething();
else if(item == THE_LAST_ITEM_IN_LIST) doSomethingElse();
}
});
You can set listeners for other views inside the adapter's getView
public class MyAdapter extends ArrayAdapter<MyItem> implements View.OnClickListener {
public View getView(int position, View convertView, ViewGroup parent) {
// setup the converView inflating it, for simplicity I've removed that code
MyItem item = getItem(position);
text1 = (TextView)convertView.findViewById(R.id.text1);
text2 = (TextView)convertView.findViewById(R.id.text2);
text1.setOnClickListener(this);
// pass the item to use when clicked
text1.setTag(item);
text2.setOnClickListener(this);
text2.setTag(item);
}
public void onClick(View v) {
MyItem item = v.getTag();
switch (v.getId()) {
case R.id.text1:
download(item);
break;
case R.id.text2:
upload(item);
break;
}
}
}
Instead of hardcoding action (eg download) inside the adapter you can pass to it an interface and for example the calling activity can implement that interface

android OnItemLongClickListener listview to display listview checkboxes

I would like to create an android app which displays a list in a listview and then allow the user to delete an item when on onItemlongclick and then displays checkboxes to select which items to delete.
I know it have to call the OnItemLongClickListener but do not know how to implement that. Any ideas to do this?
lv.setOnItemLongClickListener(this);
#Override
public boolean onItemLongClick(AdapterView<?> parent, View v, int pos, long id) {
// TODO Auto-generated method stub
return false;
}
I'm so lost in ideas how to do this. I googled but unfortunately didn't find any relevant tutorials.
Help is much appreciated. Thanks.
I did this just recently, but it was an ad hoc fix, so this might not be the best way.
In the layout for my ListView items (rows), I included a CheckBox whose visibility will be toggled, but is initially not visible, i.e., View.GONE.
Then, in my Adapter, I included a member boolean variable, selectable, and a public method to set it and refresh:
private boolean selectable = false;
public void setSelectable(boolean selectable)
{
this.selectable = selectable;
notifyDataSetChanged();
}
In the getView() method of the Adapter, selectable is checked and the CheckBox's visibility is set accordingly.
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
...
cbx.setVisibility(selectable ? View.VISIBLE : View.GONE);
...
}
I used a ToggleButton to change the selection mode, but in your case, you'll need to do something a little different. I would add an additional method to the Adapter:
public boolean isSelectable()
{
return selectable;
}
Then, you can toggle the selectable state on long clicks:
#Override
public boolean onItemLongClick(AdapterView<?> parent, View v, int pos, long id)
{
...
yourAdapter.setSelectable(!yourAdapter.isSelectable);
...
}
To respond to clicks on list items, you need to put this in onCreate():
ListView lv = (ListView) findViewById (R.id.list);
lv.setOnItemLongClickListener (this);
lv.setLongClickable (true);
Then, onItemLongClickListener will be called whenever the user long-touches a list item. Put a breakpoint there and be satisfied you understand this much.

OnItemClickListener on a ListView inside a Fragment not working

EDIT: SOLVED. If there's anything focusable in the XML of the items, it will break the touch of the list, in other words, android:focusable=false to all the checkboxes, switches or anything like that of ur list. And done =)
Ok so, here's my problem.
I wrote a app that uses tabs and fragments, and it all goes the way I want except for the thing that when I try to capture a onItemClick on a listView it does not even mark the row as touched/pressed/selected.
I've been reading a little bit about and many people have the same issue, but I did not found any responses that helped me at all.
I don't want to implement a ListFragment, in fact I don't even know how/why I should, and since all my code is already working, I don't know if implementing one will give me much more work to do, so, here it is:
Is it possible to implement a listener for a click on a listView, inside a fragment? and if it is, HOW?
PD: minSDK=14, tatgetSDK=15
Just put
android:focusable="false"
android:clickable="false"
in layout.
For all textviews,buttons etc.
Here's a code snippet that'll do what you want.
ListView lv;
//code to get the listView instance using findViewByID etc
lv.setOnItemClickListener(new OnItemClickListener()
{
#Override public void onItemClick(AdapterView<?> arg0, View arg1,int position, long arg3)
{
Toast.makeText(EnclosingActivity.this, "Stop Clicking me", Toast.LENGTH_SHORT).show();
}
});
People usually trip on this, see if you have got this covered:
All clicks and call backs (eg: the menu/actionbar callbacks) are sent to the activity the fragment is bound to, so they must be in the activity class and not the fragment class.
This may be helpful
Answer by raghunanadan in below link solved my problem
listview OnItemClick listner not work in fragment
Add this to the layout
android:descendantFocusability="blocksDescendants"
Two awesome solutions were this, if your extending ListFragment from a fragment, know that mListView.setOnItemClickListener wont be called before your activity is created, As #dheeraj-bhaskar implied. This solution ensured it is set when activity has been created
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
mListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) {
// Do the onItemClick action
Log.d("ROWSELECT", "" + rowId);
}
});
}
While looking at the source code for ListFragment, I came across this
public class ListFragment extends Fragment {
...........................................
................................................
final private AdapterView.OnItemClickListener mOnClickListener
= new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
onListItemClick((ListView)parent, v, position, id);
}
};
.................................................................
........................................................................
public void onListItemClick(ListView l, View v, int position, long id)
{
}
}
An onItemClickListener object is attached and it calls onListItemClick()
As such the other similar solution, which works in the exact same way is to override onListItemClick()
#Override
public void onListItemClick(ListView l, View v, int position, long rowId) {
super.onListItemClick(l, v, position, id);
// Do the onItemClick action
Log.d("ROWSELECT", "" + rowId);
}
Here is an overview of the workflow, create your ListView and it's corresponding Adapter(used to map your underlying data to the items in the ListView), set the adapter to the ListView, and then add an OnItemClickListener to it.
More details and sample code can be found at: http://developer.android.com/guide/topics/ui/declaring-layout.html#AdapterViews
If you want to pass data from fragment to any activity on Listview click then you can modify your code like...
class HistoryFragment extends Fragment { ListView historyListView;
public HistoryFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v= inflater.inflate(R.layout.fragment_history, container, false);
historyListView= (ListView) v.findViewById(R.id.historyDataListView);
sendRequest(); //it is my meathod to load the listview and set the adapter
return v;
}
public void onStart() {
super.onStart();
historyListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Intent intent=new Intent(getActivity(), DisplayDetails.class);
intent.putExtra("text", historyListView.getItemAtPosition((int) l).toString());
startActivity(intent);
// Toast.makeText(getActivity(),"Hello.. "+historyListView.getItemAtPosition((int) l).toString(),Toast.LENGTH_LONG).show();
}
});
}}
the button will affect the listener, try avoid using button and re compile,
it should work

How can I eliminate the dependency from of a ListView's onItemClick/getView and its row types?

As a simplified example, consider a ListView that can contain both sub-categories and book titles. If a book title is clicked, a new activity should start that shows the cover image. If a sub-category is clicked, a new list of books and categories is displayed.
A Row interface is defined as follows.
interface Row {
void onClick();
void draw(View v);
}
I would like to know how to prevent a dependency from the ListView's ArrayAdapter as well as from the implementer of onItemClickListener on the Row implementers (e.g.,Book and Category).
One of the forces driving this requirement is the "don't repeat yourself" (DRY) principle: the ArrayAdapter implementation does not need to change when new row types are introduced.
Forgive my chicken-scratched "UML" below, but here's how I do it.
class ListAdapter extends ArrayAdapter<Row<?>> {
...
public View getView(int position, View convertView, ViewGroup parent) {
View view = listViewRowViewRecycler.getView(convertView);
rowProvider.get().getRow(position).draw(view);
return view;
}
}
The implementer of OnItemClickListener has a method like this:
void onItemClick(AdapterView<?> adapterView, View view, int rowIndex, long rowId)
{
rowProvider.onItemClick(rowIndex);
}
Then RowProvider has a method like this:
void onItemClick(int rowIndex) {
rowList.get(rowIndex).onClick();
}
Then the Row interface has a method with signature void onClick() and there are Category and Book implementations of Row that provide the necessary behavior.
Another possibility is to use the setTag/getTag methods on each item's View in the list - this allows you to attach the 'Book' or 'Category' to its appropriate row.
For this to work each of the 'listed' items should implement a common interface that has an appropriate method to be called when it is clicked.
For instance:
interface Selectable {
void onSelected(); // Add parameters if necessary...
}
In your list adapter:
public View getView(int position, View convertView, ViewGroup parent) {
View itemView; // Logic to get the appropriate view for this row.
Selectable theObjectBeingRepresented;
//
// Logic to assign a Book/Category, etc to theObjectBeingRepresented.
// In this example assume there is a magic Book being represented by
// this row.
//
Book aMagicBook = new Book();
theObjectBeingRepresented = aMagicBook;
// If all objects that will be contained in your list implement the
// 'Selectable' interface then you can simply call setTag(...) with
// the object you are working with (otherwise you may need some conditional logic)
//
itemView.setTag( SELECTABLE_ITEM_KEY, theObjectBeingRepresented );
}
Then when an item is clicked:
void onItemClick(AdapterView<?> adapterView, View view, int rowIndex, long rowId)
{
Selectable item = (Selectable)view.getTag( SELECTABLE_ITEM_KEY );
// Depending on how you are populating the list, you may need to check for null
// before operating on the item..
if( null != item ) {
item.onClick(); // Appropriate implementation called...
}
}
A bit more detail on the setTag method:
setTag documentation
Hope this helps...

Categories

Resources