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

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

Posted by: admin June 16, 2020 Leave a comment

Questions:

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.

How to&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.

Answer:

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

Answer:

I dono’t have answer to your all questions but i will try for first and second

  • 1 Its absolutely fine to not disabling child on disabling of Parent. Consider a case where you want to click button of a layout but don’t want to click outer area. Best example in Listrow, you have button which you want to click but does not want to click row.

    Disabling all child at once

    LinearLayout layout = (LinearLayout) findViewById(R.id.my_layout);
    for (int i = 0; i < layout.getChildCount(); i++) {
    View child = layout.getChildAt(i);
    child.setEnabled(false);
     }
    
  • 2 Its happend only for EditText but you can stop it also. And view.setFocusable(false); is the correct to stop view gaining focus

Answer:

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