Як запустити onListItemClick у списку Списку за допомогою кнопок у списку?


89

У мене є проста ListActivity, яка використовує спеціальний ListAdapter для генерації подань у списку. Зазвичай ListAdapter просто заповнює подання TextViews, але тепер я хочу також туди поставити кнопку.

Однак я розумію та маю досвід, що розміщення фокусуючого подання в елементі списку перешкоджає спрацьовуванню onListItemClick () у ListActivity при натисканні на елемент списку. Кнопка все ще нормально функціонує в елементі списку, але коли натискається щось крім кнопки, я хочу, щоб спрацьовувало onListItemClick.

Як я можу зробити цю роботу?


5
ваше рішення з нащадком Фокусивність справді корисне, ви повинні додати його як відповідь і прийняти!
Максим Гонтар

@Max Причина, по якій я цього не роблю, полягає в тому, що це насправді погана практика, обхідний шлях. Якби я коли-небудь знайшов постійне здорове рішення, я відповів би на це (якщо пам’ятаю, що писав це питання рік тому :))
CodeFusionMobile

Я також хотів би побачити обхідне рішення, яке у вас є. Я намагався встановити фокус нащадка і не можу змусити його працювати за допомогою кнопок. Також я намагався додати GridView (із вбудованими ImageViews) до рядка списку, що має подібні проблеми.
MrPurpleStreak

Відповідь IMHO, яку я дав, є набагато елегантнішим рішенням проблеми, ніж запропонована Рампсом та Правіном. PsНе намагається оживити тут забуте питання, але я бачу, що ти ще не прийняв жодної відповіді; D
Ewoks,

@CodeFusionMobile Не могли б ви прийняти відповідь Ewoks? Відповідь з найбільшою оцінкою є недосконалою, оскільки вона відключає анімацію onclick для елемента ListView (де вона стає синьою). Це заощадило б іншим розробникам трохи часу, витраченого на те, щоб знайти найкращу відповідь, з’ясувавши, що це недоліки, а потім перейшовши до Ewoks.
1 ''

Відповіді:


99

як я писав у попередньому коментарі, рішення - це setFocusable (false) на ImageButton.

Є ще більш елегантне рішення, спробуйте додати android:descendantFocusability="blocksDescendants" в кореневому макеті елемента списку. Це зробить можливі кліки onListItem, і ви зможете окремо обробляти натискання кнопки Button або ImageButton

Сподіваюся, це допоможе;)

Ура


3
android:descendantFocusability="blocksDescendants"був ідеальним.
Метью Мітчелл,

1
ти, друже мій, мій особистий герой. ти повинен бути одним із найбільших голосів! це набагато краще майже для будь-яких випадків!
OschtärEi

Це має бути прийнятою відповіддю. У мене це спрацювало чудово. Схоже, що всі подання в елементі списку мають бути нефокусованими, і цей робить саме це, не встановлюючи кожен окремо.
пік

