ImageButton в строке Android ListView не работает

У меня есть ListView со строкой, в которой есть ImageButton. Я могу щелкнуть определенную строку, и это работает: начинается новая ожидаемая активность. Но если я нажму ImageButton, а это элемент в строке, ничего не произойдет. ImageButton подсвечивается, но распечатка внутри onClick ImageButton не выполняется. Может ли кто-нибудь сказать мне, как я могу это решить? Вот мой код:

    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);
               }
             });

          }

        });

Вот XML для строки, где находится ImageButton:

<?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>

Спасибо большое!

ИЗМЕНИТЬ

Следуя предложениям, я создал пользовательский класс адаптера, чтобы показать строку. Поэтому я изменил код следующим образом: Основная активность теперь имеет следующие строки кода:

      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);

И CustomListViewAdapter выглядит так:

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;
}
}

XML такой же.

Он компилируется, но ничего не делает и теперь даже не показывает строку... Дайте мне знать, если вам нужно, чтобы я опубликовал код, который создает matrixCursor.

Большое спасибо, очень признателен.


person user3079872    schedule 23.04.2015    source источник
comment
Вы устанавливаете прослушиватель кликов кнопки только тогда, когда вы щелкаете строку (потому что вы вызываете ее из ToDolv.setOnItemClickListener, что не сработает. Вам нужно посмотреть на создание пользовательского адаптера для вашего списка и установить событие click для ваше изображение там. Эта ссылка может помочь stackoverflow.com/questions/8166497/   -  person Dreagen    schedule 23.04.2015
comment
Разместите класс адаптера.   -  person Raghavendra    schedule 23.04.2015
comment
Он использует SimpleCursorAdapter, он еще не создал собственный адаптер для списка, что является основной проблемой   -  person Dreagen    schedule 23.04.2015
comment
@Dreagen, ты прав. Как создать собственный адаптер для представления списка?   -  person user3079872    schedule 23.04.2015
comment
@user3079872 user3079872 ссылка, которую я указал в своем первом комментарии, содержит довольно хороший пример того, как это сделать. Я бы только переписал то, что там было, если бы поместил это здесь в качестве ответа. Попробуйте, и если у вас возникнут затруднения, опубликуйте свои усилия здесь, и я могу помочь вам сделать это правильно, если это необходимо.   -  person Dreagen    schedule 23.04.2015
comment
Узнайте, как создать собственное представление списка, здесь androidexample.com/   -  person Raghavendra    schedule 23.04.2015
comment
@Dreagen, спасибо, попробую и опубликую, если буду бороться.   -  person user3079872    schedule 23.04.2015
comment
попробуйте это, ImageButton chkDone = (ImageButton) arg1.findViewById(R.id.chkDone);   -  person Karn Shah    schedule 23.04.2015
comment
@Dreagen, теперь я создал собственный адаптер по примеру отправленной вами ссылки. Я борюсь со строкой, которая вызывает пользовательский класс адаптера: ListAdapter customAdapter = new ListAdapter(this, R.layout.itemlistrow, List‹yourItem›); --› что мне поставить вместо List‹yourItem›. Я использую матричный курсор для создания элементов, отображаемых в строке.   -  person user3079872    schedule 23.04.2015
comment
@user3079872 user3079872 Извините за мой поздний ответ, вам нужно передать List<String>, содержащий все элементы в вашем массиве строк columnNames, который вы передали в старый SimpleCursorAdapter   -  person Dreagen    schedule 23.04.2015
comment
@Dreagen, нет проблем, я уверен, что ты занят. Проблема, с которой я сталкиваюсь, заключается в том, что строка представляет собой не только строки, но и имеет TextViews, куда я помещаю строки, взятые из базы данных SQLite, а также ImageViews (рисунки). Поэтому я создал matrixCursor, который прекрасно работает, пока мне не понадобится ImageButton.   -  person user3079872    schedule 23.04.2015
comment
@user3079872 user3079872 Я думал, что мы продолжим здесь. Изменив конструктор вашего пользовательского адаптера, вы прекратите его работу. Ему все еще нужно передать List<Object>. Я попытаюсь написать ответ, чтобы показать, что я имею в виду.   -  person Dreagen    schedule 23.04.2015


Ответы (4)


Вам нужно создать собственный адаптер, который принимает список объектов, которые вы можете использовать для создания своего списка.

Вам нужно создать класс, который содержит информацию, необходимую в вашем списке. Из того, что вы сказали, примерно так:

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;
    }
}

