Differencebetween the States Selected, Checked and Activated in Android

What is the difference between the states selected, checked and activated in Android?

The difference between Checked and Activated is actually quite interesting. Even the Google documentation is apologetic (emphasis below added):

... 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.)
The activated
state is propagated down to children of the view it is set on.

So here is the difference:

  1. Activated was introduced in Honeycomb so you can't use it before that
  2. Activated is now a property of every View. It has methods setActivated() and isActivated()
  3. Activated propagates to children of the View on which it is set
  4. Checked revolves around a View implementing the Checkable interface. Methods setChecked(), isChecked(), toggle()
  5. ListView (after Honeycomb) calls setChecked() OR setActivated() depending on Android version as below (taken from Android source code):

    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));
    }
    }

    Note the mCheckStates variable. It keeps track of which positions in your list are checked / activated. These are accessible via, for example, getCheckedItemPositions(). Note also that a call to ListView.setItemChecked() invokes the above. In other words, it could equally be called setItemActivated().

  6. Prior to Honeycomb we had to implement workarounds to reflect state_checked in our list items. This is because ListView calls setChecked() ONLY on the topmost View in the layout (and layouts do not implement checkable) ... and it does NOT propagate without help. These workarounds were of the following form: Extend the root layout to implement Checkable. In its constructor, recursively find all the children that implement Checkable. When setChecked() etc... are called, pass the call on to those Views. If those views implement state list drawables (eg a CheckBox) with a different drawable for state_checked then the checked state is reflected in the UI.

  7. To do a nice background to a list item after Honeycomb all you need do is have a state list drawable with a drawable for the state state_activated like this (and use setItemChecked() of course):


    <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"/>

  8. To do a nice background to a list item prior to HoneyComb you would do something like the above for state_checked and you ALSO need to extend your topmost view to implement the Checkable interface. Within that you then need to tell Android whether the state you are implementing is true or false by implementing onCreateDrawableState() and calling refreshDrawableState() whenever the state changes.


    <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"/>

... and the code to implement Checkable combined with state_checked in a RelativeLayout could be:

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);
}
}

Thanks to the following:

http://sriramramani.wordpress.com/2012/11/17/custom-states/

Stackoverflow: How to add a custom button state

Stackoverflow: Custom Checkable View which responds to Selector

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/

android: what is the difference between focused, enabled, pressed, and selected states?

Enabled -> User Interaction possible.

Disabled -> User interaction not possible.

  • if you hover the mouse over a widget, it is focussed
  • If you make a press-down (half click) on that widget, it is pressed
  • If you press-down and press-up while the mouse is at the same position, it is selected

Explanation of state_activated, state_selected, state_pressed, state_focused for ListView

  • state_selected is used when an item is selected using a
    keyboard/dpad/trackball/etc.
  • state_activated is used when View.setActivated(true) is called. This
    is used for "persistent selection" (see Settings on tablet for
    instance)
  • state_pressed is used when the user is pressing the item either
    through touch or a keyboard or a mouse
  • state_focused is used if the item is marked focusable and it receives
    focus either through the user of a keyboard/dpad/trackball/etc. or if
    the item is focusable in touch mode

What does View.isActivated() do?

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.) The activated
state is propagated down to children of the view it is set on.

Source: http://developer.android.com/reference/android/view/View.html#setActivated(boolean)

Android difference between “setSelected()” and setChecked()

SetSelected() is View Property. We can extend this for any View in Android.

For setSelected()

public void setSelected (boolean selected)

Changes the selection state of this view. A view can be selected or not. the selected view is the view that is highlighted

While setChecked() is RadioGroup Property. Which changes checked and unchecked state of RadioButton

Highlight Multiple Selected/Checked/Activated in ListView

So apparently I was led off the wrong track because I was supposed to be looking for highlighting "checked" items and not "selected" items. Thus, many answers told me to use the selector with my ListView layout using android:listSelector="@drawable/myselector, but what I really needed was to use the selector with my row layout. The solution is actually rather simple, I'll post it below:

drawable/rowbackgroundselector.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true"
android:drawable="@android:color/holo_green_light"/>
</selector>
  • note how you use "state_activated" to detect if an item is "checked"...

drawable/mylistrow.xml

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/rowbackgroundselector"
android:padding="10sp"
/>
  • using the selector for the row background

MainActivity.onListItemClick()

public void onListItemClick(ListView l, View v, int position, long id) {
getListView().setItemChecked(pos, true);
}

Lastly, make sure your adapter is using your custom row layout

mAdapter = new ArrayAdapter<FileTag>(this.getActivity(),
R.layout.mylistrow, mList);

Android View setActive, setSelected and RecyclerView States

problem at below lines

 // Set every view holder that is locked to the locked symbol
if (downloadingAlarm.getAlarmFreeorPaid().equals("PAID") && !downloadingAlarm.getAlarmPurchased()){
holder.itemView.setActivated(true);
}

// Update the background with checked or unchecked (keeping track of the selected position)
if (selected_position != 101){
if(selected_position == position){
holder.itemView.setSelected(true);
}else{
holder.itemView.setSelected(false);
}
}

You should use else for your if condition. Because views will reuse so if you not have else for you if,it's will keep previous state of views.

So use else for your if.

 // Set every view holder that is locked to the locked symbol
if (downloadingAlarm.getAlarmFreeorPaid().equals("PAID") && !downloadingAlarm.getAlarmPurchased()){
holder.itemView.setActivated(true);
}else{
holder.itemView.setActivated(false);
}

// Update the background with checked or unchecked (keeping track of the selected position)
if (selected_position != 101){
if(selected_position == position){
holder.itemView.setSelected(true);
}else{
holder.itemView.setSelected(false);
}
}
else{
//reset your data on views
}

Thanks

How can I distinguish whether Switch,Checkbox Value is changed by user or programmatically (including by retention)?

Answer 2:

A very simple answer:

Use on OnClickListener instead of OnCheckedChangeListener

    someCheckBox.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
// you might keep a reference to the CheckBox to avoid this class cast
boolean checked = ((CheckBox)v).isChecked();
setSomeBoolean(checked);
}

});

Now you only pick up click events and don't have to worry about programmatic changes.


Answer 1:

I have created a wrapper class (see Decorator Pattern) which handles this problem in an encapsulated way:

public class BetterCheckBox extends CheckBox {
private CompoundButton.OnCheckedChangeListener myListener = null;
private CheckBox myCheckBox;

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

public BetterCheckBox(Context context, CheckBox checkBox) {
this(context);
this.myCheckBox = checkBox;
}

// assorted constructors here...

@Override
public void setOnCheckedChangeListener(
CompoundButton.OnCheckedChangeListener listener){
if(listener != null) {
this.myListener = listener;
}
myCheckBox.setOnCheckedChangeListener(listener);
}

public void silentlySetChecked(boolean checked){
toggleListener(false);
myCheckBox.setChecked(checked);
toggleListener(true);
}

private void toggleListener(boolean on){
if(on) {
this.setOnCheckedChangeListener(myListener);
}
else {
this.setOnCheckedChangeListener(null);
}
}
}

CheckBox can still be declared the same in XML, but use this when initializing your GUI in code:

BetterCheckBox myCheckBox;

// later...
myCheckBox = new BetterCheckBox(context,
(CheckBox) view.findViewById(R.id.my_check_box));

If you want to set checked from code without triggering the listener, call myCheckBox.silentlySetChecked(someBoolean) instead of setChecked.



Related Topics



Leave a reply



Submit