Wednesday, January 5, 2011

Handling Button clicks in a ListView Row

By Magesh Kumar   Posted at  1:55 AM   Android 2 comments


Lets say you have a spinner widget, like the one we created in our 'colours' example, and you wanted to put a button on each row of your spinner for your users to click (everyone loves clicking buttons, right?).

You might have a layout a bit like this simple one below:

<LinearLayout android:id="@+id/LinearLayout01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">

 <TextView android:text="this is a row"
     android:id="@+id/tvViewRow"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content">
 </TextView>
 <Button android:text="Click me!"
     android:id="@+id/BtnToClick"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:onClick="myClickHandler">
 </Button>

</LinearLayout>

.. Containing just a textView and a Button View.

A listView with textual, non-clickable views in it responds to Click events via the OnItemClickListener event.

But once you put a button in the ListView, this event no longer fires.

So how do you capture the button's click event, and find what row in your ListView a clicked button is located in?

You may have noticed this android:onClick="myClickHandler">in our layout above..
What this does is tie every click of every instance of that button, in every row of our ListView to one single handler, located in the code of our ListActivity class below:

    public void myClickHandler(View v) 
    {
          
        //reset all the listView items background colours 
        //before we set the clicked one..

        ListView lvItems = getListView();
        for (int i=0; i < lvItems.getChildCount(); i++) 
        {
            lvItems.getChildAt(i).setBackgroundColor(Color.BLUE);        
        }
        
        
        //get the row the clicked button is in
        LinearLayout vwParentRow = (LinearLayout)v.getParent();
         
        TextView child = (TextView)vwParentRow.getChildAt(0);
        Button btnChild = (Button)vwParentRow.getChildAt(1);
        btnChild.setText(child.getText());
        btnChild.setText("I've been clicked!");
        
        int c = Color.CYAN;
        
        vwParentRow.setBackgroundColor(c); 
        vwParentRow.refreshDrawableState();       
    }


