0

I'm building an Android application using ListView. I have list view items as show below.

List Item Index 0

^ List Item Index 0

List Item Index 1

^ List Item Index 1

The xlm is as follows.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="4dip" >

    <ImageView
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:src="@drawable/icon" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_weight="0.93"
        android:orientation="vertical"
        android:padding="10dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp" >

        <!-- JFN bottom used to be 2, top 6 -->
        <!-- Name Label -->

        <TextView
            android:id="@+id/name"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="0dip"
            android:paddingTop="0dip"
            android:textColor="#43bd00"
            android:textSize="16sp"
            android:textStyle="bold" />
        <!-- Email label -->

        <TextView
            android:id="@+id/email"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="0dip"
            android:textColor="#acacac" />

        <!-- Mobile number label -->

        <TextView
            android:id="@+id/mobile"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="left"
            android:text="Mobile: "
            android:textColor="#5d5d5d"
            android:textStyle="bold" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="right"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/chat"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_marginRight="2dip"
            android:gravity="right"
            android:src="@drawable/chat" />

        <ImageView
            android:id="@+id/calendar"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_marginRight="2dip"
            android:gravity="right"
            android:src="@drawable/calendar" />
    </LinearLayout>

</LinearLayout>

I'm trying to detect four different click events:

  1. When the picture of the dog is clicked
  2. When the middle section is clicked
  3. When the chat button is clicked
  4. When the calendar button is clicked

In addition, each of these clicks must be distinguishable based on which item in the ListView has been clicked.

I know how I can tell each ListItem apart: I can use the ListView.setOnItemClickListener as is shown below, which provides an id of the item in the list. But this does not tell me which of the four portions was clicked on.

ListView lv = getListView();

// Listview on item click listener
lv.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view,
            int position, long id) {
        // getting values from selected ListItem
        Log.d("JFN","List item clicked with id: "+id);
    }
});

I can also bind a different onClick function call to each of the four sections in the xml, but this doesn't let me know which of the list items was clicked.

android:onClick="imgClicked"

I don't think I can combine these two solutions, as it would introduce a race condition. Is there a proper way to accomplish detecting both which list item was clicked, and which part of that particular list item was clicked?

Further Info

The following code shows my creation of the ListView using the adapter.

// Retrieve string, convert to JSON, and extract contacts
String jsonData = jsonToStringFromAssetFolder("maemployees.json",this);
JSONObject jsonObj = new JSONObject(jsonData).getJSONObject(TAG_RESULTS);
int numContacts = jsonObj.getInt(TAG_NUM);
Log.d("JFN","Number of contacts stated: "+numContacts);
contacts = jsonObj.getJSONArray(TAG_CONTACTS);
Log.d("JFN","Number of contacts present: "+contacts.length());
// Loop over contacts
for( int i=0; i<contacts.length(); i++) {
    // Extract this one
    JSONObject c = contacts.getJSONObject(i);

    // Extract strings
    String first = (c.has(TAG_FIRST)) ? c.getString(TAG_FIRST) : "";
    String last = (c.has(TAG_LAST)) ? c.getString(TAG_LAST) : "";
    String city = (c.has(TAG_CITY)) ? c.getString(TAG_CITY) : "";
    String state = (c.has(TAG_STATE)) ? c.getString(TAG_STATE) : "";
    String country = (c.has(TAG_COUNTRY)) ? c.getString(TAG_COUNTRY) : "";
    String costName = (c.has(TAG_COST_NAME)) ? c.getString(TAG_COST_NAME) : "";

    // Temporary hash map for single contact
    HashMap<String, String> contact = new HashMap<String, String>();
    contact.put("name", first+" "+last);
    contact.put("email", city+", "+state+", "+country);
    contact.put("mobile", costName);

    // Adding single contact to list
    contactList.add(contact);
}
Log.d("JFN","Done looping contacts");
//Updating parsed JSON data into ListView
ListAdapter adapter = new SimpleAdapter(
        MainActivity.this, contactList,
        R.layout.list_item, new String[] { "name", "email",
                "mobile" }, new int[] { R.id.name,
                R.id.email, R.id.mobile });
setListAdapter(adapter);
jfaghihnassiri
  • 523
  • 1
  • 4
  • 16

3 Answers3

1

