Android ListView дочерний вид setEnabled () и setClickable () ничего не делают - PullRequest
8 голосов
/ 09 января 2011

Я выполняю некоторую AsyncTask работу после того, как пользователь щелкает элемент в моем ListView. Я бы хотел отключить элемент, чтобы его нельзя было щелкнуть дважды. Я упростил прослушиватель щелчков, чтобы он содержал только этот метод, но он все равно ничего не делает для меня, вид выглядит так же, и он позволяет снова счастливо щелкать, к моему большому раздражению.

public void onItemClick(AdapterView<?> parent, View clickedView,
  int position, long id) {
  item = (Episode) parent.getItemAtPosition(position);
  clickedView.setClickable(false);
  clickedView.setEnabled(false);
  clickedView.invalidate();
}

Мой просмотр для каждой строки - это пользовательский LinearLayout с двумя TextView с.

Ответы [ 4 ]

20 голосов
/ 09 января 2011

Итак, вы можете использовать и собственный адаптер.Если вы это сделаете, переопределите эти методы:

public boolean areAllItemsEnabled() {
    return false;
}

public boolean isEnabled(int position) {
    // return false if position == position you want to disable
}

Затем, когда вы получите щелчок, сообщите адаптеру, какой последний элемент был нажат, и верните false на isEnabled для этой позиции.Например, у вас может быть такой метод в вашем адаптере:

private int mLastClicked;
public void setLastClicked(int lastClicked){
    mLastClicked = lastClicked;
}
18 голосов
/ 12 мая 2011

Если вы хотите отключить элемент, нажмите в списке, используйте clickedView.setClickable(true);

5 голосов
/ 09 января 2011

Ваша проблема не совсем ясна. Я интерпретирую ваш вопрос так, как будто вы ожидаете, что onItemClick() не будет вызван на основании ваших setEnabled() и setClickable() вызовов.

Я не удивлен, что это не работает, поскольку onItemClick() - это то, что делает ListView, а не дочерний вид. Попробуйте переопределить areAllItemsEnabled() и isEnabled() в вашем ListAdapter.

4 голосов
/ 09 января 2011

Существует несколько причин, по которым ваш подход не будет работать.

1) onItemClick вызывается только из-за событий клавиатуры. В частности KeyKevent.KEYCODE_ENTER. Он не вызывается через любой другой путь кода. Таким образом, даже если вы пытаетесь обеспечить поддержку клавиатуры / трекбола, это полезно.

Исходный код Android для соответствующих методов AbsListView:

public boolean onKeyUp(int keyCode, KeyEvent event) {
    switch (keyCode) {
    case KeyEvent.KEYCODE_DPAD_CENTER:
    case KeyEvent.KEYCODE_ENTER:
        if (!isEnabled()) {
            return true;
        }
        if (isClickable() && isPressed() &&
                mSelectedPosition >= 0 && mAdapter != null &&
                mSelectedPosition < mAdapter.getCount()) {

            final View view = getChildAt(mSelectedPosition - mFirstPosition);
            if (view != null) {
                performItemClick(view, mSelectedPosition, mSelectedRowId);
                view.setPressed(false);
            }
            setPressed(false);
            return true;
        }
        break;
    }
    return super.onKeyUp(keyCode, event);
}

public boolean performItemClick(View view, int position, long id) {
    if (mOnItemClickListener != null) {
        playSoundEffect(SoundEffectConstants.CLICK);
        mOnItemClickListener.onItemClick(this, view, position, id);
        return true;
    }

    return false;
}

2) Вы настраиваете активируемую информацию прямо в представлении. Представления, отображаемые через любой AdapterView, являются эфирными. Они создаются по запросу AdapterView и существуют только до тех пор, пока они нужны AdapterView. Вы не должны устанавливать на них данные, которые хотите сохранить. Вы можете вызвать setEnabled и setClickable на них для немедленного эффекта, но если вы хотите, чтобы эта информация сохранялась, вам нужно сохранить ее где-нибудь, к чему у Adapter есть доступ, чтобы ее можно было воссоздать, когда AdapterView воссоздает View для этой позиции.

3) Вам нужно обработать событие onClick для фактического нажатия View. Где вы справляетесь, зависит от вас. Лучшее место - это, вероятно, ваш Adapter, который может или не может передать его вашему Activity в зависимости от ваших требований к дизайну. Вот где вам нужно обрабатывать сенсорные события.

См. Этот код для простого упражнения:

public class PhoneTesting extends Activity {
    private static final String TAG = "PhoneTesting";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.d(TAG, "onCreate()");

        List<String> strings = new ArrayList<String>();
        for(int i = 0 ; i < 20 ; i++) {
            strings.add(Integer.toString(i));
        }

        ListView list = (ListView) this.findViewById(R.id.list);

        list.setAdapter(new SimpleAdapter(this, 0, 0, strings));
        list.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Log.d(TAG, "onItemClick: " + id);
            }
        });

    }

    class SimpleAdapter extends ArrayAdapter<String> implements OnClickListener {
        SimpleAdapter(Context context, int resource, int textViewResourceId, List<String> objects) {
            super(context, resource, textViewResourceId, objects);
        }

        SimpleAdapter(Context context, int resource, int textViewResourceId, String[] objects) {
            super(context, resource, textViewResourceId, objects);
        }

        SimpleAdapter(Context context, int resource, int textViewResourceId) {
            super(context, resource, textViewResourceId);
        }

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

        SimpleAdapter(Context context, int textViewResourceId, String[] objects) {
            super(context, textViewResourceId, objects);
        }

        SimpleAdapter(Context context, int textViewResourceId) {
            super(context, textViewResourceId);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            TextView b = position % 2 == 0 ? new Button(this.getContext()) : new TextView(this.getContext());
            b.setText(this.getItem(position));

            b.setOnClickListener(this);

            return b;
        }

        @Override
        public void onClick(View v) {
            TextView t = (TextView) v;
            Log.d(TAG, "onClick: " + t.getText());
        }

        @Override
        public boolean isEnabled(int position) {
            return position % 2 == 0 ? false : true;
        }

    }
}

Если вы выполните этот код и нажмете на любой из View s в ListView, вы увидите в выводе logcat, что вызывается только onClick. onItemClick никогда не вызывается.

Также обратите внимание, что isEnabled в адаптере, кажется, не действует, если View активен или нет. Я не уверен, как это интерпретировать. Однако это означает, что если вы хотите управлять этим свойством View, Adapter необходимо установить его при создании View и как-то поддерживать эту информацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...