Change the step size of a NumberPicker - android

Is it possible to do that in a more convenient way than handling it in the OnScrollListener event? Pity it doesn't have a step size attribute...

The NumberPicker in Android has a method called setDisplayedValues.
You can use this one to show custom values (it takes an array of Strings) and then map them when you need the value.
So if you need steps of 5 in an minute picker, for example, you can create an array like this:
String[] minuteValues = new String[12];
for (int i = 0; i < minuteValues.length; i++) {
String number = Integer.toString(i*5);
minuteValues[i] = number.length() < 2 ? "0" + number : number;
}
minutePicker.setDisplayedValues(minuteValues);
And then when you get the value in the OnValueChangeListener, you just need to cast it back to an integer:
Integer.parseInt(minuteValues[newVal]);

To set a step count of '5' for example, use the NumberPicker.Formatter:
NumberPicker.Formatter formatter = new NumberPicker.Formatter() {
#Override
public String format(int value) {
int temp = value * 5;
return "" + temp;
}
};
numberPicker.setFormatter(formatter);

Why not just add an OnValueChangeListener Something like:
numberPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
picker.setValue((newVal < oldVal)?oldVal-5:oldVal+5);
}
});

The NumberPicker in Android has a method called setDisplayedValues. You can use this one to show custom values (it takes an array of Strings) and then map them when you need the value.
For example, you can create a function like this:
public String[] getArrayWithSteps (int iMinValue, int iMaxValue, int iStep)
{
int iStepsArray = (iMaxValue-iMinValue) / iStep+1; //get the lenght array that will return
String[] arrayValues= new String[iStepsArray]; //Create array with length of iStepsArray
for(int i = 0; i < iStepsArray; i++)
{
arrayValues[i] = String.valueOf(iMinValue + (i * iStep));
}
return arrayValues;
}
So, you should call the method> NumberPicker.setDisplayedValues, for example:
int min = 5;
int max = 180;
int step = 10;
String[] myValues = getArrayWithSteps(min, max, step); //get the values with steps... Normally
//Setting the NumberPick (myNumberPick)
myNumberPick.setMinValue(0);
myNumberPick.setMaxValue((max-step) / min + 1); //Like iStepsArray in the function
//Because the Min and Max Value should be the range that will show.
//For example, Min = 0 and Max = 2, so the NumberPick will display the first three strings in the array String (myValues);
myNumberPick.setDisplayedValues(myValues);//put on NumberPicker
For get the Value in the NumberPick:
String sValue = String.valueOf(10+(myNumberPick.getValue()*5)); //->> (iMinValue + (myNumberPick.getValue()*iStep))

When using methods described above, one needs to be aware that the picker allows user not only to select a value by scrolling, but also by entering it with keyboard.
By default, the input type of the input field is set to TYPE_CLASS_NUMBER, and therefore user is presented with numerical keyboard. It seems that when you use setDisplayedValues the picker changes the type to TYPE_CLASS_TEXT, however, when you use setFormatter the input type is not changed.
Therefore using formatter in this case may lead to unexpected behavior. Let's say you want the user to be able to pick only the values "0" or "5". You may have code like this:
NumberPicker numberPicker = (NumberPicker) findViewById(R.id.my_number_picker);
numberPicker.setMinValue(0);
numberPicker.setMaxValue(1);
numberPicker.setFormatter(v -> v == 0 ? "0" : "5");
However, in this scenario the user is presented with the numerical keyboard, but is able only to enter only "0" or "1".
If you use instead:
numberPicker.setDisplayedValues(new String[] { "0", "5" });
the user will see the text keyboard, but will be able to enter "0" or "5" as expected.
If you are bothered with the text keyboard you can use reflection to access the private field and set the input type back to number (which is of course not recommended unless really necessary). The field is called "mInputText", or "mText" if you target oldies goldies like Gingerbread.
try {
Field inputField = NumberPicker.class.getDeclaredField("mInputText");
inputField.setAccessible(true);
EditText inputText = (EditText) inputField.get(numberPicker);
inputText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
} catch (ClassCastException e) {
// Just ignore this exception and do nothing.
} catch (IllegalAccessException e) {
// Just ignore this exception and do nothing.
} catch (NoSuchFieldException e) {
// Just ignore this exception and do nothing.
}

