NumberPicker use and customization of its appearance

Probably many of you have used widgets such as DatePicker and TimePicker. But the functionality of the widget is limited ability to choose the date and time, but I wanted more- to use this feature to select any number in a specified range (as inkontroleNumericUpDown in C #). Such a possibility exists. DatePicker widget andsystem-based TimePicker widget NumberPicker, you can not use the box. To use it you need to write a little code.

First, add NumberPicker in our main layout, xml-code is as follows:



<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent">
    <com.android.internal.widget.NumberPicker
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:id="@+id/numTestNumberPicker" android:layout_centerInParent="true">
    </com.android.internal.widget.NumberPicker>
</RelativeLayout>

We have 3 NumberPicker method that we need setRange, getCurrent and setCurrent. I guess by the names of the methods, it is clear that they do. The difficulty is that these methods are hidden for the developer and they can only call using reflectionFor ease of use, I wrote a helper-class that allows you to work with these methods. Class code is shown below:


package maximyudin.NumberPickerDemo;


import java.lang.reflect.Method;


public class NumberPicker {
    private Object picker;
    private Class<?> classPicker;


    public NumberPicker(Object o) {
        picker = o;
        classPicker = picker.getClass();
    }


    public void setRange(int start, int end) {
        try {
            Method m = classPicker.getMethod("setRange"int.classint.class);
            m.invoke(picker, start, end);
        } catch (Exception e) {
        }
    }


    public Integer getCurrent() {
        Integer current = -1;
        try {
            Method m = classPicker.getMethod("getCurrent");
            current = (Integer) m.invoke(picker);
        } catch (Exception e) {
        }
        return current;
    }


    public void setCurrent(int current) {
        try {
            Method m = classPicker.getMethod("setCurrent"int.class);
            m.invoke(picker, current);
        } catch (Exception e) {
        }
    }
}
In konstrukture class passed a real object NumberPicker (which LinearLayout), obtained by findViewById of our main layout. Consider how to use freshly NumberPicker in practice.

package maximyudin.NumberPickerDemo;

import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;

public class NumberPickerDemo extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        LinearLayout numTestNumberPickerView = (LinearLayout) findViewById(R.id.numTestNumberPicker);
        NumberPicker numTestNumberPickerObject = new NumberPicker(
                numTestNumberPickerView);

        numTestNumberPickerObject.setRange(1100);
        numTestNumberPickerObject.setCurrent(50);
        int currentPos = numTestNumberPickerObject.getCurrent();
    }
}
Basically all quite simple when using the helper-class. The screen looks as follows:

image
We now proceed to the second part of the article - full change in the appearance of the widget. For this purpose, a set of prepared me pictures (from my program MyTasks) different states of the buttons ('+' and '-') and a text field widget, it is from them is NumberPicker. Get them mozhnootsyuda.The images presented in a format Nine-Patch (9-Patch), a type of image can be stretched, depending, for example, of their content, they are often used to set the background of various widgets, including in my case. More information on the 9-Patch you can read here. Images need to put it in the drawable, or a folder drawable-mdpi (-ldpi,-hdpi), as in my case.
In order to fit these images have earned us a way (that is responsive to the different states of widgets) necessary to form three xml-file-selector in the format (a file on each widget - two buttons and a text box). The selector is a set of elements with attributes, which represent different states of the widget (selected, pressed, inactive, etc.). These files can also be placed under the drawable, or drawable-mdpi (-ldpi,-hdpi). Below are the three files.
Button for '+' (timepicker_up_btn.xml)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="schemas.android.com/apk/res/android">
    <item android:state_pressed="false" android:state_enabled="true"
        android:state_focused="false" android:drawable="@drawable/btn_up_picker_notselected" />
    <item android:state_pressed="true" android:state_enabled="true"
        android:drawable="@drawable/btn_up_picker_pressed" />
    <item android:state_pressed="false" android:state_enabled="true"
        android:state_focused="true" android:drawable="@drawable/btn_up_picker_selected" />
    <item android:state_pressed="false" android:state_enabled="false"
        android:state_focused="false" android:drawable="@drawable/btn_up_picker_disabled" />
    <item android:state_pressed="false" android:state_enabled="false"
        android:state_focused="true" android:drawable="@drawable/btn_up_picker_disabled_focus" />
