Android Seekbar float values from 2.0 to 8 - android

Hi i am new for android and in my app i have one seeckBar
for measuring persons height my seeckBar min range is--->2 and max range is---->8
Here i want to show my seeckBar values like 2.0,2.1,2.5.....2.12,
After 2.12 i want to show seeckBar range is 3ft's in that way process is need going up to 8ft's
How can i do this can some one help me please
code:-
try {
CrystalSeekbar height_seeckBar = (CrystalSeekbar) view.findViewById(R.id.height_seeckBar);
height_seeckBar.setOnSeekbarChangeListener(new OnSeekbarChangeListener() {
#Override
public void valueChanged(Number value) {
long i = (long)value;
float finalValue = i/12;
total_height.setText("" + finalValue + " (ft)");
}
});
} catch (Throwable throwable) {
throwable.printStackTrace();
}

Related

Value is continuously increasing when the condition is true. Mediapipe library

When the condition is true my counter value is increasing continuously instead of only one value. If angle is greater than 90 degree it keeps increasing like 1,2,3,4,5 instead of 1 than 2 than 3
Shoulder = new float[] {landmarks.getLandmark(12).getX(),landmarks.getLandmark(12).getY()};
elbow =new float[] {landmarks.getLandmark(24).getX(),landmarks.getLandmark(24).getY()};
wrist = new float[] {landmarks.getLandmark(15).getX(),landmarks.getLandmark(15).getY()};
double angle = calculate_angle(Shoulder, elbow, wrist);
System.out.println(angle);
runOnUiThread(new Runnable() {
#Override
public void run() {
String stage="down";
// Stuff that updates the UI
if (angle > 90) {
stage = "down";
tv.setText(stage);
}
if (angle <=90 ){
stage = "up";
tv.setText(stage);
doSomething();
System.out.println("This is"+counter);
}
}
});
// Note: If eye_presence is false, these landmarks are useless.
Log.v(
TAG,
"[TS:"
+ packet.getTimestamp()
+ "] #Landmarks for iris: "
+ landmarks.getLandmarkCount());
Log.v(TAG, getLandmarksDebugString(landmarks));
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Couldn't Exception received - " + e);
return;
}
});
// }
}
public int doSomething(){
counter = counter +1;
tv2.setText(String.valueOf(counter));
System.out.println("This is bingo"+counter);
return (counter);
}
Seems like you want to add some delay. You'll need to either tamper with the UI thread ie Thread.sleeep() or use System.currentTimeMillis() to check the last time the thread ran it's work.

Integrating im2txt model in Android phone