This is better approach for ajpolt solution
with any predefined step size, it support for custom value set via keyboard.
final NumberPicker np = (NumberPicker) dialogView.findViewById(R.id.numberPicker1);
np.setMaxValue(1000); // max value 1000
np.setMinValue(0); // min value 0
np.setValue(defValue);
np.setWrapSelectorWheel(false);
final int m_oldFocus = np.getDescendantFocusability();
np.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
np.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
np.setDescendantFocusability(m_oldFocus);
return false;
}
});
np.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
#Override
public void onValueChange(NumberPicker numberPicker, int oldVal, int newVal) {
int stepSize = 10;
if(newVal%stepSize !=0){
if(newVal < oldVal){
numberPicker.setValue(((int)(newVal/stepSize)) *stepSize);
}else{
numberPicker.setValue((((int)(newVal/stepSize)) *stepSize ) +stepSize );
}
}else{
numberPicker.setValue(newVal);
}
}
});
*I know this is 5 years old Question, but might be useful for somebody

Related

android how have the value of edittext auto format itself and calculate-able at the same time

I have 2 edittexts and 1 textview. 1 edittext for input the price another one the percentage and the textview will display the result of them both (the price * percentage/100) and i want to make the 1st edittext input(for the price) will change the format of the input and display it on the same edittext with decimal format. For example :
edittext1
100
the user type 100 it will just display 100 ,but when the user type one or more number(S) it will add "," every 3 number
edittext1
1,000
edittext1
10,000
edittext1
100,000
edittext1
1,000,000
and so on
i have the functions, one will autocalculate the value for textview1 , another will convert automatically the input of edittext. However they cant work together because the format for calculation function, it uses int/long/double and for the converter it uses decimalformat . If i use them both the app will crash with javanumberformatexception unable to parse int "1,000"(if we put 1000 into edittext)
my function for autocalculate
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simulasikredit);
ethint1 = (EditText) findViewById(R.id.ethint);
etpersen2 = (EditText) findViewById(R.id.etpersen);
textvDP1 = (TextView) findViewById(R.id.textvDP);
etpersen2.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String text1 = ethint1.getText().toString();
String text2 = etpersen2.getText().toString();
long input1 = 0;
long input2 = 0;
if(text1.length()>0)
input1 = Long.valueOf(text1);
if(text2.length()>0)
input2 = Long.valueOf(text2);
if (text1.length() != 0) {
long output = (input1 * input2) / 100;
textvDP1.setText(""+output);
}
else if(text2.length() == 0){
textvDP1.setText("");
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
}); }
et stands for edittext, tv stands for textview
and makedecimal function
public void makedecimal(View v)
{
ethint1.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
DigitsKeyListener dkl = new DigitsKeyListener(true,true);
ethint1.setKeyListener(dkl);
ethint1.addTextChangedListener(new TextWatcher(){
private String current = "";
#Override
public void afterTextChanged(Editable s) {
String userInput=s.toString();
if(!userInput.toString().equals(current)){
ethint1.removeTextChangedListener(this);
String cleanString = userInput.replaceAll("[,]", "");
if(cleanString.length()>0){
double parsed = Double.parseDouble(cleanString);
String formated = DecimalFormat.getNumberInstance().format(parsed);
current = formated;
ethint1.setText(formated);
ethint1.setSelection(formated.length());
}else{
ethint1.setText(cleanString);
ethint1.setSelection(cleanString.length());
}
ethint1.addTextChangedListener(this);
}
this makedecimal is android:onClick from ethint , ethint is the id(these two come from 1 edittext)
I need to fulfil a similar requirements before where we need to format the number in thousands and also support fractions.
My approach is to register a TextWatcher format text every time input changed, and provide a public method to get numeric value by stripping separators, which is quite tricky. My solution also caters for locale-specific separator by utilizing DecimalFormatSymbols class.
private final char GROUPING_SEPARATOR = DecimalFormatSymbols.getInstance().getGroupingSeparator();
private final char DECIMAL_SEPARATOR = DecimalFormatSymbols.getInstance().getDecimalSeparator();
...
/**
* Return numeric value repesented by the text field
* #return numeric value or {#link Double.NaN} if not a number
*/
public double getNumericValue() {
String original = getText().toString().replaceAll(mNumberFilterRegex, "");
if (hasCustomDecimalSeparator) {
// swap custom decimal separator with locale one to allow parsing
original = StringUtils.replace(original,
String.valueOf(mDecimalSeparator), String.valueOf(DECIMAL_SEPARATOR));
}
try {
return NumberFormat.getInstance().parse(original).doubleValue();
} catch (ParseException e) {
return Double.NaN;
}
}
/**
* Add grouping separators to string
* #param original original string, may already contains incorrect grouping separators
* #return string with correct grouping separators
*/
private String format(final String original) {
final String[] parts = original.split("\\" + mDecimalSeparator, -1);
String number = parts[0] // since we split with limit -1 there will always be at least 1 part
.replaceAll(mNumberFilterRegex, "")
.replaceFirst(LEADING_ZERO_FILTER_REGEX, "");
// only add grouping separators for non custom decimal separator
if (!hasCustomDecimalSeparator) {
// add grouping separators, need to reverse back and forth since Java regex does not support
// right to left matching
number = StringUtils.reverse(
StringUtils.reverse(number).replaceAll("(.{3})", "$1" + GROUPING_SEPARATOR));
// remove leading grouping separator if any
number = StringUtils.removeStart(number, String.valueOf(GROUPING_SEPARATOR));
}
// add fraction part if any
if (parts.length > 1) {
number += mDecimalSeparator + parts[1];
}
return number;
}
It's quite tedious to elaborate here so I'll only give a link for your own reading:
https://gist.github.com/hidroh/77ca470bbb8b5b556901

Check if number exists, if it does - get another

I am using a database to show random message at the push of a button.
Every time the button is pushed, a random number is generated and displays a message that corresponds to that number.
Of course, the same message can appear twice as the same number can be generated twice.
So I am creating a string, and I am concatenating each number when the button is pushed.
If the new random number is in the String, then I want to get another number. If that number is in that String, I want to get another number etc etc (Regression?).
I also want to have a global count that I can change, so if the String reaches a size of 9 numbers, it will be reset to "".
String randomList; //global
final int MAX_STRING_LENGTH = 9;
Integer randomNumber = getRandomMessage(messages.size());
if(randomList.length() > 0)
{
if(!randoms.contains(randomNumber.toString()))
{
messageText.setText(messages.get(randomNumber));
}
}
Create a boolean Array of 9 elements
boolean[] check = new boolean[9];
Everytime you use a number, set check[number] to true
void useNumber(int number){
check[number] = true;
}
To check if you already used this number
boolean checkNumber(int number){
return check[number];
}
To reset check
void resetCheck(){
for(int i = 0; i < check.length; i++) check[i] = false;
}
Edit:
Get a string for a given number, resetCheck if necessary;
String getString(int number){
if(usedString == check.length){
resetCheck();
usedString = 0;
}
if(checkNumber(number)){
return getString(getRandomNumber());
}else{
usedString++;
return strings[number];
}
}
I think you can better use a boolean array. You can store the boolean array with the SharedPreferences class. A boolean array is more flexible and you can retrieve the values in constant time. You can also easily make it larger when you have more random messages.
Do a simple trick Hope this works for you
buttonRandom.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Collections.shuffle(messages);
messageText.setText(messages.get(0));
}
});

Input filter not filter one by one in android

I use InputFilter to check my String from editText.
final InputFilter filter = new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start,
int end, Spanned dest, int dstart, int dend) {
int num = 0;
try {
num = Integer.parseInt(source.toString());
if (!(num > 0 && num < 30)) {
return "";
}
} catch (Exception e) {
}
return null;
}
};
etStatDaysCount = (EditText) inflate2.findViewById(R.id.et_settings_days_to_statistics);
etStatDaysCount.setFilters(new InputFilter[]{filter});
But I have a problem. I want to check if user put number <0 or >30 I want to replace this text. This filter check number one by one. So if I put number 56, he check number 5 and after that 6 so this filter let user put number 56 in edit text. I want to check all string which I put in edittext. So if I put 56 he should check number 5 and after that check number 56. How can I do that?
It seems like you're answering your own question. If the problem is that the filter checks the numbers one by one then don't use it! Just grab the value from the EditText whenever you're ready to test it and make sure it meets your criteria.
etStatDaysCount = (EditText) inflate2.findViewById(R.id.et_settings_days_to_statistics);
//when you're ready to look at the value...
String input = etStatDaysCount.getText().toString()
if(input.trim().equals("") || input.matches("\\D") || Integer.valueOf(input) < 0 || Integer.valueOf(input) > 30)
//this is a value that you don't want
Use TextChangeListener. It is fired up whenever an input is made to editText.
etStatDaysCount = (EditText) inflate2.findViewById(R.id.et_settings_days_to_statistics);
etStatDaysCount.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3 ) {
// you can check every number/alphabet of input here
}
If you don't want to check each individual character in your input, you can always do like:
String yourInput = etStatDaysCount.getText().toString();
if(Integer.valueOf(yourInput) <0 && Integer.valueOf(yourInput) >30 )
// undesired value
Hope this helps

