Eu gostaria de saber o que difere esses estados. Não encontrei nenhuma página da web esclarecendo isso.
Eu gostaria de saber o que difere esses estados. Não encontrei nenhuma página da web esclarecendo isso.
Respostas:
A diferença entre verificado e ativado é bastante interessante. Até mesmo a documentação do Google é apologética (ênfase adicionada):
... Por exemplo, em uma exibição de lista com seleção única ou múltipla habilitada, as exibições no conjunto de seleção atual são ativadas. (Hum, sim, lamentamos profundamente a terminologia aqui.) O estado ativado é propagado para os filhos da visualização em que está definido.
Então aqui está a diferença:
ListView (após Honeycomb) chama setChecked () OU setActivated () dependendo da versão do Android conforme abaixo (obtido do código-fonte do Android):
if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
if (child instanceof Checkable) {
((Checkable) child).setChecked(mCheckStates.get(position));
} else if (getContext().getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.HONEYCOMB) {
child.setActivated(mCheckStates.get(position));
}
}
Observe a variável mCheckStates. Ele mantém o controle de quais posições em sua lista são verificadas / ativadas. Eles são acessíveis via, por exemplo, getCheckedItemPositions (). Observe também que uma chamada para ListView.setItemChecked () invoca o acima. Em outras palavras, ele também poderia ser chamado de setItemActivated ().
Antes do Honeycomb, tínhamos que implementar soluções alternativas para refletir state_checked em nossos itens de lista. Isso ocorre porque ListView chama setChecked () SOMENTE na View superior no layout (e os layouts não implementam verificável) ... e NÃO se propaga sem ajuda. Essas soluções alternativas tinham o seguinte formato: Estenda o layout raiz para implementar Checkable. Em seu construtor, encontre recursivamente todos os filhos que implementam Checkable. Quando setChecked () etc ... são chamados, passe a chamada para essas visualizações. Se essas visualizações implementam drawables da lista de estados (por exemplo, um CheckBox) com um drawable diferente para state_checked, então o estado verificado é refletido na IU.
Para fazer um bom plano de fundo para um item de lista após o Honeycomb, tudo que você precisa fazer é ter um drawable da lista de estados com um drawable para o estado state_activated assim (e usar setItemChecked () é claro):
<item android:state_pressed="true"
android:drawable="@drawable/list_item_bg_pressed"/>
<item android:state_activated="true"
android:drawable="@drawable/list_item_bg_activated"/>
<item android:drawable="@drawable/list_item_bg_normal"/>
Para fazer um bom pano de fundo para um item de lista antes do HoneyComb, você faria algo como o acima para state_checked e TAMBÉM precisa estender sua visão superior para implementar a interface Checkable. Dentro disso, você precisa dizer ao Android se o estado que está implementando é verdadeiro ou falso, implementando onCreateDrawableState () e chamando refreshDrawableState () sempre que o estado muda.
<item android:state_pressed="true"
android:drawable="@drawable/list_item_bg_pressed"/>
<item android:state_checked="true"
android:drawable="@drawable/list_item_bg_checked"/>
<item android:drawable="@drawable/list_item_bg_normal"/>
... e o código para implementar Checkable combinado com state_checked em um RelativeLayout poderia ser:
public class RelativeLayoutCheckable extends RelativeLayout implements Checkable {
public RelativeLayoutCheckable(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RelativeLayoutCheckable(Context context) {
super(context);
}
private boolean mChecked = false;
@Override
protected void onFinishInflate() {
super.onFinishInflate();
}
@Override
public boolean isChecked() {
return mChecked;
}
@Override
public void setChecked(boolean checked) {
mChecked = checked;
refreshDrawableState();
}
private static final int[] mCheckedStateSet = {
android.R.attr.state_checked,
};
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, mCheckedStateSet);
}
return drawableState;
}
@Override
public void toggle() {
setChecked(!mChecked);
}
}
Graças ao seguinte:
http://sriramramani.wordpress.com/2012/11/17/custom-states/
Stackoverflow: como adicionar um estado de botão personalizado
Stackoverflow: Visualização verificável personalizada que responde ao Seletor
http://www.charlesharley.com/2012/programming/custom-drawable-states-in-android/
http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList
http://blog.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/
Selection is a transient property, representing the view (hierarchy) the user is currently interacting with. Activation is a longer-term state that the user can move views in and out of. For example, in a list view with single or multiple selection enabled, the views in the current selection set are activated. (Um, yeah, we are deeply sorry about the terminology here.) fonte
setItemChecked()e usando um seletor com propriedadeandroid:state_activated="true"
De acordo com o doc :
android: booleano selecionado por estado . " true" se este item deve ser usado quando o objeto é a seleção atual do usuário ao navegar com um controle direcional (como ao navegar por uma lista com um d-pad); " false" se este item deve ser usado quando o objeto não está selecionado. O estado selecionado é usado quando o foco (android: state_focused) não é suficiente (como quando a exibição de lista tem foco e um item dentro dela é selecionado com um d-pad).
android: booleano state_checked . " true" se este item deve ser usado quando o objeto é verificado; " false" se deve ser usado quando o objeto está desmarcado.
android: booleano state_activated . " true" se este item deve ser usado quando o objeto é ativado como a seleção persistente (como para "destacar" o item da lista selecionado anteriormente em uma visualização de navegação persistente); " false" se deve ser usado quando o objeto não está ativado. Introduzido na API de nível 11 .
Acho que o médico é bastante claro, então qual é o problema?
Aqui está outra solução para este problema: https://github.com/jiahaoliuliu/CustomizedListRow/blob/master/src/com/jiahaoliuliu/android/customizedlistview/MainActivity.java
Substituí o método setOnItemClickListener e verifiquei casos diferentes no código. Mas definitivamente a solução do Marvin é muito melhor.
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position,
long id) {
CheckedTextView checkedTextView =
(CheckedTextView)view.findViewById(R.id.checkedTextView);
// Save the actual selected row data
boolean checked = checkedTextView.isChecked();
int choiceMode = listView.getChoiceMode();
switch (choiceMode) {
// Not choosing anything
case (ListView.CHOICE_MODE_NONE):
// Clear all selected data
clearSelection();
//printCheckedElements();
break;
// Single choice
case (ListView.CHOICE_MODE_SINGLE):
// Clear all the selected data
// Revert the actual row data
clearSelection();
toggle(checked, checkedTextView, position);
//printCheckedElements();
break;
// Multiple choice
case (ListView.CHOICE_MODE_MULTIPLE):
case (ListView.CHOICE_MODE_MULTIPLE_MODAL):
// Revert the actual selected row data
toggle(checked, checkedTextView, position);
//printCheckedElements();
break;
}
}
});