0

I have a ListView with a row that has an ImageButton. I can click on a particular row and this works: the new expected activity starts. But if I click on the ImageButton, and this is an item within the row, nothing happens. The imageButton gets highlighted but the print out within the onClick of the ImageButton is not executed. Can anyone tell me how I can resolve this? Here is my code:

    SimpleCursorAdapter menuItems2 = new SimpleCursorAdapter(
            this, R.layout.todo_row, matrixCursor, columnNames, to);
    ToDolv.setAdapter(menuItems2);

    ToDolv.setClickable(true);

    ToDolv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
          @Override
          public void onItemClick(AdapterView<?> arg0, View arg1, final int position, long arg3) { 
               final String article = (String) todoIDArray.get(position);
               globalVariable.setArtID(article);
               Intent intent1 = new Intent(MainActivity.this, AddToDo.class);
               startActivity(intent1);
               finish();

               ImageButton chkDone = (ImageButton) findViewById(R.id.chkDone);
               chkDone.setOnClickListener(new View.OnClickListener() {              
               @Override
                  public void onClick(View v) {
                     // TODO Auto-generated method stub
                     View parentRow = (View) v.getParent();
                     ListView listView = (ListView) parentRow.getParent();
                     final int position = listView.getPositionForView(parentRow);
                     System.out.println("I am in position "+ position);
               }
             });

          }

        });

Here is the XML for the Row where the ImageButton is:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip"
android:background = "#5a9b3e"
android:alpha = "0.7"
android:descendantFocusability="blocksDescendants"
>
    <TextView 
    android:id="@+id/id"
    android:textColor="#5a9b3e"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    />
    <TextView
        android:id="@+id/heading"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:textColor="#FFFFFF"
        android:textStyle="bold"
        android:alpha = "1.0"
        android:layout_alignParentTop="true"
        android:ellipsize="marquee"
        android:singleLine="false"
        android:textSize="12sp"
        />


   <ImageView
        android:id="@+id/icon"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:padding="2dp"
        android:layout_toRightOf="@+id/heading"
        android:layout_toEndOf="@+id/heading"

        />

   <ImageView 
       android:id="@+id/lights"
       android:layout_width= "20dp"
       android:layout_height="20dp"
       android:padding="2dp"
       android:layout_toRightOf="@+id/icon"
       android:layout_toEndOf="@+id/icon"
       />

    <ImageButton
    android:id="@+id/chkDone"
    android:layout_width="20dp"
    android:layout_height="20dp"
    android:padding="0dp"
    android:background="?android:attr/listChoiceBackgroundIndicator"
    android:layout_toRightOf="@+id/lights"
    android:layout_toEndOf="@+id/lights"
    android:src ="@drawable/checkbox"
    android:scaleType="fitXY"
    android:focusable="false"
    android:focusableInTouchMode="false"
    />
   <TextView 
       android:id="@+id/date"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textColor="#FFFFFF"
       android:textStyle="bold"
       android:alpha = "1.0"
       android:layout_marginStart="2sp"
       android:layout_marginLeft="2sp"
       android:layout_marginTop="2sp"
       android:textSize="12sp" 
       android:layout_toRightOf="@+id/chkDone"
       android:layout_toEndOf="@+id/chkDone"/>
</RelativeLayout>

Thanks very much!

EDIT

Following suggestions I have created a Custom Adapter Class to show the row. So I have changed the code as follows: The Main activity now has the following lines of code:

      ListView yourListView = (ListView) findViewById(R.id.list);
      SimpleCursorAdapter menuItems2 = new SimpleCursorAdapter(
            this, R.layout.todo_row, matrixCursor, columnNames, to);

      CustomListViewAdapter customAdapter = new CustomListViewAdapter(this, R.layout.todo_row, menuItems2);
      yourListView .setAdapter(customAdapter);

And the CustomListViewAdapter Looks like:

