|Android Adventures - A NumberPicker DialogFragment Project|
|Written by Mike James|
|Thursday, 14 August 2014|
Page 2 of 3
Adding the NumberPickers
Next we need to add a number of NumberPickers. The simplest way is to use a for loop:
This works but saving a reference to each of the NumberPicker objects would be useful for later code development. All we need for this is a private array. Another problem is that if we simply use the loop index to store the NumberPickers in the array we will end up with the high order value in array. To make things work as expected we need to store the low value NumberPicker in array.
To declare the array:
and the for loop becomes:
The use of numDials-i-1 simply reverses the index - alternatively you could just run the for loop from numDials-1 to 0.
The new line that involves setValue sets the NumberPickers to the current value which when the dialog is first displayed is the initial value supplied by the user. We still need to write the function getDigit.
Overall this code uses various things that are yet to be defined: numDials, currentValue and getDigit.
The Vertical LinearLayout
Finally we need the vertical LinearLayout and the button to complete the UI.
Creating the vertical LinearLayout is just more of the same:
The only new thing is that we have to set the orientation and finally we add the horizontal LinearLayout to nest it within the vertical layout.
Now we need to add the button. This just has some text, "Done" and an onClick handler. The details of the onClick handler are best explained later so for the moment let's just use a stub that we can come back and fill in later:
We also need to set the button to center inside the container and this is done by setting Gravity to CENTER_HORIZONTAL. If you didn't know this you could find it out by seeing what centered a button in a vertical LinearLayout using the designer - experiment is often the quickest way. In code you set gravity on a LayoutParams object because it is actually enforced by the container. This makes sense if you think about it because only the container can center an object within it.
Finally we add the button to the vertical LinearLayout and return it as the result of the onCreateView:
Apart from a few missing details such as a value for numDials you could run the program at this point and you would see the UI appear as in the screen dump at the start of the article.
All that remains to do is implement the initialization of the two parameters, provide the code for getDigit and deal with what should happen when the Done button is selected.
We have chosen to use the object factory approach to initializing the Fragment and this has been covered in previous chapters.
Essentially all we have to do is customize the generated code to work with our two integer parameters numDials and currentValue. First we need some private variables to store their values in:
These replace the generated declarations of param1 and param2.
As these values are going to be stored in a bundle for later retrieval we also need to customize the key names that have been generated. Change the lines at the top of the program that have ARG_PARM1 and ARG_PARAM2 to:
You don't have to use these key definitions if you don't want to - you can simply enter the keyvalues directly when needed, see later.
With these definitions we can now work on customising the object factory to use these parameters in place of the generated ones:
You can see that now the factory accepts two parameters and these are stored in the arguments bundle for later use.
In case you are still wondering why a bundle is used rather than simply storing the intial parameters in the corresponding private variables it is worth pointing out that this is a static method and it doesn't have access to the instance variables. You could create get/set methods for the private methods and then the static method could set them on the instance i.e. numdialog. You could even make the variables public and use;
However using the bundle also solves the problem of restoring the state when the fragment is recreated.
So how does the instance get access to the initial parameters?
If you recall the answer is that the onCreate method retrieves them from the bundle:
You can also see that this is the place to create the NumberPicker array that is needed. As onCreate is always called before onCreateView all of the data we need, including the array is ready to be used by it.
Now that we have the currentValue of the NumberPickers safely stored we can tackle the problem of creating getDigit. This is a function that extracts the ith digit from a number n:
We need it because if the user specifies an initial value of 123 then we need to set the low order NumberPicker to 3, the next to 2 and the high order to 1. That is we need to extract each digit in turn.
I have to admit that crating this function occupied more time that was reasonable. A purely numeric solution is to take the remainder on division by a power of 10. For example (123)%10=3, (123)%100=23 and (123)%1000=123. If you integer divide the first by 1, the second by 10 and the final value by 100 you get 3, 2 and 1.
This is fine but creating powers of 10 in Java involves the use of the math object and it returns a double. An alternative is to use String handling and this is the method I eventually used, but to be honest it seems too complicated as well:
The computation with i is necessary because we are calling the low order digit, digit zero and it is the high order digit that is character zero in the String.
The onDone event
Now all we have to deal with is what happens when the user selects the Done button.
To do this we need to implement the Fragment interface pattern as discussed in previous chapters.
First we need to define an interface for a suitable listener and event handler. We need to call the interface something that isn't going to clash or mislead the user:
This code has to replace the interface generated by the tempate.
The onDone method simply sends the current value set on the NumberPickers to the Activity that is using the dialog as an event parameter.
Next we have to modify the onAttach generated code so that we retrieve the Activity's implementation of the interface to work with the newly named interface:
We also need to modify the private variable mListener used to store the Activity's implementation:
|Last Updated ( Saturday, 25 July 2015 )|