list.getchildAt(i) return null pointer ,only shows visible views not shows more

I have a list view, in that list view, I have 30 items with edit text in which I manually put the value and after that I calculate the total of value set on edit text for 30 items. But problems is it calculate the total of only visible list items which are almost 10 and I need all 30 values of edit text.after 10 items view become null.
How to resolve this problem.
totalpoints.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
/*for (int i = 0; i < summaryList.size(); i++)
{
summaryList.get();
}*/
for (int i = 0; i < listView_subCategory.getCount(); i++) {
view = listView_subCategory.getChildAt(i);
if (view == null) {
} else {
try {
EditText text = (EditText) view
.findViewById(R.id.et_date);
TextView tv_productname=(TextView) view.findViewById(R.id.textView_userName);
String points = text.getText().toString().trim();
String productname=tv_productname.getText().toString().trim();
int point = Integer.valueOf(points);
count_summary = count_summary + point;
String truetotal = Integer.toString(count_summary);
et_total.setText(truetotal);
} catch (Exception e) {
Toast toast1 = Toast.makeText(getActivity(),
"Fill Value First", Toast.LENGTH_SHORT);
toast1.setGravity(Gravity.CENTER, 0, 0);
toast1.show();
}
}
}
count = 0;
}
});
I guess you should think fo a better approach than iterating over the EditTexts with getChildAt() to collect all the value.
I take it that the user can change the values in the EditTexts, you can have an Array of size 30 of Values and everytime the user enters / changes a value you change the according value in the Array. Use a listener that changes the values in your Array like this.

