Список рассылки Android: невозможно получить достоверное поведение при проверке CHOICE_MODE_SINGLE - PullRequest
3 голосов
/ 23 марта 2012

Вот что я имею в виду под странным:

  1. Для элементов обычно требуется 2 нажатия, чтобы правильно изменить цвет фона.
  2. При изменении списка Android кажется некорректно аннулировать представления списка, поскольку проверенные повторно используемые представления имеют проверенный фон для новых элементов (которые я подтвердил с помощью отладчика: не проверено).
  3. Несколько элементов могутвыглядят как выбранные, и на самом деле «правильно» снимите флажок, когда я нажимаю на них снова, за исключением того факта, что ListView сообщает только о самом последнем элементе, как проверено.
  4. Первый раз, когда яотметьте элемент, я не могу снять его, щелкнув по нему.
  5. Все работает более или менее хорошо, если я изменяю режим выбора на ListView.CHOICE_MODE_MULTIPLE, за исключением, разумеется, того, что я не хочу множественноговыделение.

Я использую пользовательский адаптер и пользовательский макет.О, также, нацеливаясь на 4.0.3 пока.Вот код для списка:

ListView categoryList = (ListView) findViewById(R.id.categoryList);
categoryList.setAdapter(categoryAdapter);
categoryList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
categoryList.setItemsCanFocus(false);
categoryList.setOnItemClickListener(categoryAdapter);

Вот прослушиватель щелчков:

public void onItemClick(AdapterView<?> parent, View view, int position, long id) {              
    ListView listView = (ListView) parent;  
    RemoteListItem remoteListItem = (RemoteListItem) view.getTag();

    if (remoteListItem.isEnabled()) {
        remoteListItem.action(view);
    }
    view.invalidate(); /added out of sheer desperation              
}

Вот расширенная версия RelativeLayout, которую я использую:

package com.sastraxi.machineshop.ui;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Checkable;
import android.widget.RelativeLayout;

/**
 * RelativeLayout that implements the Checkable interface.
 * Set this view's tag as a Checkable, and this layout will delegate
 * Checkable's interface methods to the tag object. 
 */
public class CheckableRelativeLayout extends RelativeLayout implements Checkable {

    @Override
    public boolean isClickable() {
        return false;
    }

    public CheckableRelativeLayout(Context context) {
        super(context);
    }

    public CheckableRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CheckableRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * Delegates to (Checkable) getTag().
     */
    public boolean isChecked() {        
        try {
            Checkable checkableTag = (Checkable) getTag();
            return checkableTag.isChecked();
        } catch (ClassCastException e) {
            Log.w("CheckableRelativeLayout", "Tag is not an instance of Checkable; this object won't do anything useful.");
        } catch (NullPointerException e) {
            Log.w("CheckableRelativeLayout", "Tag is null; this object won't do     anything useful.");
        }       
        return false;
    }

    /**
     * Delegates to (Checkable) getTag().
     */
    public void setChecked(boolean checked) {
        try {
            Checkable checkableTag = (Checkable) getTag();
            checkableTag.setChecked(checked);
            invalidate();
        } catch (ClassCastException e) {
            Log.w("CheckableRelativeLayout", "Tag is not an instance of Checkable; this object won't do anything useful.");
        } catch (NullPointerException e) {
            Log.w("CheckableRelativeLayout", "Tag is null; this object won't do anything useful.");
        }
    }

    /**
     * Delegates to (Checkable) getTag().
     */
    public void toggle() {
        try {
            Checkable checkableTag = (Checkable) getTag();
            checkableTag.toggle();
            invalidate();
        } catch (ClassCastException e) {
            Log.w("CheckableRelativeLayout", "Tag is not an instance of Checkable; this object won't do anything useful.");
        } catch (NullPointerException e) {
            Log.w("CheckableRelativeLayout", "Tag is null; this object won't do anything useful.");
        }
    }

    private static final int[] CHECKED_STATE_SET = {
        android.R.attr.state_checked
    };

    /**
     * Reflect the delegate Checkable's state in this View's state set.
     */
    @Override    
    protected int[] onCreateDrawableState(int extraSpace) {
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
        if (isChecked()) {
            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
        }     
        return drawableState;
    }

}

Вот тип элемента списка, к которому он относится:

public abstract class RemoteListItem implements Checkable {

    private final String name;
    private final String extra;
    private boolean enabled = true;
    private boolean selected = false;

    public boolean isChecked() {
        return selected;
    }

    public void toggle() {
        selected = !selected;
    }

    public void setChecked(boolean checked) {
        selected = checked;
    }

    public RemoteListItem(String name, String extra) {
        this.name = name;
        this.extra = extra;     
    }

    public String getExtra() {
        return extra;
    }

    public String getName() {
        return name;
    }

    public abstract void action(View viewInList);

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
        RemoteListAdapter.super.notifyDataSetChanged();
    }

    public boolean isSelectable() {
        return true;
    }

}

Вот макет, который расширяется для элементов:

<?xml version="1.0" encoding="utf-8"?>
<com.sastraxi.machineshop.ui.CheckableRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
    android:layout_height="?android:attr/listPreferredItemHeightSmall"
    android:padding="12dp"  
    android:gravity="center_vertical"
    android:background="@drawable/listitem_background">

    <TextView
        android:id="@+id/key"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_alignParentLeft="true"    
        android:inputType="none"   
    />

    <TextView
        android:id="@+id/value"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:gravity="right"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textColor="@color/faded_text_colour"
        android:layout_alignParentRight="true"
        android:inputType="none"
    />

    <ProgressBar
         android:id="@+id/progress"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         style="@android:style/Widget.ProgressBar.Small"
         android:layout_marginTop="5dip"
         android:layout_marginRight="2dip"
         android:gravity="right"
         android:visibility="gone"
         android:layout_alignParentRight="true"/>

</com.sastraxi.machineshop.ui.CheckableRelativeLayout>

Кроме того, @ drawable / listitem_background - это список состояний, которыйоткуда проверяется цвет фона.Я чувствую себя настолько растерянным из-за того, что все работает не так, как я ожидаю.Кажется, я где-то пропускаю view.invalidate(), но не могу понять, где.

Ответы [ 2 ]

0 голосов
/ 29 марта 2012

Я закончил тем, что создал новый BaseAdapter, который экономит мне лот горя с каждым ListView в моем проекте. Вот ссылка на совет по github для тех, кто ищет решение подобных проблем.

Базовые классы адаптеров: SmartListAdapter и SimplerSmartListAdapter

Реализующий класс: OpenFilesAdapter реализует SimplerSmartListAdapter.

Базовые классы позволяют вам выбирать такие вещи, как: кликабелен ли каждый элемент, можно проверить или нет; максимальное количество проверенных элементов одновременно и предоставляет заголовки категорий бесплатно. Он также позволяет перемещать обработчик кликов и обновления пользовательского интерфейса в адаптер.

Разница между двумя базовыми классами заключается в том, что SmartListAdapter позволяет вам определить пользовательское отображение из «списка поддержки» в список элементов, которые фактически отображаются, что полезно, например поддержание постоянного списка поддержки и показ / скрытие элементов в зависимости от контекста. SimplerSmartListAdapter расширяет SmartListAdapter, определяя это отображение как биективное.

0 голосов
/ 23 марта 2012

Звучит так, будто ваше первое прикосновение дает ему фокус, второе регистрируется как щелчок. Установите элемент на не сфокусированный, и ваше первое касание должно регистрироваться как щелчок.

...