I have a listview containing different xml layouts, each with different views. I was wondering how I can get the data from the views inside the item that the user has clicked on, inside the onItemClick
method.
My listview is made up of multiple layouts so I cannot know for sure which layout is being pressed when the onItemClick method is called. For example, one of the items in the layouts in the listview is:
// list_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/lblSub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:padding="6dp"
android:layout_marginRight="4dp"
android:text=""
android:textColor="#FFFFFF"
android:textSize="18sp" />
<TextView
android:id="@+id/lblMain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:padding="6dp"
android:layout_marginLeft="4dp"
android:text=""
android:textColor="#FFFFFF"
android:textSize="18sp" />
</RelativeLayout>
Where as another layout in the listview could be:
// list_item_name.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/lblName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="4dp"
android:padding="4dp"
android:text="TextView"
android:textColor="#FFFFFF"
android:textSize="28sp" />
</RelativeLayout>
So I am at a loss as to how to get the data for all these views for any layout within the listview.
My previous attempt was this:
public void onItemClick(AdapterView<?> listView, View view, int position, long id) {
Object obj = adapter.getItem(position);
String value = obj.toString();
}
However value
in this instance, returns a string containing all the values of all the views inside this item, for example: {caption=MobileNumber, value=07000123456}
<<< I cannot do anything with this string unless I try and pick it apart using substring
, which is unreliable at best considering the values may have been created by the user.
This is my adapter in use (credit to Jeff Sharkey, I did not create this adapter):
public class SeparatedListAdapter extends BaseAdapter {
public final Map<String,Adapter> sections = new LinkedHashMap<String,Adapter>();
public final ArrayAdapter<String> headers;
public final static int TYPE_SECTION_HEADER = 0;
public SeparatedListAdapter(Context context) {
headers = new ArrayAdapter<String>(context, R.layout.list_header);
}
public void addSection(String section, Adapter adapter) {
this.headers.add(section);
this.sections.put(section, adapter);
}
public void addSectionNoHeader(String section, Adapter adapter) {
this.sections.put(section, adapter);
}
public Object getItem(int position) {
for(Object section : this.sections.keySet()) {
Adapter adapter = sections.get(section);
int size = adapter.getCount() + 1;
// check if position inside this section
if(position == 0) return section;
if(position < size) return adapter.getItem(position - 1);
// otherwise jump into next section
position -= size;
}
return null;
}
public int getCount() {
// total together all sections, plus one for each section header
int total = 0;
for(Adapter adapter : this.sections.values())
total += adapter.getCount() + 1;
return total;
}
public int getViewTypeCount() {
// assume that headers count as one, then total all sections
int total = 1;
for(Adapter adapter : this.sections.values())
total += adapter.getViewTypeCount();
return total;
}
public int getItemViewType(int position) {
int type = 1;
for(Object section : this.sections.keySet()) {
Adapter adapter = sections.get(section);
int size = adapter.getCount() + 1;
// check if position inside this section
if(position == 0) return TYPE_SECTION_HEADER;
if(position < size) return type + adapter.getItemViewType(position - 1);
// otherwise jump into next section
position -= size;
type += adapter.getViewTypeCount();
}
return -1;
}
public boolean areAllItemsSelectable() {
return false;
}
public boolean isEnabled(int position) {
return (getItemViewType(position) != TYPE_SECTION_HEADER);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
int sectionnum = 0;
for(Object section : this.sections.keySet()) {
Adapter adapter = sections.get(section);
int size = adapter.getCount() + 1;
// check if position inside this section
if(position == 0) return headers.getView(sectionnum, convertView, parent);
if(position < size) return adapter.getView(position - 1, convertView, parent);
// otherwise jump into next section
position -= size;
sectionnum++;
}
return null;
}
@Override
public long getItemId(int position) {
return position;
}
}
I'm looking for a way of extracting the values of all the views inside the item. But the fact that the item that has been clicked could be one of any layouts is confusing me. Any ideas?
Here is an example of how I am using this adapter in code:
SeparatedListAdapter adapter;
Customer cust;
ListView lvDetails;
public Map<String,?> createDoubleItem(String title, String caption) {
Map<String,String> item = new HashMap<String,String>();
item.put(ITEM_VALUE, title);
item.put(ITEM_CAPTION, caption);
return item;
}
public Map<String,?> createSingleItem(String name) {
Map<String,String> item = new HashMap<String,String>();
item.put(ITEM_VALUE, name);
return item;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_customer);
Intent intent = getIntent();
cust = Db.Functions.getCustomer(intent.getStringExtra("uuid"));
lvDetails = (ListView) findViewById(R.id.custdetails);
adapter = new SeparatedListAdapter(this);
lvDetails.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> listView, View view, int position, long id) {
Gen.popup("Item clicked");
}
});
// Name
List<Map<String,?>> name = new LinkedList<Map<String,?>>();
if (cust.firstName == null && cust.lastName == null)
name.add(createSingleItem("Unnamed Customer"));
else
name.add(createSingleItem(
((cust.title != null) ? cust.title + " " : "") +
((cust.firstName != null) ? cust.firstName + " " : "") +
((cust.lastName != null) ? cust.lastName : "")));
adapter.addSection("Name", new SimpleAdapter(this, name, R.layout.list_item_name,
new String[] { ITEM_VALUE },
new int[] { R.id.lblName }));
// Phones
if ((cust.mobileNumber != null || cust.homeNumber != null || cust.workNumber != null) && SHOW_PHONES)
{
List<Map<String,?>> phone = new LinkedList<Map<String,?>>();
if (cust.mobileNumber != null)
phone.add(createDoubleItem(cust.mobileNumber, "Mobile"));
if (cust.homeNumber != null)
phone.add(createDoubleItem(cust.homeNumber, "Home"));
if (cust.workNumber != null)
phone.add(createDoubleItem(cust.workNumber, "Work"));
adapter.addSection("Phone", new SimpleAdapter(this, phone, R.layout.list_item,
new String[] { ITEM_VALUE, ITEM_CAPTION },
new int[] { R.id.lblSub, R.id.lblMain }));
}
lvDetails.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
Here's an easy way - paste this into each of the xml Views:
android:onClick="someFunction"
Then inside this someFunction
do:
public void someFunction(View v){
switch (v.getId()){
case R.id.lblSub:
// This layout was clicked, do something about it
break;
case R.id.lblMain:
// This layout was clicked, do something about it
break;
}
My understanding here is that you have 3 types of items:
areAllItemsSelectable
and isEnabled
methods and therefore cannot be clicked)You also have apparently 2 sections, Name and Phone.
Items from section 1 (adapter.getItemViewType(position) == 1
) are single items, while section 2 (adapter.getItemViewType(position) == 2
).
In both cases, your item
object (adapter.getItem(position)
) is declared a Map<String, ?>
and is even defined as a Map<String, String>
.
That means that you can cast item to a Map
:
Map<String, String> itemAsMap = (Map<String, String>) item;
and then fetch your value from the Map, using the ITEM_VALUE
and ITEM_CAPTION
keys.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With