I am new to TensorFlow and cannot find out the solution of these questions.
How can I retrain the im2txt model for my new dataset such that the dataset on which the im2txt model was trained does not get lost and my new dataset is added to the MSCOCO dataset to caption the new images (i.e training dataset= MSCOCO dataset + My new dataset). Someone, please share the detailed procedure and the problems that I can face while retraining.
I have found out the TensorFlow tutorial for running inception V3 model in android on real-time datasets, Can this method be applied as well to the im2txt model i.e. can this be made to caption an image taken from a mobile in real time. Someone, please share the detailed steps how to do this.
After the weeks of struggle can be able to run and execute the im2txt model on Android.
Since I found the solutions from different blogs and different questions and answers, Felt that it might be useful if the all(maximum) solution is at one place.So, Sharing the steps followed.
You need to clone the tensorflow project https://github.com/tensorflow/tensorflow/releases/tag/v1.5.0 in order to freeze the graph and for some more utils.
Downloaded the im2txt model form https://github.com/KranthiGV/Pretrained-Show-and-Tell-model
Followed the steps described in the above link Can able to Run the inference to generate captions on the Linux desktop Successfully after renaming some variable in the graph(to overcome NotFoundError (see above for traceback): Key lstm/basic_lstm_cell/bias not found in checkpoint types of errors)
Now we need to freeze the existing model to obtain the frozen graph in order to use in android/ios
from cloned tensorflow project using freeze_graph.py( tensorflow/tensorflow/blob/master/tensorflow/python/tools/freeze_graph.py) one can freeze the graph from any model by giving the following command
An example of command-line usage is:
bazel build tensorflow/python/tools:freeze_graph && \
bazel-bin/tensorflow/python/tools/freeze_graph \
--input_graph=some_graph_def.pb \
--input_checkpoint=model.ckpt-8361242 \
--output_graph=/tmp/frozen_graph.pb --output_node_names=softmax
--input_binary=true
we need to supply the all the output_node_names which we required to run the model, from "Pretrained-Show-and-Tell-model\im2txt\im2txt\inference_wrapper.py" we can list out the output node names as 'softmax', 'lstm/initial_state' and 'lstm/state'
when I run the freeze graph command by supplying the output node names as 'softmax', 'lstm/initial_state' and 'lstm/state' got the error "AssertionError: softmax is not in the graph"
From the answers for
How to freeze an im2txt model?(How to freeze an im2txt model?)
by Steph and Jeff Tang
The current model ckpt.data, ckpt.index and ckpt.meta files and a graph.pbtxt should be loaded in inference mode (see InferenceWrapper in im2txt). It builds a graph with the correct names 'softmax', 'lstm/initial_state' and 'lstm/state'. You save this graph (with the same ckpt format) and then you can apply the freeze_graph script to obtain the frozen model.
to do this in Pretrained-Show-and-Tell-model\im2txt\im2txt\inference_utils\inference_wrapper.base.py, just add something like saver.save(sess, "model/ckpt4") after saver.restore(sess, checkpoint_path) in def _restore_fn(sess):. Then rebuild and run_inference and you'll get a model that can be frozen, transformed, and optionally memmapped, to be loaded by iOS and Android apps
Now I run the command as below
python tensorflow/python/tools/freeze_graph.py \
--input_meta_graph=/tmp/ckpt4.meta \
--input_checkpoint=/tmp/ckpt4 \
--output_graph=/tmp/ckpt4_frozen.pb \
--output_node_names="softmax,lstm/initial_state,lstm/state" \
--input_binary=true
and loaded the obtained ckpt4_frozen.pb file into the Android application and got the error
"java.lang.IllegalArgumentException: No OpKernel was registered to support Op 'DecodeJpeg' with these attrs. Registered devices: [CPU], Registered kernels:
[[Node: decode/DecodeJpeg = DecodeJpegacceptable_fraction=1, channels=3, dct_method="", fancy_upscaling=true, ratio=1, try_recover_truncated=false]]"
From https://github.com/tensorflow/tensorflow/issues/2883
Since DecodeJpeg isn't supported as part of the Android tensorflow core, you'll need to strip it out of the graph first
bazel build tensorflow/python/tools:strip_unused && \
bazel-bin/tensorflow/python/tools/strip_unused \
--input_graph=ckpt4_frozen.pb \
--output_graph=ckpt4_frozen_stripped_graph.pb \
--input_node_names=convert_image/Cast,input_feed,lstm/state_feed\
--output_node_names=softmax,lstm/initial_state,lstm/state\
--input_binary=true
When I try to load ckpt4_frozen_stripped_graph.pb in android i faced errors so i followed Jeff Tang's answer (Error using Model after using optimize_for_inference.py on frozen graph)
Instead of tools:strip_unused I used graph transformation tool
bazel-bin/tensorflow/tools/graph_transforms/transform_graph \
--in_graph=/tmp/ckpt4_frozen.pb \
--out_graph=/tmp/ckpt4_frozen_transformed.pb \
--inputs="convert_image/Cast,input_feed,lstm/state_feed" \
--outputs="softmax,lstm/initial_state,lstm/state" \
--transforms='
strip_unused_nodes(type=float, shape="1,299,299,3")
fold_constants(ignore_errors=true)
fold_batch_norms
fold_old_batch_norms'
I can able load the obtained ckpt4_frozen_transformed.pb on android successfully.
when I supply the input as float array of RGB image pixels for input node "convert_image/Cast" and fetch the output from "lstm/initail_state" node successfully.
Now the challenge is to understand the beam search in "Pretrained-Show-and-Tell-model\im2txt\im2txt\inference_utils\caption_generator.py" and same should be implemented on the Android side.
If you observe the python script caption_generator.py at
softmax, new_states, metadata = self.model.inference_step(sess,input_feed,state_feed)
input_feed is an int32 bit array and state_feed is a multidimensional float array
on the android side, I tried feeding int32 bit array for "input_feed", since there is no Java API to feed multidimensional array so I fed float array to lstm/state_feed as it is which fetched previously from "lstm/initail_state" node.
Got two errors one is for the input_fedd is expecting int 64bit and
"java.lang.IllegalArgumentException: -input rank(-1) <= split_dim < input rank (1), but got 1" at lstm/state_feed.
For the first error, I changed the input_feed feed data type from int32 to int 64.
About second error it is expecting rank two tensor.
If you see tensorflow java sources the data type float array which we are feeding is converted to a rank one tensor, we should feed data type in such a way that rank two tensor should be created but at present, I didn't find any API to feed multidimensional float array there
When I browsing tensorflow java source I found the API which was not exposed as Android API where we can create a rank two tensor. so I rebuilt and both libtensorflow_inference.so and libandroid_tensorflow_inference_java.jar by enabling the rank two tensor creation call.(for building process refer https://blog.mindorks.com/android-tensorflow-machine-learning-example-ff0e9b2654cc)
Now I can able to run the inference on Android and get the one caption for the image.But the accuracy very low.
Reason limiting for the one caption is I didn't find a way to fetch the outputs as a multidimensional array which is required for generating more number of cations for a single image.
String actualFilename = labelFilename.split("file:///android_asset/")[1];
vocab = new Vocabulary(assetManager.open(actualFilename));
inferenceInterface = new TensorFlowInferenceInterface(assetManager, modelFilename);
final Graph g = c.inferenceInterface.graph();
final Operation inputOperation = g.operation(inputName);
if (inputOperation == null) {
throw new RuntimeException("Failed to find input Node '" + inputName + "'");
}
final Operation outPutOperation = g.operation(outputName);
if (outPutOperation == null) {
throw new RuntimeException("Failed to find output Node '" + outputName + "'");
}
// The shape of the output is [N, NUM_CLASSES], where N is the batch size.
int numClasses = (int) inferenceInterface.graph().operation(outputName)
.output(0).shape().size(1);
Log.i(TAG, "Read " + vocab.totalWords() + " labels, output layer size is " + numClasses);
// Ideally, inputSize could have been retrieved from the shape of the input operation. Alas,
// the placeholder node for input in the graphdef typically used does not specify a shape, so it
// must be passed in as a parameter.
inputSize = inputSize;
// Pre-allocate buffers.
outputNames = new String[]{outputName + ":0"};
outputs = new float[numClasses];
inferenceInterface.feed(inputName + ":0", pixels, inputSize, inputSize, 3);
inferenceInterface.run(outputNames, runStats);
inferenceInterface.fetch(outputName + ":0", outputs);
startIm2txtBeamSearch(outputs);
//Implemented Beam search in JAVA
private void startIm2txtBeamSearch(float[] outputs) {
int beam_size = 1;
//TODO:Prepare vocab ids from file
ArrayList<Integer> vocab_ids = new ArrayList<>();
vocab_ids.add(1);
int vocab_end_id = 2;
float lenth_normalization_factor = 0;
int maxCaptionLength = 20;
Graph g = inferenceInterface.graph();
//node input feed
String input_feed_node_name = "input_feed";
Operation inputOperation = g.operation(input_feed_node_name);
if (inputOperation == null) {
throw new RuntimeException("Failed to find input Node '" + input_feed_node_name + "'");
}
String output_feed_node_name = "softmax";
Operation outPutOperation = g.operation(output_feed_node_name);
if (outPutOperation == null) {
throw new RuntimeException("Failed to find output Node '" + output_feed_node_name + "'");
}
int output_feed_node_numClasses = (int) outPutOperation.output(0).shape().size(1);
Log.i(TAG, "Output layer " + output_feed_node_name + ", output layer size is " + output_feed_node_numClasses);
FloatBuffer output_feed_output = FloatBuffer.allocate(output_feed_node_numClasses);
//float [][] output_feed_output = new float[numClasses][];
//node state feed
String input_state_feed_node_name = "lstm/state_feed";
inputOperation = g.operation(input_state_feed_node_name);
if (inputOperation == null) {
throw new RuntimeException("Failed to find input Node '" + input_state_feed_node_name + "'");
}
String output_state_feed_node_name = "lstm/state";
outPutOperation = g.operation(output_state_feed_node_name);
if (outPutOperation == null) {
throw new RuntimeException("Failed to find output Node '" + output_state_feed_node_name + "'");
}
int output_state_feed_node_numClasses = (int) outPutOperation.output(0).shape().size(1);
Log.i(TAG, "Output layer " + output_state_feed_node_name + ", output layer size is " + output_state_feed_node_numClasses);
FloatBuffer output_state_output = FloatBuffer.allocate(output_state_feed_node_numClasses);
//float[][] output_state_output= new float[numClasses][];
String[] output_nodes = new String[]{output_feed_node_name, output_state_feed_node_name};
Caption initialBean = new Caption(vocab_ids, outputs, (float) 0.0, (float) 0.0);
TopN partialCaptions = new TopN(beam_size);
partialCaptions.push(initialBean);
TopN completeCaption = new TopN(beam_size);
captionLengthLoop:
for (int i = maxCaptionLength; i >= 0; i--) {
List<Caption> partialCaptionsList = new LinkedList<>(partialCaptions.extract(false));
partialCaptions.reset();
long[] input_feed = new long[partialCaptionsList.size()];
float[][] state_feed = new float[partialCaptionsList.size()][];
for (int j = 0; j < partialCaptionsList.size(); j++) {
Caption curCaption = partialCaptionsList.get(j);
ArrayList<Integer> senArray = curCaption.getSentence();
input_feed[j] = senArray.get(senArray.size() - 1);
state_feed[j] = curCaption.getState();
}
//feeding
inferenceInterface.feed(input_feed_node_name, input_feed, new long[]{input_feed.length});
inferenceInterface.feed(input_state_feed_node_name, state_feed, new long[]{state_feed.length});
//run
inferenceInterface.run(output_nodes, runStats);
//fetching
inferenceInterface.fetch(output_feed_node_name, output_feed_output);
inferenceInterface.fetch(output_state_feed_node_name, output_state_output);
float[] word_probabilities = new float[partialCaptionsList.size()];
float[] new_state = new float[partialCaptionsList.size()];
for (int k = 0; k < partialCaptionsList.size(); k++) {
word_probabilities = output_feed_output.array();
//output_feed_output.get(word_probabilities[k]);
new_state = output_state_output.array();
//output_feed_output.get(state[k]);
// For this partial caption, get the beam_size most probable next words.
Map<Integer, Float> word_and_probs = new LinkedHashMap<>();
//key is index of probability; value is index = word
for (int l = 0; l < word_probabilities.length; l++) {
word_and_probs.put(l, word_probabilities[l]);
}
//sorting
// word_and_probs = word_and_probs.entrySet().stream()
// .sorted(Map.Entry.comparingByValue())
// .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(e1, e2) -> e1, LinkedHashMap::new));
word_and_probs = MapUtil.sortByValue(word_and_probs);
//considering first (beam size probabilities)
LinkedHashMap<Integer, Float> final_word_and_probs = new LinkedHashMap<>();
for (int key : word_and_probs.keySet()) {
final_word_and_probs.put(key, word_and_probs.get(key));
if (final_word_and_probs.size() == beam_size)
break;
}
for (int w : final_word_and_probs.keySet()) {
float p = final_word_and_probs.get(w);
if (p < 1e-12) {//# Avoid log(0).
Log.d(TAG, "p is < 1e-12");
continue;
}
Caption partialCaption = partialCaptionsList.get(k);
ArrayList<Integer> sentence = new ArrayList<>(partialCaption.getSentence());
sentence.add(w);
float logprob = (float) (partialCaption.getPorb() + Math.log(p));
float scroe = logprob;
Caption beam = new Caption(sentence, new_state, logprob, scroe);
if (w == vocab_end_id) {
completeCaption.push(beam);
} else {
partialCaptions.push(beam);
}
}
if (partialCaptions.getSize() == 0)//run out of partial candidates; happens when beam_size = 1.
break captionLengthLoop;
}
//clear buffer retrieve sub sequent output
output_feed_output.clear();
output_state_output.clear();
output_feed_output = null;
output_state_output = null;
output_feed_output = FloatBuffer.allocate(output_feed_node_numClasses);
output_state_output = FloatBuffer.allocate(output_state_feed_node_numClasses);
Log.d(TAG, "----" + i + " Iteration completed----");
}
Log.d(TAG, "----Total Iterations completed----");
LinkedList<Caption> completeCaptions = completeCaption.extract(true);
for (Caption cap : completeCaptions) {
ArrayList<Integer> wordids = cap.getSentence();
StringBuffer caption = new StringBuffer();
boolean isFirst = true;
for (int word : wordids) {
if (!isFirst)
caption.append(" ");
caption.append(vocab.getWord(word));
isFirst = false;
}
Log.d(TAG, "Cap score = " + Math.exp(cap.getScore()) + " and Caption is " + caption);
}
}
//Vocab
public class Vocabulary {
String TAG = Vocabulary.class.getSimpleName();
String start_word = "<S>", end_word = "</S>", unk_word = "<UNK>";
ArrayList<String> words;
public Vocabulary(File vocab_file) {
loadVocabsFromFile(vocab_file);
}
public Vocabulary(InputStream vocab_file_stream) {
words = readLinesFromFileAndLoadWords(new InputStreamReader(vocab_file_stream));
}
public Vocabulary(String vocab_file_path) {
File vocabFile = new File(vocab_file_path);
loadVocabsFromFile(vocabFile);
}
private void loadVocabsFromFile(File vocabFile) {
try {
this.words = readLinesFromFileAndLoadWords(new FileReader(vocabFile));
//Log.d(TAG, "Words read from file = " + words.size());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
private ArrayList<String> readLinesFromFileAndLoadWords(InputStreamReader file_reader) {
ArrayList<String> words = new ArrayList<>();
try (BufferedReader br = new BufferedReader(file_reader)) {
String line;
while ((line = br.readLine()) != null) {
// process the line.
words.add(line.split(" ")[0].trim());
}
br.close();
if (!words.contains(unk_word))
words.add(unk_word);
} catch (IOException e) {
e.printStackTrace();
}
return words;
}
public String getWord(int word_id) {
if (words != null)
if (word_id >= 0 && word_id < words.size())
return words.get(word_id);
return "No word found, Maybe Vocab File not loaded";
}
public int totalWords() {
if (words != null)
return words.size();
return 0;
}
}
//MapUtil
public class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
List<Map.Entry<K, V>> list = new ArrayList<>(map.entrySet());
list.sort(new Comparator<Map.Entry<K, V>>() {
#Override
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
if (o1.getValue() instanceof Float && o2.getValue() instanceof Float) {
Float o1Float = (Float) o1.getValue();
Float o2Float = (Float) o2.getValue();
return o1Float >= o2Float ? -1 : 1;
}
return 0;
}
});
Map<K, V> result = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
}
//Caption
public class Caption implements Comparable<Caption> {
private ArrayList<Integer> sentence;
private float[] state;
private float porb;
private float score;
public Caption(ArrayList<Integer> sentence, float[] state, float porb, float score) {
this.sentence = sentence;
this.state = state;
this.porb = porb;
this.score = score;
}
public ArrayList<Integer> getSentence() {
return sentence;
}
public void setSentence(ArrayList<Integer> sentence) {
this.sentence = sentence;
}
public float[] getState() {
return state;
}
public void setState(float[] state) {
this.state = state;
}
public float getPorb() {
return porb;
}
public void setPorb(float porb) {
this.porb = porb;
}
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
#Override
public int compareTo(#NonNull Caption oc) {
if (score == oc.score)
return 0;
if (score < oc.score)
return -1;
else
return 1;
}
}
//TopN
public class TopN {
//Maintains the top n elements of an incrementally provided set.
int n;
LinkedList<Caption> data;
public TopN(int n) {
this.n = n;
this.data = new LinkedList<>();
}
public int getSize() {
if (data != null)
return data.size();
return 0;
}
//Pushes a new element
public void push(Caption x) {
if (data != null) {
if (getSize() < n) {
data.add(x);
} else {
data.removeLast();
data.add(x);
}
}
}
//Extracts all elements from the TopN. This is a destructive operation.
//The only method that can be called immediately after extract() is reset().
//Args:
//sort: Whether to return the elements in descending sorted order.
//Returns: A list of data; the top n elements provided to the set.
public LinkedList<Caption> extract(boolean sort) {
if (sort) {
Collections.sort(data);
}
return data;
}
//Returns the TopN to an empty state.
public void reset() {
if (data != null) data.clear();
}
}
Even though accuracy is very low I am sharing this because it might be useful for some to load the show and tell models in android.

swipe or scroll to bottom in appium - android

How can I swipe scroll to bottom in an android app using appium?
I tried using
driver.swipe(300,800,300,500,2);
driver.scrollTo("string")
But above did not helped. Can anyone suggest me some generic solution ?
A generic solution will be scrolling using dimensions. use the below code
public void scroll() throws IOException {
try {
Dimension dimensions = driver.manage().window().getSize();
System.out.println("Size of screen= " +dimensions);
int Startpoint = (int) (dimensions.getHeight() * 0.5);
System.out.println("Size of scrollStart= " +Startpoint );
int scrollEnd = (int) (dimensions.getHeight() * 0.2);
System.out.println("Size of cscrollEnd= " + scrollEnd);
driver.swipe(0, Startpoint,0,scrollEnd,1000);
} catch (IOException e) {
}
}
add this to ur code and simply use scroll(); in ur test case. Modify the decimal values given in the code to nmeet your requirements

The difference between onratingbarchanged and onratingbarclicked android

I've got a rating bar in my android application which is in a custom adapter. I've set the ratingbar to listen for a change and on that change, update the database through a cient/server architecture. I then use the custom adapter in a master/details view. The problem is, everytime I load the details page on click of the left-hand list item, it updates the rating bar. This is not what I want. I only want to update the rating bar once it's been clicked, not everytime the adapter is used.
Is there way to only fire an event when it is clicked and not changed. Is there a major difference between onratingbarchanged (which it is currently) and onratingbarclicked (which I'm assuming is what I should be doing?)
My code is as follows:
//Should this rather be setOnClickListener()???
ratingBar.setOnRatingBarChangeListener(new OnRatingBarChangeListener()
{
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser)
{
questions.get(position).TotalRating = rating;
String newRating = "" + rating;
ratingBar.setRating(rating);
Toast.makeText(getContext(),
"Rating set to: " + rating + " for the position: " + position, Toast.LENGTH_SHORT).show();
String question = questions.get(position).Question;
//Create XML with both position/question to send to doAsyncTask
serverUpdateRating update = new serverUpdateRating();
Document doc;
try
{
//Create an XML document with question from the selected position as well as the new rating
doc = x.createDoc();
Element tutor = doc.createElement("Update");
tutor.appendChild(x.UpdateRating(doc, newRating, question));
doc.appendChild(tutor);
//Create a string
String s = x.getStringFromDocument(doc);
String result = update.execute(s).get();
//return either true (updated correctly) or false (problem)
if (result.equals("true"))
{
Toast.makeText(getContext(),
"Rating successfully updated", Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(getContext(),
"Rating update unsuccessful", Toast.LENGTH_LONG).show();
}
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
I don't know if there is a workaround for this, but if there is, I would be extremely grateful!
You could use fromUser in onRatingChanged
onRatingChanged :
[...] fromUser True if the rating change was initiated by a user's touch
gesture or arrow key/horizontal trackbell movement.

Change the step size of a NumberPicker

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

Categories

Resources