You must be setting the content of your list view in an Adapter, So inside the adapter, there is a method getView(). Inside that getView() define each of your view and then set onCLickListener inside those view.

For Ex:

dog.setOnClickListener(new OnClickListener() {      
    @Override
    public void onClick(View v) {
       //operation to be performed.
    }
});

similarly apply onCLickListeners() to all other views.

SMR
  • 6,628
  • 2
  • 35
  • 56
Anchit Mittal
  • 3,412
  • 4
  • 28
  • 48
  • I'll try this, I assume I do this in the same loop I use to populate the list, correct? – jfaghihnassiri Jan 29 '14 at 04:39
  • yup, the onClickListener() for each item is put up in the same method – Anchit Mittal Jan 29 '14 at 04:45
  • I'm a little lost, where do I retrieve the information regarding which item from the list (the list contains multiple collections of the four areas) has been selected using this approach. Am I declaring these four listeners within the listener I included in the question: lv.setOnItemClickListener(new OnItemClickListener() {...} ); – jfaghihnassiri Jan 29 '14 at 04:50
  • can you post your adapter or piece of code where you are updating the listview content – Anchit Mittal Jan 29 '14 at 04:53
  • I added the code in my question. I was following this tutorial and simply using a local JSON file: http://www.androidhive.info/2012/01/android-json-parsing-tutorial/ – jfaghihnassiri Jan 29 '14 at 05:34
  • For doing an individual handling for views you need to make your own custom adapter. – Anchit Mittal Jan 29 '14 at 05:44
1

Allright I was having a similar kind of problem but i was using a ViewPager with a ListFragment and a custom ListView Layout.

In the above case you are using just ImageViews, but just in case if you use controls like ImageButton, CheckBox ,Button etc then you would face problems discussed here and here.

This is simply because such controls can steal focus from the ListView and the complete list item cant be selected/clicked. so I would say that just using ImageViews is a smart move.
I am assuming that you are using an Adapter to set the content of your list. Inside that adapter you can assign onClickListener()s for each item like this:

public class MyListAdapter extends ArrayAdapter<String>{
    .......
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
         View rowView=inflator.inflate(R.layout.channel_list_item, null, true);
         ImageView chat=(ImageView) rowView.findViewById(R.id.chat);
         chat.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                 //do something
            }
         }

         ImageView calendar=(ImageView) rowView.findViewById(R.id.calendar);
         calendar.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                 //do something
            }
         }
         .......
    }
}

but remember that while using controls like ImageButton, CheckBox ,Button you need to assign property android:focusable="false" in the XML. and for the ImageButton you need to do this inside the getView() method:

    final ImageButton imgBtn=(ImageButton) rowView.findViewById(R.id.imgBtn);
    imgBtn.setFocusable(false);
    imgBtn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            //do your task here
        }
    });

or you can also use Nathaniel Waggoner's approach.

Hope I answered your question.

Community
  • 1
  • 1
SMR
  • 6,628
  • 2
  • 35
  • 56
  • This worked perfectly, I had to make my own adapter where I filled in my data pieces, and specified the event handlers for each of the three pictures I was interested in. Is the adapter a good place to specify the event handler for the rest of the ListItem? For example, if a click event occurred anywhere but those three images? – jfaghihnassiri Feb 08 '14 at 06:23
  • Found the answer to my question [here](http://stackoverflow.com/questions/1821871/how-to-fire-onlistitemclick-in-listactivity-with-buttons-in-list?lq=1). You set the listener on the "rowView" just like you did the images. – jfaghihnassiri Feb 08 '14 at 06:32
0

If you don't want to set on click listeners for each item, the other option is to compare the view.getId() value of the view passed into on click, to the ids of the views, something like:

switch(view.getId()){
  case(R.id.dog_image):
    //do stuff
    break;
  case(R.id.other_image):
    //do stuff
    break;
}

Otherwise you can do this programatically by doing the following in onCreate:

.....
setContentView(myView);
ImageView dogImage = (ImageView) findViewById(R.id.dog_image);
dogImage.setOnClickListener(new View.OnClickListener {
   @Override
   public void onClick(View v) {
     // do stuff...
   }

})

....
Nathaniel D. Waggoner
  • 2,856
  • 2
  • 19
  • 41