In my last article on listviews, I presented how it is possible to create a custom listview with items containing more than a simple line of text, without the use of external XMLs. Now I come with a new challenge:

Yes, you can have this nice interface in your Android Project. Here is what you need to know:
1. We create a custom listview adapter as in the previous article. This will hold two String: first name and last name.
2. Based on position, we load the special graphics: the item with position 0, will be the top image. The last position item will be the bottom image. We have special images if the item before had content or if it was empty:

  1.  
  2. //check current item in list
  3. boolean isEmpty = ( (item.getFirstName().length() == 0) &&
  4. (item.getLastName().length() == 0));
  5.  
  6.  
  7. boolean isPrevEmpty = false;
  8. if (prevItem == null)
  9. isPrevEmpty = true;
  10. else
  11. isPrevEmpty = ( (prevItem.getFirstName().length() == 0) &&
  12. (prevItem.getLastName().length() == 0));
  13.  

To better understand how the background images for each item are combined, you have the source code included below, look for the RES folder to see the images.
3. Based on position, some of the items get special content, eg. the very first item is a Header, with an EditText and two ToggleButtons. Normally you would use these to sort the content of your list.
In CustomAdapter.java:

  1.  
  2. //header
  3. if (position == 0) {
  4.  

Will handle the EditText and the two toggle buttons. The toggle buttons are like check boxes, but they support images. The image is defined in an xml, filter_left.xml and filter_right.xml corresponding to the left and right togglebuttons. The XML is places together with the images, and the content is as follows:

  1.  
  2. <?xml version="1.0" encoding="utf-8"?>
  3. <selector xmlns:android="http://schemas.android.com/apk/res/android">
  4. <item android:state_checked="true"
  5. android:drawable="@drawable/filter_left_on" /> <!-- pressed -->
  6. <item android:drawable="@drawable/filter_left_off" /> <!-- default/unchecked -->
  7. </selector>
  8.  

In CustomAdapter.java , the bottom item is handled as follows:

  1.  
  2. else if (position == total - 1) {
  3. //-- this is the LAST LV ITEM --//
  4.  

This position parameter , but also the total variable, are conveniently sent from within the CustomAdapter class:

  1.  
  2. public View getView(int position, View convertView, ViewGroup parent)
  3. {
  4. CustomAdapterItem item = itemList.get(position);
  5. CustomAdapterItem prevItem = null;
  6. if (position > 0) prevItem = itemList.get(position-1);
  7. View v = new CustomAdapterView(this.context, item, position, itemList.size(), prevItem );
  8. return v;
  9. }
  10.  

As you can see we access the previous item as well, to learn if it's populated or not, and use the proper image for out item in the listview:


If the previous item had content

If the previous item was empty

As you can see this helps to create a continuous interface listview.

To handle the click events and text change event in the top EditText, we set the callback back to the parent class:
In CustomAdapterView:

  1.  
  2. setOnClickListener((OnClickListener) context);
  3. setId(item.getItemID());
  4. ...
  5. et.setId(CustomComplexListview.idFilterEdit);
  6. et.addTextChangedListener((TextWatcher) context);
  7.  

But make sure the parent class, implements the click and text change events or your app will crash:

  1.  
  2. public class CustomComplexListview extends Activity implements OnClickListener, TextWatcher {
  3.  

The interface is vertically scrollable - a very nice effect, including the header moves together with the rest of the items.

When the application first starts, the listview is scrolled automatically so that the Header is hidden. A very nice effect for an elegant listview in your application. See: CustomComplexListview.java:

  1.  
  2. m_lv.setSelection(1);
  3.  

To populate the listview, I decided to process the top Header and the last bottom item separately. The reason is these are special items that do not get the normal content (first name + lastname):

  1.  
  2. m_lv = new ListView(this);
  3.  
  4. ArrayList<CustomAdapterItem> m_lvItems = new ArrayList<CustomAdapterItem>();
  5. //
  6. //add Header
  7. m_lvHeaderItem = new CustomAdapterItem("","",0); //add header
  8. m_lvItems.add(m_lvHeaderItem);
  9. //add items
  10. CustomAdapterItem lvItem;
  11.  
  12. int items = 0;
  13.  
  14. lvItem = new CustomAdapterItem( "Radu", "Motisan", idLVFirstItem+items);
  15. m_lvItems.add(lvItem);
  16. items++;
  17.  
  18. lvItem = new CustomAdapterItem( "PocketMagic", ".net", idLVFirstItem+items);
  19. m_lvItems.add(lvItem);
  20. items++;
  21.  
  22. lvItem = new CustomAdapterItem( "Complex", "Listview", idLVFirstItem+items);
  23. m_lvItems.add(lvItem);
  24. items++;
  25.  
  26. // add extra items to fill the rest of the listview: we need 4 items at least!
  27. for (int i=0;i<4-items;i++) {
  28. lvItem = new CustomAdapterItem("","", 0);
  29. m_lvItems.add(lvItem);
  30. }
  31.  
  32. //add Footer
  33. lvItem = new CustomAdapterItem("","",0); //add footer: must be last item!
  34. m_lvItems.add(lvItem);
  35. //create the Adapter
  36. if (m_lvAdapter == null) m_lvAdapter = new CustomAdapter(this, m_lvItems);
  37. //Add adapter to Listview
  38. m_lv.setAdapter((ListAdapter) m_lvAdapter);
  39. // Configure listview: no divider, no focusable, etc
  40. m_lv.setDividerHeight(0);
  41. m_lv.setScrollBarStyle(0);
  42. m_lv.setSelection(1);
  43. m_lv.setFocusable(false);
  44.  

By default, besides the Header and the Footer (bottom big item), we always get 4 items (to fill the screen up). Also I use setDividerHeight(0) and setScrollBarStyle(0) to disable the separator line between listview items.

Inside one item, but also in the Header when we have the EditText and the two togglebuttons, we use Relative layouts to conveniently place the components, one relative to another:

  1.  
  2. //the EditText
  3. et.setId(CustomComplexListview.idFilterEdit);
  4. et.setBackgroundResource(R.drawable.edit);
  5. et.addTextChangedListener((TextWatcher) context);
  6. RelativeLayout.LayoutParams layoutparams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
  7. layoutparams.leftMargin = 0;
  8. layoutparams.topMargin = 0;
  9. PanelH.addView(et, layoutparams);
  10. ...
  11. //The First Toggle Button
  12. RelativeLayout.LayoutParams layoutparams1 = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
  13. layoutparams1.addRule(RelativeLayout.BELOW, CustomComplexListview.idFilterEdit);
  14. layoutparams1.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
  15. PanelH.addView(b1, layoutparams1);
  16.  

As you can see, we simply align the left toggle button below the EditText control. Extremely convenient!

You'll see all the details in my code:
CustomComplexListview

If you have any questions, use the comments form below.

(Visited 89 times, 1 visits today)
facebooktwittergoogle_plusredditpinterestlinkedinmailfacebooktwittergoogle_plusredditpinterestlinkedinmail
Tagged on: