195

I'm trying to deactivate the soft keyboard when using a NumberPicker to enter numerical values (for aesthetic reasons). This is my layout-xml-code:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="30dp"
        android:layout_marginTop="30dp" >

        <NumberPicker
            android:id="@+id/repetitionPicker"
            android:layout_width="40dp"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:text="@string/repetitions_short_divider"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <NumberPicker
            android:id="@+id/weightPicker"
            android:layout_width="40dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="40dp" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:text="@string/pounds"
            android:textAppearance="?android:attr/textAppearanceMedium" />
    </LinearLayout>


    <Button
        android:id="@+id/saveButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="@string/save" />

</LinearLayout>

And finally this is the code where I try to block the keyboard in the onCreate()-method:

// hide keyboard
View.OnClickListener disableKeyBoardListener = new View.OnClickListener() {
    public void onClick(View v) {
        ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))
                .hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
};

((EditText) weightPicker.getChildAt(1)).setInputType(InputType.TYPE_NULL);
((EditText) repetitionPicker.getChildAt(1)).setInputType(InputType.TYPE_NULL);

((EditText) weightPicker.getChildAt(1)).setOnClickListener(disableKeyBoardListener);
//((EditText) repetitionPicker.getChildAt(1)).setOnClickListener(disableKeyBoardListener);
//weightPicker.setOnClickListener(disableKeyBoardListener);
//repetitionPicker.setOnClickListener(disableKeyBoardListener);     

getWindow().setSoftInputMode(
        WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); 

Sadly, the soft keyboard still shows up when clicking on a NumberPicker. Any ideas?

damaxxed
  • 2,464
  • 2
  • 16
  • 17

11 Answers11

528

Just found this and it works like a charm:

myNumberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);

You can also set this in XML:

android:descendantFocusability="blocksDescendants" 
ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
Andrew Webber
  • 5,296
  • 1
  • 13
  • 2
  • 1
    Unless I'm missing something, this removes the ability to type in a value for the NumberPicker. It's not necessarily a bad thing, depending on how you are using the picker, but it does appear to be a limitation of the solution. – frenziedherring Aug 26 '13 at 17:01
  • 79
    You can also set this in XML: android:descendantFocusability="blocksDescendants" – Ben Clayton Aug 29 '13 at 08:21
  • Only the programmatic version worked for me with androidx 1.2.0-rc2, and I combined it with `isClickable=true` and `isFocusable=true` (Kotlin) – hgoebl Jul 25 '20 at 05:33
58

Xml version of Andrew Webber's answer

android:descendantFocusability="blocksDescendants"

Example

<NumberPicker
        android:id="@+id/your_numberpicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants"/>
G_V
  • 2,396
  • 29
  • 44
7

After reading through the com/android/internal/widget/NumberPicker.java source code i got to the following solution:

// Hide soft keyboard on NumberPickers by overwriting the OnFocusChangeListener
OnFocusChangeListener fcl = new OnFocusChangeListener() {
    public void onFocusChange(View v, boolean hasFocus) {
        // Do nothing to suppress keyboard
    }
};

((EditText) numberPicker.getChildAt(1)).setOnFocusChangeListener(fcl);

// Suppress soft keyboard from the beginning
((EditText) numberPicker.getChildAt(1)).setInputType(InputType.TYPE_NULL);
damaxxed
  • 2,464
  • 2
  • 16
  • 17
  • Yes, I had to directly edit the child views of the NumberPicker. The Android API is very sparse sometimes. – damaxxed Jan 21 '12 at 04:37
6

Just enhanced the @MaxVogler 's ans (so if wannt vote this vote @MaxVogler too) and make it a robust hack. Also we dont need to call setOnFocusChangeListener and setInputType. Only setFocusable to false will do.

Below is a helper api to enable/disable the feature

public static void enableNumberPickerManualEditing(NumberPicker numPicker,
        boolean enable) {
    int childCount = numPicker.getChildCount();

    for (int i = 0; i < childCount; i++) {
        View childView = numPicker.getChildAt(i);

        if (childView instanceof EditText) {
            EditText et = (EditText) childView;
            et.setFocusable(enable);
            return;
        }
    }
}
havexz
  • 9,550
  • 2
  • 33
  • 29