public class CustomListViewAdapter extends ArrayAdapter<RowItem> {
Context context;
public CustomListViewAdapter(Context context, int resourceId,
        SimpleCursorAdapter menuItems2) {
    super(context, resourceId);
    this.context = context;
    System.out.println("I am in the custom Adapter class "+ context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent){
    System.out.println("This is the get view");
    View row = convertView;
    if (row == null) {
       LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
       row = mInflater.inflate(R.layout.todo_row, parent, false);
    }

    ImageButton chkDone = (ImageButton) row.findViewById(R.id.chkDone);
    chkDone.setOnClickListener(new View.OnClickListener() {              
          @Override
          public void onClick(View v) {
                View parentRow = (View) v.getParent();
                ListView listView = (ListView) parentRow.getParent();
                final int position =   listView.getPositionForView(parentRow);
                System.out.println("I am in position "+ position);
          }
     });

    return row;
}
}

The XML is the same.

It compiles, but it doesn't do anything and it does not even show the row now... Let me know if you need me to post the code that builds up the matrixCursor.

Thanks very much, much appreciated.

user3079872
  • 191
  • 1
  • 5
  • 15
  • You are setting the click listener of the button only when you click the row (because you are calling it from within `ToDolv.setOnItemClickListener` which isn't going to work. You need to look at creating a custom adapter for your listview and setting your click event for your image view in there. This link might be of some help http://stackoverflow.com/questions/8166497/custom-adapter-for-list-view – Dreagen Apr 23 '15 at 09:37
  • Post you adapter class. – Raghavendra Apr 23 '15 at 09:40
  • He is using `SimpleCursorAdapter`, he hasn't created a custom adapter for the list yet which is the main problem – Dreagen Apr 23 '15 at 09:41
  • @Dreagen, you are right. How do I create a custom adapter for the list view? – user3079872 Apr 23 '15 at 09:41
  • @user3079872 the link I put in my first comment has a pretty good example of how to do it. I would only be re writing what was in there if I were to put it as an answer on here. Give that a go and if you struggle post your effort on here and I can help you get it right if needs be – Dreagen Apr 23 '15 at 09:43
  • Check how to create custom listview from here http://androidexample.com/How_To_Create_A_Custom_Listview_-_Android_Example/index.php?view=article_discription&aid=67&aaid=92 – Raghavendra Apr 23 '15 at 09:43
  • @Dreagen, thanks, will have a go and post if I struggle. – user3079872 Apr 23 '15 at 09:44
  • try this , ImageButton chkDone = (ImageButton) arg1.findViewById(R.id.chkDone); – Karn Shah Apr 23 '15 at 10:11
  • @Dreagen, I have now created a custom adapter following the example of the link you sent. I am struggling with the line that calls the custom adapter class: ListAdapter customAdapter = new ListAdapter(this, R.layout.itemlistrow, List); --> what should I put instead of List. I am using a matrix cursor to build up the items to show in the row. – user3079872 Apr 23 '15 at 10:23
  • @user3079872 Sorry for my late reply, you need to pass in `List` containing all of the items in your `columnNames` string array which you passed into the old `SimpleCursorAdapter` – Dreagen Apr 23 '15 at 11:04
  • @Dreagen, no problem, I am sure you are busy. The issue I have is that the row is not just strings, but it has TextViews, where I put strings taken from SQLite Database, as well as ImageViews (drawables). Hence I created a matrixCursor which works great UNTIL i need an ImageButton. – user3079872 Apr 23 '15 at 11:36
  • @user3079872 I thought we'd carry on in here. By changing the constructor of your custom adapter you will stop it working. It still needs to have `List` passed in to it. I will attempt to write an answer to show what i mean. – Dreagen Apr 23 '15 at 12:55

4 Answers4

1

You need to create a custom adapter which accepts a list of objects that you can use to build your list.

You need to create a class which holds the information needed in your list. From what you've said something like this:

public class RowItem {

    private String _columnName;
    private Drawable _drawable;

    public RowItem(String columnName, Drawable drawable) {
         _columnName = columnName;
         _drawable = drawable;
    }

    public String getColumnName() {
        return _columnName;
    }

    public Drawable getDrawable() {
        return _drawable;
    }
}

Then create these objects from the items you want in your list

ArrayList<RowItem> rowItems = new ArrayList<>();

//Create a number of row items and add them to your list
RowItem myItem1 = new RowItem("String I want for column name", myDrawable);
rowItems.add(myItem1);

After creating your list of RowItem objects you create your custom adapter like this:

CustomListViewAdapter customAdapter = new CustomListViewAdapter(this, R.layout.todo_row, rowItems);

Then you can pass your list of RowItem objects into your custom adapter via it's contructor (like you were trying to do previously):

public class CustomListViewAdapter extends ArrayAdapter<RowItem> {

Context context;
ArrayList<RowItem> _rowItems;

public CustomListViewAdapter(Context context, int resourceId,
        ArrayList<RowItem> rowItems) {
    super(context, resourceId);
    this.context = context;
    _rowItems = rowItems;
    System.out.println("I am in the custom Adapter class "+ context);
}

@Override
public View getView(int position, View convertView, ViewGroup parent){
    System.out.println("This is the get view");
    View row = convertView;
    RowItem item = _rowItems.get(position);

    // you can now get your string and drawable from the item
    // which you can use however you want in your list
    String columnName = rowItem.getColumnName();
    Drawable drawable = rowItem.getDrawable();
    if (row == null) {
        LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
       row = mInflater.inflate(R.layout.todo_row, parent, false);

    }

    ImageButton chkDone = (ImageButton) row.findViewById(R.id.chkDone);
    chkDone.setOnClickListener(new View.OnClickListener() {              
          @Override
          public void onClick(View v) {
                View parentRow = (View) v.getParent();
                ListView listView = (ListView) parentRow.getParent();
                final int position =   listView.getPositionForView(parentRow);
                System.out.println("I am in position "+ position);
          }
     });

    return row;
}
Dreagen
  • 1,733
  • 16
  • 21
  • With the information I have this is the best answer I could come up with. Hopefully it will make things a bit clearer for you – Dreagen Apr 23 '15 at 13:12
  • thank you very much, I am very grateful for your help. I have put your code into my classes. Everything seems to be OK, except for the line _rowItems = rowItems; which it does not like. it says that _rowItems cannot be resolved to a variable. Am I missing an import in order to cope with "_" on variables? – user3079872 Apr 23 '15 at 14:49
  • Your very welcome. It sounds like you're missing this line: `ArrayList _rowItems = new ArrayList<>();` although there is a typo in that line in my answer, and it could be a bit shorter. I'll edit my answer now – Dreagen Apr 23 '15 at 14:54
  • I have edited my answer now. Make sure you have the line: `ArrayList _rowItems;` in your `CustomListViewAdapter` – Dreagen Apr 23 '15 at 14:56
  • Yes, thanks. However, it complains about the lines: 'String columnName = rowItem.getColumnName(); ' and the one underneath. Another question I have is how do I call the CustomListViewAdapter from the Main Activity? I have: 'CustomListViewAdapter customAdapter = new CustomListViewAdapter(this, R.layout.todo_row, List);' But it does not like it. It says Syntax error on token >, and this is by the myItem1 bit ... again, extremely grateful! – user3079872 Apr 23 '15 at 15:10
  • I have edited my answer to show you how to construct your custom adapter (it's under the part about creating your list of Row Item objects) – Dreagen Apr 23 '15 at 15:16
  • I have run it, but it still shows nothing ... It doesn't even get to the View getView bit ... I have changed the rowItem.getColumnName(); to item.getColumnName(); but don't think that would make a difference. Excuse my ignorance, but would it know to execute View getView even if this is not called from anywhere? – user3079872 Apr 23 '15 at 15:24
  • your change wouldn't have caused it not to work. `getView` get called by the android framework when it's rendering the listview items so don't worry about that. I am not going to be able to help for much longer as I will be leaving soon. What I would do now is create a new question saying that your custom adapter isn't showing any items. Post your custom adapter code in there along with the code where you set the adapter on your listview. Link that question here and I'll look when I get a chance – Dreagen Apr 23 '15 at 15:45
  • thank you, I will do as you suggest. Yes, I have been reading about the getView and it should get called by the android framework, so something is not quite right. I will tidy up my code and post a new question and "try" to link it to this one ... that in itself will be a challenge! Thanks again, I am very grateful for your help. – user3079872 Apr 23 '15 at 15:49
  • Even if you can't link this question to it. Put a link to the new question in a comment here. That way I can easily find it – Dreagen Apr 23 '15 at 15:50
  • I think I have managed to make reference of this question in my new question. Here is the link to the new question: http://stackoverflow.com/questions/29829252/custom-adapter-isnt-showing-any-items Again, thanks a lot! – user3079872 Apr 23 '15 at 16:24
  • @Draegen, I don't know how to thank you enough! It is now working perfectly! And I understand what I am doing, which is a bonus!! Thanks again! – user3079872 Apr 23 '15 at 21:56
  • @user3079872 Glad to hear you got it all sorted! Good luck with the rest of it :) – Dreagen Apr 24 '15 at 07:46
0

try this

ImageButton chkDone = (ImageButton) findViewById(R.id.chkDone);
chkDone.setClickable(true);

may it works for you

Moinkhan
  • 12,732
  • 5
  • 48
  • 65
  • may be the problem is that.. you are registering the ImageButtonClick on ListView Click. that means your imagebutton click is not going to register until you click listitem. so try to move the imagebutton click outside the listitem click – Moinkhan Apr 23 '15 at 09:47
0

Change this line. You should call findViewById() in your AdapterView, not in Activity.

ImageButton chkDone = (ImageButton) arg0.findViewById(R.id.chkDone);

UPDATE That's right, so sorry. You should Override method getView() in your adapter class which you need to create. It must be like this:

@Override
public View getView(int position, View convertView, ViewGroup parent){
    View row = convertView;
    if (row == null) {
       LayoutInflater mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
       row = mInflater.inflate(R.layout.mylistlayout, parent, false);
    }

    ImageButton chkDone = (ImageButton) findViewById(R.id.chkDone);
    chkDone.setOnClickListener(new View.OnClickListener() {              
          @Override
          public void onClick(View v) {
                View parentRow = (View) v.getParent();
                ListView listView = (ListView) parentRow.getParent();
                final int position =   listView.getPositionForView(parentRow);
                System.out.println("I am in position "+ position);
          }
     });

    return row;
}
Yurets
  • 3,999
  • 17
  • 54
  • 74
  • thanks, I have created a custom adapter class and put the above code in it. I am struggling with the line of code that calls the custom adapter: ListAdapter customAdapter = new ListAdapter(this, R.layout.itemlistrow, List); Not sure what i should put for I am using a matrix cursor to build the contents of the row. – user3079872 Apr 23 '15 at 10:26
0

Looking at your Java code, it seems that you have the ImageButton's OnClickListener inside the ListView's OnItemClickListener.. Therefore, put it outside of that method and it should work I believe.

EDIT: Try this:

    public View getView(int position, View row, ViewGroup parent) {
            final ViewHolder holder;
            if (row == null) {
                LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
                row = inflater.inflate(R.layout.items_layout, parent, false);
                holder = new ViewHolder();

                holder.chkDone = (ImageButton) row.findViewById(R.id.chkDone);

             row.setTag(holder);
            } else {
                holder = (ViewHolder)row.getTag();
            }

            // You add all your methods here...
            holder.chkDone.setOnClickListener(new View.OnClickListener() {              
               @Override
                  public void onClick(View v) {
                     // TODO Auto-generated method stub
                     View parentRow = (View) v.getParent();
                     ListView listView = (ListView) parentRow.getParent();
                     final int position = listView.getPositionForView(parentRow);
                     System.out.println("I am in position "+ position);
               }
             });

        }
        return(row);
    }

    class ViewHolder {
        ImageButton chkDone;
    }
Musa Y.
  • 1,747
  • 18
  • 26
  • it will not work, because layout which contains `ImageButton` is defined inside of `ListView` – Yurets Apr 23 '15 at 10:01
  • Why not define it outside the `ListView`'s `OnItemClickListener`? I think it shouldn't be a problem, try it. – Musa Y. Apr 23 '15 at 10:03
  • Edited my answer, so try it. – Musa Y. Apr 23 '15 at 10:21
  • @M-Y, I would be very happy to try it, but a silly question, how do I call getView? – user3079872 Apr 23 '15 at 10:29
  • Here is a very good example of how to use it: http://examples.javacodegeeks.com/android/core/ui/listview/android-multitouch-listview-example/ – Musa Y. Apr 23 '15 at 10:35
  • @M-Y, thanks, I can see that the item being passed is an array of String. My row has strings, as well as drawables, hence I am using a matrix cursor. – user3079872 Apr 23 '15 at 10:55
  • Add all views in `ViewHolder` and then initialise them in `getView` similar to the example above or in the link.. Then add all your methods after where it says `// You add all your methods here...`, and hopefully everything should work. – Musa Y. Apr 23 '15 at 11:00
  • This answer is assuming you have already implemented a custom adapter for your listview and this code would be in there. – Dreagen Apr 23 '15 at 11:05
  • 1
    @user3079872 if you need to pass in something which has strings and drawables, create a class which has both these items on it and pass it a list of that class – Dreagen Apr 23 '15 at 11:06
  • @Dreagen, you are absolutely right again! My CustomViewListAdapter is declared as: public CustomListViewAdapter(Context context, int resourceId, List items) { I am trying to pass a matrix cursor where I am expecting a list ... – user3079872 Apr 23 '15 at 11:43
  • @user3079872 In that case, make a class called RowItem, which has on it a variable for your cursor and a variable for your string. Then you can get them from the object inside the adapter. – Dreagen Apr 23 '15 at 12:02
  • @user3079872 However, it's probably not the best option to be passing cursors into the adapter and running queries in there due to performance issues, but maybe that's something to think about after you've got it working – Dreagen Apr 23 '15 at 12:03
  • @Dreagen, I got the code to at least compile (!) but it does not even show the row! Should I start a new question? I would need to post the custom adapter class code ... This is driving me crazy! Thanks a lot! – user3079872 Apr 23 '15 at 12:22
  • @user3079872 That's a good start! Post your adapter code here and I'll take a look – Dreagen Apr 23 '15 at 12:33
  • @Dreagen, I have edited my question with the new code. Thanks very much! – user3079872 Apr 23 '15 at 12:50