In this case, the View v being passed in as a parameter is our button.
We get the parent of our button, being careful to cast it as a LinearLayout (have another look at the xml if you're not sure why), and then simply set the background colour of our Layout Row.

Don't forget to call .refreshDrawableState(); on yourvwParentRow or it will never redraw and you won't see your nice colour change.

.. Tada!



New modified code...

main.xml
---------
<LinearLayout android:id="@+id/LinearMain" 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" 
 xmlns:android="http://schemas.android.com/apk/res/android">

    <ListView android:id="@+id/android:list"
          android:layout_width="wrap_content"
         android:layout_height="wrap_content"/>
        
   <TextView android:id="@+id/android:empty"
          android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="No items"/>

</LinearLayout>

view_row.xml
---------------
<LinearLayout android:id="@+id/LinearLayout01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">

 <TextView android:text="this is a row"
  android:id="@+id/tvViewRow"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
 </TextView>
 <Button android:text="Click me!"
  android:id="@+id/BtnToClick"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:onClick="myClickHandler">
 </Button>

</LinearLayout>

ListViewBtnClickExample.java
--------------------------------
package example.ListViewBtnClickExample;

import android.app.ListActivity;
import android.database.Cursor;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

public class ListViewBtnClickExample extends ListActivity {
 private TestDBAdapter thisTestDBAdapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {   
     thisTestDBAdapter = new TestDBAdapter(this);
        
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        thisTestDBAdapter.open();
        
        thisTestDBAdapter.insertEntryTable("BLUE");
        thisTestDBAdapter.insertEntryTable("GREEN");
        thisTestDBAdapter.insertEntryTable("RED");
        thisTestDBAdapter.insertEntryTable("YELLOW");
        thisTestDBAdapter.insertEntryTable("BLACK");
        thisTestDBAdapter.insertEntryTable("GREY");
        thisTestDBAdapter.insertEntryTable("VIOLET");
        thisTestDBAdapter.insertEntryTable("MAGENTA");
        
   fillData();
        
    }
    

    public void myClickHandler(View v) 
    {
       
     //reset all the listView items background colours before we set the clicked one..
     ListView lvItems = getListView();
     for (int i=0; i<lvItems.getChildCount(); i++) 
     {
   lvItems.getChildAt(i).setBackgroundColor(Color.BLUE); 
  }
    
    
     //get the row the clicked button is in
     LinearLayout vwParentRow = (LinearLayout)v.getParent();
  
     TextView child = (TextView)vwParentRow.getChildAt(0);
     Button btnChild = (Button)vwParentRow.getChildAt(1);
     btnChild.setText(child.getText());
     btnChild.setText("I've been clicked!");
    
  int c = Color.CYAN;
 
  vwParentRow.setBackgroundColor(c); 
  vwParentRow.refreshDrawableState();
    
    }
    
    private void fillData() {
     Cursor coloursCursor;

   coloursCursor = thisTestDBAdapter.fetchAllEntriesForTable();
     
        startManagingCursor(coloursCursor);
        
        // Create an array to specify the fields we want to display in the list (only TITLE)
        
        String[] from = new String[]{TestDBAdapter.KEY_TITLE, TestDBAdapter.KEY_ROWID};
        
        // and an array of the fields we want to bind those fields to (in this case just tvViewRow)
        int[] to = new int[]{R.id.tvViewRow};

                
        // Now create a simple cursor adapter and set it to display
        SimpleCursorAdapter colours = 
             new SimpleCursorAdapter(this, R.layout.view_row, coloursCursor, from, to);
        setListAdapter(colours);
       
    }  
}

TestDBAdapter.java
----------------------

package example.ListViewBtnClickExample;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;


public class TestDBAdapter {

 public static final String KEY_ROWID = "_id";
 public static final String KEY_TITLE = "title";
    
    private static final String TAG = "TestDbAdapter";
    private DatabaseHelper mDbHelper;
    private SQLiteDatabase mDb;
    
    private static final String DATABASE_NAME = "droidTest1d";
    private static final String table1 = "table1"; 

    private static final int DATABASE_VERSION = 5;
    
    /**
     * Database creation sql statement
     */
    private static final String DATABASE_CREATE1 =
        " create table " + table1 + 
        " (_id integer primary key autoincrement," +
       " title text);";

    private final Context mCtx;
    
    private static class DatabaseHelper extends SQLiteOpenHelper {

        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
        

        @Override
        public void onCreate(SQLiteDatabase db) {

         db.execSQL(DATABASE_CREATE1);
      
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                    + newVersion + ", which will destroy all old data");
            db.execSQL("DROP TABLE IF EXISTS " + table1 + ";");

            onCreate(db);
        }
    }
    

    public TestDBAdapter(Context ctx) 
    {
        this.mCtx = ctx;
    }


    
    public TestDBAdapter open() throws SQLException 
    {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;
    }
    
    
    public void close() 
    {
        mDbHelper.close();
    }

// CRUD below
    //Insert

    public long insertEntryTable(String colourName) 
    {
        ContentValues initialValues = new ContentValues();
        initialValues.put(KEY_TITLE, colourName);
      
        
        return mDb.insert(table1, null, initialValues);
    }
    


    public boolean deleteEntryTable1(long rowId) 
    {

        return mDb.delete(table1, KEY_ROWID + "=" + rowId, null) > 0;
    }


    
    public Cursor fetchAllEntriesForTable() 
    {
  if (mDb == null)
  {
   this.open();
  }
 

   return mDb.query("table1", new String[] { KEY_ROWID, KEY_TITLE}, null, null, null, null, null);


 
    }
}

AndroidManifest.xml
--------------------
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="example.ListViewBtnClickExample"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".ListViewBtnClickExample"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
    <uses-sdk android:minSdkVersion="4" />

</manifest> 






About the Author

Nulla sagittis convallis arcu. Sed sed nunc. Curabitur consequat. Quisque metus enim, venenatis fermentum, mollis in, porta et, nibh. Duis vulputate elit in elit. Mauris dictum libero id justo.
View all posts by: BT9

2 comments:

  1. can you give the source code please

    ReplyDelete
  2. I can add button into listview row
    May you show me the way to put button into listview row?

    ReplyDelete

Back to top ↑
Connect with Us

What they says

© 2013 MaGeSH 2 help. WP Mythemeshop Converted by BloggerTheme9
Blogger templates. Proudly Powered by Blogger.