Monday, October 24, 2011

Custom ListView with Button and Image in Android

Hi, This tutorial shows you how to customize the existing list view activity to be more attractive by adding some common widgets inside individual lines of list. The point is to customize the default android adapter layout by subclassing BaseAdapter to implement your own adapter which having both image, textview and button inside. To position the group of widgets being shown on each line, we have to implement one more layout, here is (adaptor_content.xml), to hold and position those widgets and add this adapter layout into your customized adapter programmatically. Ok, that's it. Let's walk through the source code before, it's so easy. but if you have any question or need to share more features, please post it here... Build this community to be real mobile dev community.


Layout main.xml



<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_height="fill_parent" android:layout_width="fill_parent"
 android:background="@color/screen_background">
 <ImageView android:background="@drawable/banner" android:id="@+id/bannerImage"
  android:layout_width="fill_parent" android:layout_height="wrap_content"
  android:layout_alignParentTop="true" />
 <ListView android:id="@+id/android:list" android:layout_width="fill_parent"
  android:layout_height="fill_parent" android:layout_marginTop="10dip"
  android:layout_below="@+id/bannerImage" android:drawSelectorOnTop="false"
  android:layout_marginBottom="60dip" android:cacheColorHint="#00000000" />
</RelativeLayout>
Layout adaptor_content.xml 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/lineItem"
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="wrap_content" android:layout_height="wrap_content"
 android:gravity="center_vertical">
 <ImageView android:id="@+id/iconLine" android:layout_width="48dip"
  android:layout_height="48dip" android:layout_alignParentLeft="true" />
 <TextView android:id="@+id/textLine" android:layout_height="wrap_content"
  android:layout_marginLeft="10dip" android:textSize="24sp"
  android:textColor="#ff000000" android:layout_width="wrap_content"
  android:layout_toRightOf="@+id/iconLine" />
 <Button android:id="@+id/buttonLine" android:gravity="center"
  android:layout_height="wrap_content" android:layout_width="wrap_content"
  android:layout_alignParentRight="true" android:text="Delete" />

</RelativeLayout>
ListActivity Class CustomListViewDemo.java 

import android.app.ListActivity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class CustomListViewDemo extends ListActivity {
  private EfficientAdapter adap;
  private static String[] data = new String[] { "0", "1", "2", "3", "4" };
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.main);
    adap = new EfficientAdapter(this);
    setListAdapter(adap);
  }
  @Override
  protected void onListItemClick(ListView l, View v, int position, long id) {
    // TODO Auto-generated method stub
    super.onListItemClick(l, v, position, id);
    Toast.makeText(this, "Click-" + String.valueOf(position), Toast.LENGTH_SHORT).show();
  }
  public static class EfficientAdapter extends BaseAdapter implements Filterable {
    private LayoutInflater mInflater;
    private Bitmap mIcon1;
    private Context context;
    public EfficientAdapter(Context context) {
      // Cache the LayoutInflate to avoid asking for a new one each time.
      mInflater = LayoutInflater.from(context);
      this.context = context;
    }
    /**
     * Make a view to hold each row.
     * 
     * @see android.widget.ListAdapter#getView(int, android.view.View,
     *      android.view.ViewGroup)
     */
    public View getView(final int position, View convertView, ViewGroup parent) {
      // A ViewHolder keeps references to children views to avoid
      // unneccessary calls
      // to findViewById() on each row.
      ViewHolder holder;
      // When convertView is not null, we can reuse it directly, there is
      // no need
      // to reinflate it. We only inflate a new View when the convertView
      // supplied
      // by ListView is null.
      if (convertView == null) {
        convertView = mInflater.inflate(R.layout.adaptor_content, null);
        // Creates a ViewHolder and store references to the two children
        // views
        // we want to bind data to.
        holder = new ViewHolder();
        holder.textLine = (TextView) convertView.findViewById(R.id.textLine);
        holder.iconLine = (ImageView) convertView.findViewById(R.id.iconLine);
        holder.buttonLine = (Button) convertView.findViewById(R.id.buttonLine);
        
        
        convertView.setOnClickListener(new OnClickListener() {
          private int pos = position;
          @Override
          public void onClick(View v) {
            Toast.makeText(context, "Click-" + String.valueOf(pos), Toast.LENGTH_SHORT).show();    
          }
        });
        holder.buttonLine.setOnClickListener(new OnClickListener() {
          private int pos = position;
          @Override
          public void onClick(View v) {
            Toast.makeText(context, "Delete-" + String.valueOf(pos), Toast.LENGTH_SHORT).show();
          }
        });
        
        
        convertView.setTag(holder);
      } else {
        // Get the ViewHolder back to get fast access to the TextView
        // and the ImageView.
        holder = (ViewHolder) convertView.getTag();
      }
      // Get flag name and id
      String filename = "flag_" + String.valueOf(position);
      int id = context.getResources().getIdentifier(filename, "drawable", context.getString(R.string.package_str));
      // Icons bound to the rows.
      if (id != 0x0) {
        mIcon1 = BitmapFactory.decodeResource(context.getResources(), id);
      }
      // Bind the data efficiently with the holder.
      holder.iconLine.setImageBitmap(mIcon1);
      holder.textLine.setText("flag " + String.valueOf(position));
      return convertView;
    }
    static class ViewHolder {
      TextView textLine;
      ImageView iconLine;
      Button buttonLine;
    }
    @Override
    public Filter getFilter() {
      // TODO Auto-generated method stub
      return null;
    }
    @Override
    public long getItemId(int position) {
      // TODO Auto-generated method stub
      return 0;
    }
    @Override
    public int getCount() {
      // TODO Auto-generated method stub
      return data.length;
    }
    @Override
    public Object getItem(int position) {
      // TODO Auto-generated method stub
      return data[position];
    }
  }
}
Download code:

3 comments:

  1. Hi... The download link doesnt work. Can you post the link new?? PLS

    ReplyDelete
  2. Android posts are really better with images included

    ReplyDelete