Затем создайте эти объекты из элементов, которые вы хотите в своем списке.

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);

После создания списка объектов RowItem вы создаете свой собственный адаптер следующим образом:

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

Затем вы можете передать свой список объектов RowItem в свой собственный адаптер через его конструктор (как вы пытались сделать ранее):

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;
}
person Dreagen    schedule 23.04.2015
comment
С той информацией, что у меня есть, это лучший ответ, который я мог придумать. Надеюсь, это немного прояснит для вас ситуацию - person Dreagen; 23.04.2015
comment
большое спасибо, я очень благодарен за вашу помощь. Я поместил ваш код в свои классы. Вроде бы все в порядке, кроме строки rowItems = rowItems; что не нравится. он говорит, что _rowItems не может быть преобразован в переменную. Я пропустил импорт, чтобы справиться с для переменных? - person user3079872; 23.04.2015
comment
Добро пожаловать. Похоже, вы пропустили эту строку: ArrayList<RowItem> _rowItems = new ArrayList<>();, хотя в моем ответе в этой строке опечатка, и она могла бы быть немного короче. Я отредактирую свой ответ сейчас - person Dreagen; 23.04.2015
comment
Я отредактировал свой ответ сейчас. Убедитесь, что у вас есть строка: ArrayList<RowItem> _rowItems; в вашем CustomListViewAdapter - person Dreagen; 23.04.2015
comment
Да, спасибо. Однако он жалуется на строки: 'String columnName = rowItem.getColumnName(); ' и тот, что внизу. Еще один вопрос, который у меня есть, заключается в том, как мне вызвать CustomListViewAdapter из основного действия? У меня есть: 'CustomListViewAdapter customAdapter = new CustomListViewAdapter (это, R.layout.todo_row, List‹myItem1›);' Но это не нравится. Он говорит о синтаксической ошибке на токене ›, и это бит myItem1 ... еще раз, очень благодарен! - person user3079872; 23.04.2015
comment
Я отредактировал свой ответ, чтобы показать вам, как создать собственный адаптер (он находится в части создания списка объектов Row Item) - person Dreagen; 23.04.2015
comment
Я запустил его, но он по-прежнему ничего не показывает... Он даже не доходит до бита View getView... Я изменил rowItem.getColumnName(); в элемент.getColumnName(); но не думаю, что это будет иметь значение. Извините за невежество, но будет ли он знать, что нужно выполнить View getView, даже если он не вызывается ниоткуда? - person user3079872; 23.04.2015
comment
ваше изменение не заставило бы его не работать. getView вызывается платформой Android при отображении элементов списка, поэтому не беспокойтесь об этом. Я больше не смогу помогать, так как скоро уезжаю. Что бы я сделал сейчас, так это создал новый вопрос о том, что ваш пользовательский адаптер не показывает никаких элементов. Разместите свой собственный код адаптера вместе с кодом, в котором вы установили адаптер в своем списке. Ссылка на этот вопрос здесь, и я посмотрю, когда у меня будет шанс - person Dreagen; 23.04.2015
comment
спасибо, я сделаю, как вы предлагаете. Да, я читал о getView, и он должен вызываться фреймворком Android, так что что-то не так. Я приведу в порядок свой код, опубликую новый вопрос и попытаюсь связать его с этим ... это само по себе будет проблемой! Еще раз спасибо, я очень благодарен за вашу помощь. - person user3079872; 23.04.2015
comment
Даже если вы не можете связать этот вопрос с ним. Поместите ссылку на новый вопрос в комментарий здесь. Таким образом, я могу легко найти его - person Dreagen; 23.04.2015
comment
Я думаю, что мне удалось сослаться на этот вопрос в моем новом вопросе. Вот ссылка на новый вопрос: stackoverflow .com/questions/29829252/ Еще раз большое спасибо! - person user3079872; 23.04.2015
comment
@Draegen, я не знаю, как тебя отблагодарить! Теперь он работает отлично! И я понимаю, что делаю, что является бонусом!! Спасибо еще раз! - person user3079872; 24.04.2015
comment
@user3079872 user3079872 Рад слышать, что у вас все получилось! Удачи в остальном :) - person Dreagen; 24.04.2015