Indexing Android

My problem is I have around 1000+ records in an Android App
string field1;
string field2;
string field3;
string field4;
//...
I want to search in this set of records and get the best results on two fields (field1 and field2).
Currently I read each record and compare() (string compare) with the text i want to search so that takes a long time.
What is the best method to perform search?
Store each records in SQLite DB and do "select query where like"
Hash-Mapped
? any other suggestions?
Or may be create an Index of the records and do search.
If you want to search for not exact matches, I would try to make an ArrayList of MyAppRecord where
public class MyAppRecord {
private String record;
private int deviance;
}
and get for each record the deviance of the String you want to find with:
public static int getLevenshteinDistance (String s, String t) {
if (s == null || t == null) {
throw new IllegalArgumentException("Strings must not be null");
}
int n = s.length(); // length of s
int m = t.length(); // length of t
if (n == 0) {
return m;
} else if (m == 0) {
return n;
}
int p[] = new int[n+1]; //'previous' cost array, horizontally
int d[] = new int[n+1]; // cost array, horizontally
int _d[]; //placeholder to assist in swapping p and d
// indexes into strings s and t
int i; // iterates through s
int j; // iterates through t
char t_j; // jth character of t
int cost; // cost
for (i = 0; i<=n; i++) {
p[i] = i;
}
for (j = 1; j<=m; j++) {
t_j = t.charAt(j-1);
d[0] = j;
for (i=1; i<=n; i++) {
cost = s.charAt(i-1)==t_j ? 0 : 1;
// minimum of cell to the left+1, to the top+1, diagonally left and up +cost
d[i] = Math.min(Math.min(d[i-1]+1, p[i]+1), p[i-1]+cost);
}
// copy current distance counts to 'previous row' distance counts
_d = p;
p = d;
d = _d;
}
// our last action in the above loop was to switch d and p, so p now
// actually has the most recent cost counts
return p[n];
}
}
save it to your MyAppRecord-object and finally sort your ArrayList by the deviance of its MyAppRecord-objects.
Note that this could take some time, depending on your set of records. And NOTE that there is no way of telling wether dogA or dogB is on a certain position in your list by searching for dog.
Read up on the Levensthein distance to get a feeling on how it works. You may get the idea of sorting out strings that are possibly to long/short to get a distance that is okay for a threshold you may have.
It is also possible to copy "good enough" results to a different ArrayList.

Categories

Resources