1
Здається, це не працює для мене. Під кореневим макетом ви маєте на увазі макет рядка або де визначено перегляд списку? Як би там не було, я спробував усі можливі комбінації .. не працює :(
GreenBee

"Кореневий макет елемента списку", як я вже писав. Отже, припустимо, у вас є список, що складається з макетів (назвіть їх кореневим макетом елемента списку), які мають кілька Button, ImageButton, TextVeiw ..
Ewoks

59

Сподіваюся, я можу тут допомогти. Я припускаю, що у вас є власний макет для елементів listView, і цей макет складається з кнопок та деяких інших подань - як TextView, ImageView чи що інше. Тепер ви хочете, щоб при натисканні кнопки запускалася різна подія, а по всьому іншому натискалася інша подія.

Ви можете досягти цього, не використовуючи onListItemClick () своєї ListActivity.
Ось що вам потрібно зробити:

Ви використовуєте нестандартне макетування, тому, ймовірно, ви перевизначаєте метод getView () зі свого користувацького адаптера. Фокус полягає в тому, щоб встановити різних прослуховувачів для вашої кнопки та різних для всього перегляду (вашого рядка). Погляньте на приклад:

private class MyAdapter extends ArrayAdapter<String> implements OnClickListener {

    public MyAdapter(Context context, int resource, int textViewResourceId,
            List<String> objects) {
        super(context, resource, textViewResourceId, objects);
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        String text = getItem(position);
        if (null == convertView) {
            convertView = mInflater.inflate(R.layout.custom_row, null);
        }
        //take the Button and set listener. It will be invoked when you click the button.
        Button btn = (Button) convertView.findViewById(R.id.button);
        btn.setOnClickListener(this);
        //set the text... not important     
        TextView tv = (TextView) convertView.findViewById(R.id.text);
        tv.setText(text);
        //!!! and this is the most important part: you are settin listener for the whole row
        convertView.setOnClickListener(new OnItemClickListener(position));
        return convertView;
    }

    @Override
    public void onClick(View v) {
        Log.v(TAG, "Row button clicked");
    }
}

Ваш клас OnItemClickListener можна оголосити, як тут:

private class OnItemClickListener implements OnClickListener{       
    private int mPosition;
    OnItemClickListener(int position){
        mPosition = position;
    }
    @Override
    public void onClick(View arg0) {
        Log.v(TAG, "onItemClick at position" + mPosition);          
    }       
}

Звичайно, ви, мабуть, додасте ще кілька параметрів до конструктора OnItemClickListener.
І одна важлива річ - реалізація getView, показана вище, досить потворна, зазвичай вам слід використовувати шаблон ViewHolder, щоб уникнути дзвінків findViewById .. але ви, напевно, це вже знаєте.
Мій файл custom_row.xml - RelativeLayout з кнопкою id "button", TextView id "text" та ImageView id "image" - лише для того, щоб все зрозуміло.
З повагою!


9
Моє рішення закінчилося іншим шляхом. Я вирішив проблему, встановивши властивість Focusability нащадка для макета рядка списку, щоб блокувати нащадків, і раптом це спрацювало. Тепер я використовую simpleCursorAdapter із прикріпленим до нього спеціальним видошукачем для налаштування подій та інших вигадливих речей, пов’язаних із кнопками.
CodeFusionMobile

3
Я використав це рішення. Однак попередження: якщо ваш обробник onClick спричиняє зміну вмісту списку, що призведе до виклику getView І якщо ваш віджет має статус стану (наприклад, ToggleButton або CheckBox), і getView встановлює цей стан, ви можете встановити setOnClickListener (null) перед тим, як змінити стан у onView, щоб уникнути отримання ефекту циклу.
Pierre-Luc Paour

3
як щодо мого рішення? У мене складається враження, що він більш елегантний і може бути застосований простіше, коли нам це потрібно ..
Евокс,

перший коментар повинен бути прийнятий як відповідь, тому таким людям, як я, не знадобиться годин, щоб знайти його
keybee

Дякую! Це було корисно. Мені це подобається як більш локалізована альтернатива фокусу: підхід blockDescendants, описаний в інших потоках.
Йоав Шапіра

18

Коли користувальницький ListView містить сфокусовані елементи, onListItemClick не буде працювати (я думаю, це очікувана поведінка). Просто видаліть фокус із власного подання, це зробить трюк:

Наприклад:

public class ExtendedCheckBoxListView extends LinearLayout {

    private TextView mText;
    private CheckBox mCheckBox;

    public ExtendedCheckBoxListView(Context context, ExtendedCheckBox aCheckBoxifiedText) {
         super(context);
         
         mText.setFocusable(false);
         mText.setFocusableInTouchMode(false);

         mCheckBox.setFocusable(false);
         mCheckBox.setFocusableInTouchMode(false);
               
    }
}

3
Мені подобається ваше рішення: якщо на рядок є лише один віджет, який можна натискати, то відмовити їм у фокусуванні - це елегантне рішення. Це означає, що натискання в будь-якому місці рядка буде збігатися, але це корисна поведінка, коли віджет є радіо або прапорцем. Те саме можна досягти в XML за допомогою android: focusable = "false" та android: focusableInTouchMode = "false".
П'єр-Люк Паур,

1
XML-спосіб, здається, не працює, якщо ви зміните видимість, тому потрібно робити це за допомогою коду, встановивши для "Перегляду" значення "видиме"
max4ever

13

У мене така сама проблема: OnListItemClick не запускається! [ВИРІШЕНО]
Це трапляється з класом, який розширює ListActivity,
із макетом для ListActivity, який вміщує TextBox і ListView, вкладені в LinearLayout
та іншим макетом для рядків (CheckBox і TextBox, вкладеними в LineraLayout).

Це код:

res / layout / configpage.xml (основне для ListActivity)

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent" > 
    <TextView  
        android:id="@+id/selection"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="pippo" /> 
    <ListView  
        android:id="@android:id/list"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:drawSelectorOnTop="false"  
        android:background="#aaFFaa" > 
    </ListView> 
<LinearLayout> 

res/layout/row.xml (layout for single row)  
<LinearLayout  
  xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"> 
  <CheckBox  
      android:id="@+id/img"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content"  
      **android:focusable="false"**  
      **android:focusableInTouchMode="false"** /> 

  <TextView  
      android:id="@+id/testo"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content"  
      **android:focusable="false"**  
      **android:focusableInTouchMode="false"** /> 
</LinearLayout> 

src /.../.../ ConfigPage.java

public class ConfigPage extends ListActivity
{
    TextView selection;

    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.configpage);  
        // loaded from res/value/strings  
        String[] azioni = getResources().getStringArray(R.array.ACTIONS);  
        setListAdapter(new ArrayAdapter&lt;String&gt;(this, R.layout.row, 
                R.id.testo,   azioni));  
        selection = (TextView) findViewById(R.id.selection);  
    }       

    public void onListItemClick(ListView parent, View view, int position, long id)
    {
        selection.setText(" " + position);
    }
}

