Спеціальна ListView проблема кліків на елементи в Android


110

Отже, у мене є власний об'єкт ListView. Елементи списку мають два текстові огляди, розміщені один на одного, плюс горизонтальну смужку ходу, яку я хочу залишати прихованою, поки я фактично щось не роблю. Край справа - прапорець, який я хочу відображати лише тоді, коли користувачеві потрібно завантажити оновлення до своєї бази даних. Коли я відключаю прапорець, встановлюючи видимість на Visibility.GONE, я можу натиснути на елементи списку. Коли прапорець видно, я не можу натиснути на що-небудь у списку, крім прапорців. Я здійснив пошук, але не знайшов нічого, що стосується моєї поточної ситуації. Я знайшов це питанняале я використовую перекритий ArrayAdapter, оскільки я використовую ArrayLists, щоб містити список баз даних внутрішньо. Чи потрібно мені просто переглянути перегляд LinearLayout і додати onClickListener, як це робив Том? Я не впевнений.

Ось макет рядка перегляду списку XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:padding="6dip">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="0dip"
        android:layout_weight="1"
        android:layout_height="fill_parent">
        <TextView
            android:id="@+id/UpdateNameText"
            android:layout_width="wrap_content"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:textSize="18sp"
            android:gravity="center_vertical"
            />
        <TextView
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:id="@+id/UpdateStatusText"
            android:singleLine="true"
            android:ellipsize="marquee"
            />
        <ProgressBar android:id="@+id/UpdateProgress" 
                     android:layout_width="fill_parent" 
                     android:layout_height="wrap_content"
                     android:indeterminateOnly="false" 
                     android:progressDrawable="@android:drawable/progress_horizontal" 
                     android:indeterminateDrawable="@android:drawable/progress_indeterminate_horizontal" 
                     android:minHeight="10dip" 
                     android:maxHeight="10dip"                    
                     />
    </LinearLayout>
    <CheckBox android:text="" 
              android:id="@+id/UpdateCheckBox" 
              android:layout_width="wrap_content" 
              android:layout_height="wrap_content" 
              />
</LinearLayout>

І ось клас, який розширює ListActivity. Очевидно, він ще в розробці, тож пробачте те, чого не вистачає або, можливо, залишиться прокладати:

public class UpdateActivity extends ListActivity {

    AccountManager lookupDb;
    boolean allSelected;
    UpdateListAdapter list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        lookupDb = new AccountManager(this);
        lookupDb.loadUpdates();

        setContentView(R.layout.update);
        allSelected = false;

        list = new UpdateListAdapter(this, R.layout.update_row, lookupDb.getUpdateItems());
        setListAdapter(list);

        Button btnEnterRegCode = (Button)findViewById(R.id.btnUpdateRegister);
        btnEnterRegCode.setVisibility(View.GONE);

        Button btnSelectAll = (Button)findViewById(R.id.btnSelectAll);
        btnSelectAll.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                allSelected = !allSelected;

                for(int i=0; i < lookupDb.getUpdateItems().size(); i++) {
                    lookupDb.getUpdateItem(i).setSelected(!lookupDb.getUpdateItem(i).isSelected());
                }