попробуй это

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

может это сработает для вас

person Moinkhan    schedule 23.04.2015
comment
может быть проблема в том, что вы регистрируете ImageButtonClick на ListView Click. это означает, что ваш щелчок по кнопке изображения не будет регистрироваться, пока вы не нажмете элемент списка. поэтому попробуйте переместить кнопку изображения, щелкнуть за пределами элемента списка, щелкнуть - person Moinkhan; 23.04.2015

Измените эту строку. Вы должны звонить findViewById() в свой AdapterView, а не в Activity.

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

ОБНОВЛЕНИЕ Верно, извините. Вы должны переопределить метод getView() в своем классе адаптера, который вам нужно создать. Должно быть так:

@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;
}
person Yurets    schedule 23.04.2015
comment
спасибо, я создал собственный класс адаптера и поместил в него приведенный выше код. Я борюсь со строкой кода, которая вызывает пользовательский адаптер: ListAdapter customAdapter = new ListAdapter(this, R.layout.itemlistrow, List‹yourItem›); Не уверен, что я должен указать для ‹yourItem›. Я использую матричный курсор для построения содержимого строки. - person user3079872; 23.04.2015

Глядя на ваш код Java, кажется, что у вас есть ImageButton OnClickListener внутри ListView OnItemClickListener. Поэтому поместите его вне этого метода, и я считаю, что он должен работать.

EDIT: Попробуйте это:

    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;
    }
person M-Y    schedule 23.04.2015
comment
это не сработает, потому что макет, содержащий ImageButton, определен внутри ListView - person Yurets; 23.04.2015
comment
Почему бы не определить его за пределами ListView OnItemClickListener? Думаю проблем не должно быть, попробуйте. - person M-Y; 23.04.2015
comment
Отредактировал мой ответ, так что попробуйте. - person M-Y; 23.04.2015
comment
@ M-Y, я бы с удовольствием попробовал, но глупый вопрос, как мне вызвать getView? - person user3079872; 23.04.2015
comment
Вот очень хороший пример того, как его использовать: examples.javacodegeeks.com/android/core/ui/listview/ - person M-Y; 23.04.2015
comment
@ M-Y, спасибо, я вижу, что передаваемый элемент представляет собой массив строк. В моей строке есть строки, а также рисунки, поэтому я использую матричный курсор. - person user3079872; 23.04.2015
comment
Добавьте все представления в ViewHolder, а затем инициализируйте их в getView, как в примере выше или в ссылке. Затем добавьте все свои методы после того, где указано // You add all your methods here..., и, надеюсь, все должно работать. - person M-Y; 23.04.2015
comment
Этот ответ предполагает, что вы уже реализовали собственный адаптер для своего списка, и этот код будет там. - person Dreagen; 23.04.2015
comment
@user3079872 user3079872, если вам нужно передать что-то, что имеет строки и чертежи, создайте класс, в котором есть оба этих элемента, и передайте ему список этого класса. - person Dreagen; 23.04.2015
comment
@Dreagen, ты снова абсолютно прав! Мой CustomViewListAdapter объявлен как: public CustomListViewAdapter (Context context, int resourceId, List‹RowItem› items) {Я пытаюсь передать матричный курсор, где я ожидаю список... - person user3079872; 23.04.2015
comment
@user3079872 user3079872 В этом случае создайте класс с именем RowItem, в котором есть переменная для вашего курсора и переменная для вашей строки. Затем вы можете получить их из объекта внутри адаптера. - person Dreagen; 23.04.2015
comment
@user3079872 user3079872 Однако, вероятно, это не лучший вариант - передавать курсоры в адаптер и выполнять там запросы из-за проблем с производительностью, но, возможно, об этом стоит подумать после того, как он заработает. - person Dreagen; 23.04.2015
comment
@Dreagen, я получил код, по крайней мере, для компиляции (!), Но он даже не показывает строку! Должен ли я начать новый вопрос? Мне нужно было бы опубликовать собственный код класса адаптера... Это сводит меня с ума! Большое спасибо! - person user3079872; 23.04.2015
comment
@user3079872 user3079872 Хорошее начало! Выложи сюда свой код адаптера, я посмотрю - person Dreagen; 23.04.2015
comment
@Dreagen, я отредактировал свой вопрос с новым кодом. Спасибо большое! - person user3079872; 23.04.2015