</selector>
For a text box (ed_picker_background.xml)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="schemas.android.com/apk/res/android">
    <item android:state_window_focused="false" android:state_enabled="true"
        android:drawable="@drawable/edit_picker_notselected" />
    <item android:state_window_focused="false" android:state_enabled="false"
        android:drawable="@drawable/edit_picker_notselected" />
    <item android:state_pressed="true" android:drawable="@drawable/edit_picker_pressed" />
    <item android:state_focused="true" android:state_enabled="true"
        android:drawable="@drawable/edit_picker_selected" />
    <item android:state_enabled="true" android:drawable="@drawable/edit_picker_notselected" />
    <item android:state_focused="true" android:drawable="@drawable/edit_picker_notselected" />
    <item android:drawable="@drawable/edit_picker_notselected" />
</selector>
For button '-' (timepicker_down_btn.xml)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="schemas.android.com/apk/res/android">
    <item android:state_pressed="false" android:state_enabled="true"
        android:state_focused="false" android:drawable="@drawable/btn_down_picker_notselected" />
    <item android:state_pressed="true" android:state_enabled="true"
        android:drawable="@drawable/btn_down_picker_pressed" />
    <item android:state_pressed="false" android:state_enabled="true"
        android:state_focused="true" android:drawable="@drawable/btn_down_picker_selected" />
    <item android:state_pressed="false" android:state_enabled="false"
        android:state_focused="false" android:drawable="@drawable/btn_down_picker_disabled" />
    <item android:state_pressed="false" android:state_enabled="false"
        android:state_focused="true" android:drawable="@drawable/btn_down_picker_disabled_focus" />
</selector>
Now we need to slightly modify the constructor helper-class that was created forNumberPicker at the outset. This will allow us to create an object NumberPicker change the appearance of its components. The code of the modified class is shown below.

package maximyudin.NumberPickerDemo;

import java.lang.reflect.Method;

import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;

public class NumberPicker {
    private Object picker;
    private Class<?> classPicker;

    public NumberPicker(LinearLayout numberPickerView) {
        picker = numberPickerView;
        classPicker = picker.getClass();

        // Кнопка '+', тип - NumberPickerButton
        View upButton = numberPickerView.getChildAt(0);
        upButton.setBackgroundResource(R.drawable.timepicker_up_btn);

        // Текстовое поле, тип - EditText
        EditText edDate = (EditText) numberPickerView.getChildAt(1);
        edDate.setTextSize(17);
        edDate.setBackgroundResource(R.drawable.ed_picker_background);

        // Кнопка '-', тип - NumberPickerButton
        View downButton = numberPickerView.getChildAt(2);
        downButton.setBackgroundResource(R.drawable.timepicker_down_btn);
    }

    public void setRange(int start, int end) {
        try {
            Method m = classPicker.getMethod("setRange"int.classint.class);
            m.invoke(picker, start, end);
        } catch (Exception e) {
        }
    }

    public Integer getCurrent() {
        Integer current = -1;
        try {
            Method m = classPicker.getMethod("getCurrent");
            current = (Integer) m.invoke(picker);
        } catch (Exception e) {
        }
        return current;
    }

    public void setCurrent(int current) {
        try {
            Method m = classPicker.getMethod("setCurrent"int.class);
            m.invoke(picker, current);
        } catch (Exception e) {
        }
    }
}
The result is shown in the figure below.In this article of mine is complete, I hope I helped you learn something new. Waiting forcomments and amendments, if there is someone to that offer.