Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

View.setEnabled(false) does not work quite right in android

I just found out View.setEnabled(false) does not work quite right in android, in the following ways:

  1. Disable parent view does not automatically disable child views. This is inconvenient.
  2. Though grayed in color, disabled views can still get focus and get keyboard input, make choice, etc. This is not right.
  3. When getting keyboard input, DEL/BACK can only remove one key backward no matter how many you input. This behavior only shows in disabled EditText.
  4. Radio label is grayed but radio button image is not grayed.

It seems like a bug. But how do I get a real DISABLE feature?

EDIT: forget to mention the first.

like image 250
Michael SM Avatar asked Oct 07 '13 12:10

Michael SM


3 Answers

Recursively setting all descendants is needed, otherwise RadioButtons in the layout will not get setEnabled because RadioButtons are grand-children not direct children, there is RadioGroup in between. I record my best solution so far here based on others' answer.

public static void setEnabledAll(View v, boolean enabled) {
    v.setEnabled(enabled);
    v.setFocusable(enabled);

    if(v instanceof ViewGroup) {
        ViewGroup vg = (ViewGroup) v;
        for (int i = 0; i < vg.getChildCount(); i++)
            setEnabledAll(vg.getChildAt(i), enabled);
    }
}

Subclass is not working at this time. If I have:

public MyView class View {
    protected void setEnabled(boolean enabled, boolean setChildren){
        setEnabled(enabled);
        setFocusable(enabled);
        if(setChildren && this isinstanceof ViewGroup){
              for ( int i = 0 ; i < this.getChildCount() ; i++ )
                  //this line will have issue if it is not MyView                      
                  this.getChildAt(i).setEnabled(enabled, true); 
        }
    }
}

unless View itself has this overloaded setEnabled like this:

public class View {
    protected void setEnabled(boolean enabled, boolean setChildren){
        setEnabled(enabled);
        setFocusable(enabled);
        if(setChildren && this isinstanceof ViewGroup){
              for ( int i = 0 ; i < this.getChildCount() ; i++ )         
                  this.getChildAt(i).setEnabled(enabled, true); 
        }
    }
}

This solution will eliminate problems 1, 2, 3. Problem 4 can be solved by setting disabled style selector for RadioGroup - I am not sure why android has no default disabled style selector for RadioGroup. Maybe another point for Android enhancement. Android is very flexible in SDK design also means sometimes extra work needed.

like image 111
Michael SM Avatar answered Nov 13 '22 23:11

Michael SM


From memory, please excuse typos:

class ExtendedLinearLayout extends LinearLayout{

    protected void setEnabled(boolean enabled, boolean setChildren){

        super.setEnabled(enabled);

        if(setChildren){
              for ( int idx = 0 ; idx < this.getChildCount() ; idx++ ) {
                  (View)(this.getChildAt(idx)).setEnabled(enabled);
              }
        }
    }
}
like image 27
Simon Avatar answered Nov 13 '22 22:11

Simon


Just want to update this Michael SM' solution with kotlin. Override for view will looks like:

override fun setEnabled(enabled: Boolean) {
    super.setEnabled(enabled)
    children.forEach { it.isEnabled = enabled }
}

Call now is:

view.isEnabled = false
like image 34
Oleh Pavliuchenko Avatar answered Nov 13 '22 21:11

Oleh Pavliuchenko