4

Here's another way to do it which enables the user still to edit a number if they want to - it just suppresses the soft keyboard initially. Use NumberPicker.setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS) to suppress the soft keyboard when the interface first shows as per answers above. Then get your dialog or activity to implement View.OnTouchListener, call setOnTouchListener(this) on your NumberPicker, and in your implementation of onTouch(View v,MotionEvent e) reset the numberpicker descendant focusability to its normal value, then return false.

Returning false means that the touch is still processed by the NumberPicker, which means that if the user taps the edit box the soft keyboard comes up. This happens to be exactly what I wanted faced with the same problem - having the soft keyboard come up with the dialog when it first shows is displeasing as it shifts the dialog up after it appears.

public class GetBufferDialog extends DialogFragment implements View.OnTouchListener {

after creating the Dialog in the onCreateDialog() method and finding the NumberPicker:

m_oldFocus = m_numberpicker.getDescendantFocusability();
m_numberpicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); 
m_numberpicker.setOnTouchListener(this);

and here's the OnTouch method:

public boolean onTouch(View v, MotionEvent event) {
    m_numberpicker.setDescendantFocusability(m_oldFocus);
    return false;
}
IntelliJ Amiya
  • 74,896
  • 15
  • 165
  • 198
4

Working code Programatically :

mp.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);

XML:

android:descendantFocusability="blocksDescendants" 
Vinayak
  • 6,056
  • 1
  • 32
  • 30
3

I don't know why it works, but setting OnClickListener which does nothing prevented keyboard from showing (Lollipop)

numberPicker.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
  }
});
  • If I add `android:descendantFocusability="blocksDescendants"`, after clicking to current value it's hiding. Only adding click listener helped me. Thanks! You save my mind. – Bogdan Stolyarov Dec 03 '20 at 13:09
2

The simplest I found to work was :

numberPicker               = (NumberPicker) myDialogView.findViewById(R.id.myViewId);
EditText numberPickerChild = (EditText) numberPicker.getChildAt(0);
numberPickerChild.setFocusable(false);
numberPickerChild.setInputType(InputType.TYPE_NULL);
bapjg
  • 21
  • 1
2

If you only want to hide the software keyboard when loading the view with your number picker, but still want the users to be able to edit after the view loads, then you shouldn't block descendant focusability. Instead, just prevent the number picker from being the first focused item in your view.

See this answer for details.

Based on the above answer:

    <!-- Dummy item to prevent Number Picker from receiving focus -->
    <LinearLayout        
        android:focusable="true" 
        android:focusableInTouchMode="true"
        android:layout_width="0px" 
        android:layout_height="0px"/>

    <!-- :nextFocusUp and :nextFocusLeft have been set to the id of this component 
         to prevent the dummy from receiving focus again -->
    <NumberPicker 
        android:id="@+id/number_picker"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:nextFocusUp="@id/number_picker" 
        android:nextFocusLeft="@id/number_picker"/>
eckc
  • 488
  • 6
  • 13
0
/**
 * set focus to top level window
 * disposes descendant focus
 * disposes softInput
 * @param context - activity context
 * @param enable - state of focus
 * */
public static void topLevelFocus(Context context, boolean enable){
    if(Activity.class.isAssignableFrom(context.getClass())){
        ViewGroup tlView = (ViewGroup) ((Activity) context).getWindow().getDecorView();
        if(tlView!=null){
            tlView.setFocusable(enable);
            tlView.setFocusableInTouchMode(enable);
            tlView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
            tlView.requestFocus();
        }
    }
}

* calling this:

  • will not block descendant focusability (numberpicker will be editable)

  • will hide soft input on create

  • before (processing input) getValue() will allow to get proper walue


ceph3us
  • 7,326
  • 3
  • 36
  • 43
0

This extension is nice to not forget how to do it and have readable code. It is little bit hiding implementation details, but in this case I believe it's acceptable:

fun NumberPicker.disableTextEditing(disable: Boolean) {
    descendantFocusability = if (disable) FOCUS_BLOCK_DESCENDANTS else FOCUS_BEFORE_DESCENDANTS
}
Renetik
  • 5,887
  • 1
  • 47
  • 66