Це починає працювати, коли я додав у row.xml

  • android:focusable="false"
  • android:focusableInTouchMode="false"

Я використовую Eclipse 3.5.2
Android SDK 10.0.1
хв версія SDK: 3

Сподіваюся, це корисно
... і вибачте за мою англійську :(


@fellons не знаю чому, але у мене це не спрацювало. Мій onListItemClick не викликається.
likejudo

Ви додали код властивостей android: focusable = "false" та android: focusableInTouchMode = "false" код?
rfellons

2

просто додайте android:focusable="false"як один із атрибутів кнопки


1

У мене була та ж проблема з ToggleButton. Після південного удару головою об стіну я нарешті вирішив це. Це настільки просто, як зробити фокусуючий вигляд нефокусуючим, використовуючи „android: focusable“. Вам також слід уникати гри з фокусуванням та клікабельністю (я щойно склав слова) рядка списку, просто залиште їм значення за замовчуванням.

Звичайно, тепер, коли ваші фокусуючі погляди в рядку списку не можна сфокусувати, користувачі, які використовують клавіатуру, можуть мати проблеми, ну, фокусуючи їх. Це, швидше за все, не буде проблемою, але на той випадок, якщо ви хочете написати 100% бездоганні програми, ви можете використовувати подію onItemSelected, щоб зробити елементи вибраного рядка фокусируемими, а елементи попередньо вибраного рядка - нефокусуючими.


Я використав такий підхід. Це найпростіший спосіб, якщо ви можете обійти проблему неможливості зосередитись на окремих предметах. Це також утримує державні видатки для елементів списку такими, якими вони повинні бути, чого не роблять деякі інші обхідні шляхи.
Джонатан С.

1
 ListView lv = getListView();
lv.setTextFilterEnabled(true);

lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
    int position, long id) {
  // When clicked, show a toast with the TextView text
  Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
      Toast.LENGTH_SHORT).show();
}
});

-1

Я використовував getListAdapter (). GetItem (position), створюючи екземпляр Об’єкта, що містить мої значення в елементі

MyPojo myPojo = getListAdapter().getItem(position);

потім використав метод getter з myPojo, він викличе належні значення в елементі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.