                list.notifyDataSetChanged();
                // loop through each UpdateItem and set the selected attribute to the inverse 

            } // end onClick
        }); // end setOnClickListener

        Button btnUpdate = (Button)findViewById(R.id.btnUpdate);
        btnUpdate.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
            } // end onClick
        }); // end setOnClickListener

        lookupDb.close();
    } // end onCreate


    @Override
    protected void onDestroy() {
        super.onDestroy();

        for (UpdateItem item : lookupDb.getUpdateItems()) {
            item.getDatabase().close();        
        }
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        UpdateItem item = lookupDb.getUpdateItem(position);

        if (item != null) {
            item.setSelected(!item.isSelected());
            list.notifyDataSetChanged();
        }
    }

    private class UpdateListAdapter extends ArrayAdapter<UpdateItem> {
        private List<UpdateItem> items;

        public UpdateListAdapter(Context context, int textViewResourceId, List<UpdateItem> items) {
            super(context, textViewResourceId, items);
            this.items = items;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View row = null;

            if (convertView == null) {
                LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                row = li.inflate(R.layout.update_row, null);
            } else {
                row = convertView;
            }

            UpdateItem item = items.get(position);

            if (item != null) {
                TextView upper = (TextView)row.findViewById(R.id.UpdateNameText);
                TextView lower = (TextView)row.findViewById(R.id.UpdateStatusText);
                CheckBox cb = (CheckBox)row.findViewById(R.id.UpdateCheckBox);

                upper.setText(item.getName());
                lower.setText(item.getStatusText());

                if (item.getStatusCode() == UpdateItem.UP_TO_DATE) {
                    cb.setVisibility(View.GONE);
                } else {
                    cb.setVisibility(View.VISIBLE);
                    cb.setChecked(item.isSelected());
                }

                ProgressBar pb = (ProgressBar)row.findViewById(R.id.UpdateProgress);
                pb.setVisibility(View.GONE);
            }
            return row;
        }

    } // end inner class UpdateListAdapter
}

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

Відповіді:


243

Проблема полягає в тому, що Android не дозволяє вам вибирати елементи списку, на яких є елементи, орієнтовані на них. Я змінив прапорець на елементі списку, щоб мати такий атрибут:

android:focusable="false"

Тепер елементи мого списку, які містять прапорці (працює і для кнопок), "вибираються" в традиційному розумінні (вони загоряються, ви можете натиснути будь-де в елементі списку, і обробник "onListItemClick" запустить і т.д.).

EDIT: Як оновлення, коментатор зазначив "Просто зауваження, після зміни видимості кнопки мені довелося знову програматично відключити фокус".


24
Здається, це рішення не працює, коли ImageButton використовується в елементі списку. :(
Джуліан А.

1
Гаразд, але що робити, якщо я хочу, щоб прапорець і мій перегляд списку були взаємовиключними? Якщо я вибираю пункт ListView, я не обов'язково хочу перевіряти прапорець. Чи можливо це за допомогою цього рішення?
Mike6679

@Mike Так, для цього рішення все одно потрібно чітко натискати прапорець, щоб взаємодіяти з ним. Він просто відновлює функціональність у ListView, який загадково обходить, коли у макеті елемента списку ви маєте фокусуються елементи.
MattC

2
Чудова відповідь дякую, добре працює і з ImageButtons. Лише зауваження, після зміни видимості кнопки мені довелося знову програмно відключити фокусування.
Ljdawson

1
вам може знадобитися встановити android: clickable = "false"
Міна Самі

43

Якщо у вас є елемент ImageButton всередині елемента списку, вам слід встановити descendantFocusabilityзначення "blocksDescendants" у елементі елемента кореневого списку.

android:descendantFocusability="blocksDescendants"

І focusableInTouchModeпрапор trueв ImageButtonподанні.

android:focusableInTouchMode="true"

1
Це ідеально підходить для списку, що має кнопки зображення. Але це може працювати, окрім ImageButton
raksja

12

У мене виникли подібні проблеми, і я виявив, що CheckBox досить вибагливий у ListView. Що трапляється, це нав'язує волю на весь ListItem і начебто перекриває onListItemClick. Ви можете застосувати для цього обробник кліків і встановити властивість тексту для CheckBox, а не використовувати TextViews.

Я б сказав, що також загляньте в цей об'єкт View, він може працювати краще, ніж CheckBox

Перевірений перегляд тексту


6
Я виявив, що якщо встановити параметр "фокусируемого" значення "false" для елементів, що фокусуються у списку, ви можете знову використовувати функцію onListItemClick.
MattC

2
Однак прапорець стає помаранчевим, як елемент списку. Хтось знає рішення?
erdomester

8

використовувати цей рядок у корінному перегляді елемента списку

android: descendantFocusability = "блокиDescendants"

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