Enter fractions in a uitextfield from 3 UIPickers? - objective-c

So what I'm intending to do is instead of typing in decimals, I want to be able to enter whole numbers and fractions in a textfield. Or select them from a UIPicker.
Example: Feet, Inches, fractions.(2 - 4 1/2).
What's the best way to accomplish this? Please be detailed in your answer. Thank you in advance!
Update: Ok maybe a little more detail is needed.
I'm going to use the picker, and want to display 5 rows like this:
<Ft> <In>
0 0 S 0 0 S 1/16
1 1 P 1 1 P 1/8
2 2 A 2 2 A 3/16
3 3 C 3 3 C 1/4
4 4 E 4 4 E 5/16
ect...all the way to 9, and to 15/16 for the fractions. (Note the space between Ft and Inches and title for row).
Ok, So I was able to get 3 pickers to display on screen just how I wanted, my biggest issue is getting it to display in the textfield properly. So just how the example is above, ft has it's own picker, inches has it's own, and fractions has it's own, How would you get all three to display as "00ft 00 0/0in" in one text field?
UPDATE: the code below is correct, make sure you create an IBOutlet for your UIView that contains the pickers, and hook it up in IB.
.m file
feetArray = [[NSMutableArray alloc] init];
for(int feet = 0; feet <= 9; feet ++){
NSString *feetString = [NSString stringWithFormat:#"%d%", feet];
[feetArray addObject:feetString]; // Add the string.
}
inchArray = [[NSMutableArray alloc] init];
for(int inch = 0; inch <= 12; inch ++){
NSString *inchString = [NSString stringWithFormat:#"%d%", inch];
[inchArray addObject:inchString]; // Add the string.
}
fractionArray = [[NSMutableArray alloc] init];
for(int frac = 0; frac <= 15; frac ++){
NSString *fractionString = [NSString stringWithFormat:#"%d/16", frac];
[fractionArray addObject:fractionString]; // Add the string.
}
}
//How many rows in each Picker.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
if (pickerView.tag == 1) {
return 2;
}
if (pickerView.tag == 2) {
return 2;
}
return 1;
}
//Selects array for each picker.
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (pickerView.tag == 1) {
return [feetArray count];
}
if (pickerView.tag == 2) {
return [inchArray count];
}
return [fractionArray count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
if (pickerView.tag == 1) {
return [feetArray objectAtIndex:row];
}
if (pickerView.tag == 2) {
return [inchArray objectAtIndex:row];
}
return [fractionArray objectAtIndex:row];
}
//Formats the textfield based on the pickers.
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
NSString *result = [feetArray objectAtIndex:[feetPicker selectedRowInComponent:0]];
result = [result stringByAppendingFormat:#"%#ft", [feetArray objectAtIndex:[feetPicker selectedRowInComponent:1]]];
result = [result stringByAppendingFormat:#" %#", [inchArray objectAtIndex:[inchesPicker selectedRowInComponent:0]]];
result = [result stringByAppendingFormat:#"%#", [inchArray objectAtIndex:[inchesPicker selectedRowInComponent:1]]];
result = [result stringByAppendingFormat:#" %#in", [fractionArray objectAtIndex:[fractionPicker selectedRowInComponent:0]]];
RiseTextField.text = result;
}

By setting up UIPickerView object as the inputView, you won't need to worry about text input. Tapping on the text field would bring up the picker and make the input constrained just as you want it. You can either subclass or set them directly in your controller. I set it up as a subclass here. Its a rough implementation of what you need as I understand it. You can take a look and see if it helps.

I would advice to use a picker, it's way easier then typing fractions and will prevent the input of incorrect fractions.
There are two ways to get the fractions into your UIPicker, use the pickerView:titleForRow:forComponent: method of your UIPicker delegate to give the fraction as a string. You can use UTF8 fraction characters like ¼ with this function.
If is not giving enough flexibility. You could make images of the fractions and put the images into the picker by using the pickerView:viewForRow:forComponent:reusingView: method of your delegate.
The documentation will give you lots of information! Good luck!

It sounds like you want something like the date picker with multiple wheels to choose each part of the distance. Unfortunately there isn't a way to do this. You have 2 options though. The simple option is to use several pickers next to each other. It wont look quite the same but it's simple. The more complicated option is to build one with UIScrollViews and style it to look the way you want it too.

Related

UIPickerView with multiple components / 3rd component items based on component 1 and 2 selection

I just created a UIPickerView with three components. The user selects numbers in wheel 1 and 2 and based on those selections it will show either one of two possible arrays in wheel/component 3. I've got it to work fine with one exception:
Problem:
In order to have the 3rd component updated based on selection of component 1 and 2, the user has to actually physically select an item by moving the picker wheels. But there might be situation in which the user wants to use the default selection (in my case an NSString "0" in component 1 and 2) and does not touch those wheels. Therefore component 3 will not get updated.
Any idea how to address this problem? Is there a way I can update the UIPickerView before the user selects the item in the third component, in order to tricker the default selection in component 1 and 2 as an actual selection without having the user actually move those wheels?
Or lets formulate the question that way: can I have the default row of a UIPickerView automatically selected without selecting the particular row with the finger?
Additional explanation of what I try to accomplish:
when the user clicks in a textfield, an UIPickerView with three columns will open up. In the first wheel the user selects a number between 0 and 16, in the second he will select a fraction, and in the third a measuring unit. For example:
1 1/2 cups,
1 ounce,
1/2 cup,
etc.
Based on the number and fraction selection the unit names in the third picker wheel will either be shown in singular or plural spelling (1 cup vs. 2 cups). The whole thing works perfectly as long the first two wheels are touched and a physically selection is done. Problem: lets take for example that the user wants to select "1 ounce". He will move the first wheel to 1, will leave the second alone (as it is already positioned on the 0), and then choose "ounces". But with my code the third wheel will not update to singular spelling. ONLY, if I actually move the second wheel and go back to 0. Then the 3rd wheel instantly changes.
Thanks!!
Here is the code I have so far:
_countPickerData = #[#"0", #"1", #"2", #"3", #"4", #"5", #"6", #"7", #"8", #"9", #"10", #"11", #"12", #"13", #"14", #"15", #"16"];
_fractionPickerData = #[#"0", #"1/2", #"1/4", #"1/8", #"3/4", #"3/8", #"5/8", #"7/8"];
_singularUnitPickerData = #[#"NONE", #"ounce", #"cup", #"pound"];
_pluralUnitPickerData = #[#"NONE", #"ounces", #"cups", #"pounds"];
// The number of columns of data
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 3;
}
// The number of rows of data
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
switch (component) {
case 0: return [_countPickerData count];
case 1: return [_fractionPickerData count];
case 2:
if (([countHelper isEqualToString:#"1"] && [countFractionHelper isEqualToString:#"0"]) || ([countHelper isEqualToString:#"0"] && ([countFractionHelper isEqualToString:#"1/2" ] || [countFractionHelper isEqualToString:#"1/4"] || [countFractionHelper isEqualToString:#"1/8"])))
{
return [_singularUnitPickerData count];
}
else
{
return [_pluralUnitPickerData count];
}
}
return 0;
}
// The data to return for the row and component (column) that's being passed in
- (NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
switch (component)
{
case 0: return [_countPickerData objectAtIndex:row];
case 1: return [_fractionPickerData objectAtIndex:row];
case 2:
if (([countHelper isEqualToString:#"1"] && [countFractionHelper isEqualToString:#"0"]) || ([countHelper isEqualToString:#"0"] && ([countFractionHelper isEqualToString:#"1/2" ] || [countFractionHelper isEqualToString:#"1/4"] || [countFractionHelper isEqualToString:#"1/8"])))
{
pickedUnitHelper = [_singularUnitPickerData objectAtIndex:row];
return pickedUnitHelper;
}
else
{
pickedUnitHelper = [_pluralUnitPickerData objectAtIndex:row];
return pickedUnitHelper;
}
default:break;
}return nil;
}
// Preparing pickerView selection for textFieldIngredientUnit
NSInteger selectedRowUnit;
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
switch (component)
{
case 0:
countHelper = [_countPickerData objectAtIndex:row];
return;
case 1:
countFractionHelper = [_fractionPickerData objectAtIndex:row];
return;
case 2:
if (([countHelper isEqualToString:#"1"] && [countFractionHelper isEqualToString:#"0"]) || ([countHelper isEqualToString:#"0"] && ([countFractionHelper isEqualToString:#"1/2" ] || [countFractionHelper isEqualToString:#"1/4"] || [countFractionHelper isEqualToString:#"1/8"])))
{
pickedUnitHelper = [_singularUnitPickerData objectAtIndex:row];
return;
}
else
{
pickedUnitHelper = [_pluralUnitPickerData objectAtIndex:row];
return;
}
default:break;
}
}
Yes, you can automatically select a row of the picker without touching it with your finger. For example:
[self.pickerView selectRow:0 inComponent:2 animated:YES];
Call this before the view appears on the screen. Probably in viewWillAppear:
Update:
Markus and I checked this out over chat, and I came up with a solution. Basically, any time:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
is called, if it is component 0 or 1, we need to reload component 2. We do this (within the didSelectRow method) by saying:
[pickerView reloadComponent:2];
There were a couple other minor things in his code that weren't working correctly, but for the purpose of this stack overflow question, this is all that needs to be explained.
I recently had the very same problem (uipickerview not selecting the first value). I tried to do..
[_myPicker selectRow:0 in Component:0 animated:YES];
But that still did not select the value, it turned the picker to whatever I chose in selectRow and Component, but did not send that value anywhere. So what I did was to create an extra row in my picker's array. My picker values where 1, 2, 3, and 4. So when I added the array it looked like this..
_myPickerArray = [[NSArray alloc] initWithObjects:#" ", #"1", #"2", #"3", #"4", nil];
Now the user must turn the wheel to select something. In your code you are checking if the input is a string of 1. If they select the space, then that condition will not be met. See if that works.

UIPickerView values

I want UIPicker to start from 2 (0, 1 to be not displayed)
self.tmpArray = [NSMutableArray arrayWithCapacity:10];
for(int x = 2; x < 10; x++)
{
[self.tmpArray addObject:[NSNumber numberWithInt:x]];
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return [self.tmpArray count];
}
With the code above UIPicker shows 0,1,2,3 etc...
You're not in any way passing on the values from tmpArray, so they have no bearing on what UIPickerView displays.
You need to implement viewForRow:forComponent: and be able to supply suitable views when the picker view requests them.

loop Nsmutable arrray of uiimages from end to beginning

I have an NSMUtable array of images where a different image is displayed with a previous and a next button, but when I get to the end of the array the simulator crashes. I want to loop the end of the array to the beginning so that when I get to the end of the array of images when I hit the next button again it loops back to the first image, also when Im at the first image if I hit the previous button it loops to the last image with no crashes
What you want is a circular array, which is easy to implement using a standard NSMutableArray. For instance, say you store your images in an array called imageArray and use a simple variable to keep track of the index of your current image, like:
int currentImageIndex = 0;
...then you might implement nextImage and previousImage like:
- (UIImage*) nextImage {
currentImageIndex = (currentImageIndex + 1) % [imageArray count];
return [imageArray objectAtIndex:currentImageIndex];
}
- (UIImage*) previousImage {
currentImageIndex--;
if (currentImageIndex < 0) {
currentImageIndex = [imageArray count] - 1;
}
return [imageArray objectAtIndex:currentImageIndex];
}
Then just use nextImage and previousImage whenever you want to step through the array, and problem solved.
Simple enough to do. all you need to do is create a check to see if you're on the last element, and if so, set your tracker (like count or i etc) to 0 again,
Heres the psudo code
//set index
if ( array [ index ] == len(array) - 1) //at end
{
index = 0
}
if(array [index] == -1)//at beginning
{
index = len(array) -1
}
// do something with array[index]
I want to propose this solution:
A property for the selected UIImage, a NSInteger property to hold the current index.
-(IBAction) nextButtonTapped:(id)sender
{
self.currentIndex = self.currentIndex++ % [self.images count];
self.selectedImage= [self.images objectAtIndex:self.currentIndex];
[self reloadImageView];
}
-(IBAction) previousButtonTapped:(id)sender
{
self.currentIndex--;
if (self.currentIndex < 0)
self.currentIndex += [self.images count];
self.selectedImage= [self.images objectAtIndex:self.currentIndex];
[self reloadImageView];
}
-(void)reloadImageView
{
//do, what is necessary to display new image. Animation?
}

UISegmentedControl writing text labels problem

Goodday,
I got the following problem with this code:
-(void)textpopup:(UISegmentedControl *)sender {
int nummer = sender.tag;
if (sender.tag) {
if(sender.selectedSegmentIndex == 0 || sender.selectedSegmentIndex == 1){
beoordeling = [[UITextField alloc] init];
beoordeling.frame = CGRectMake(50 , nummer * 117 + 275 , scrollView.frame.size.width - 100 , 35);
beoordeling.autoresizingMask = (UIViewAutoresizingFlexibleWidth);
beoordeling.borderStyle = UITextBorderStyleLine;
beoordeling.tag = nummer;
[scrollView addSubview:beoordeling];
}
if(sender.selectedSegmentIndex == 2 || sender.selectedSegmentIndex == 3){
if (beoordeling.tag == sender.tag) {
[beoordeling removeFromSuperview];
}
}
}
}
i shall explain the scenario. I got some dynamic UISegmentedControls. At the moment there are 12 of them. At the first 2 segments chosen, a textfield needs to popup. This goes well. But after choosing the first 2 segments for a while and when i go to segments 2 and 3, sometimes the textfields won't remove.
I expected that the textfields which are written when i push segment 0 and 1 are removed when segment 2 and 3 are pushed.
Am i missing something?
EDIT:
At first i want to say, that i never know in advance how many UITextFields i got. When segments 0 and 1 are chosen, a UITextField needs to popup to that corresponding UISegmentedControl. And when segments 2 and 3 are chosen, the UITextField needs to stay away. But i got that fixed now in the following way.
-(void)textpopup:(UISegmentedControl *)sender {
int nummer = sender.tag;
if(sender.selectedSegmentIndex == 0 || sender.selectedSegmentIndex == 1){
// Before i add a new UITextField, the old one has to be removed.
UITextField *text = (UITextField *)[beoordeling viewWithTag:sender.tag];
[text removeFromSuperView];
beoordeling = [[UITextField alloc] init];
beoordeling.frame = CGRectMake(50 , nummer * 117 + 275 , scrollView.frame.size.width - 100 , 35);
beoordeling.autoresizingMask = (UIViewAutoresizingFlexibleWidth);
beoordeling.borderStyle = UITextBorderStyleLine;
beoordeling.tag = nummer;
[scrollView addSubview:beoordeling];
}
else if(sender.selectedSegmentIndex == 2 || sender.selectedSegmentIndex == 3) {
UITextField *tf = (UITextField *)[beoordeling viewWithTag:sender.tag];
tf.text = nil;
[tf removeFromSuperview];
}
}
The second if should be an else if, because it should execute only if the first one doesn't (the selected index can't be both 0 and 2).
What you're trying to do depends on how you've defined beoordeling. I suggest having it as an instance variable, possibly even an IBOutlet. Release in your class's dealloc. Then, in the first if clause, write
if (!beoordeling) {
beoordeling = [[UITextField alloc] init];
// Other setup
}
[scrollView addSubview:beoordeling];
I don't quite understand why you're checking for the tag, but to remove in the second if, just call removeFromSubview.
Do all your segmented controls invoke the same behavior? If you have only one beorrdeling that you're setting the tag on, then you don't need to bother checking for the tag. Just add/remove it, using removeFromSubview. If you have as many of text fields as segmented controls, maybe KVC would be what you want. If your segmented controls' tags go from 0–11, you might have beoordeling0, beoordeling1, beoordeling2, and so on. Then, to get the one you want, use something like this:
beoordeling = (UITextField *)[self valueForKey:[NSString stringWithFormat:#"beoordeling%d", sender.tag]];
Not really sure what you are trying to achieve here, but you do need to release your UITextField object beoordeling or you will leak. AddSubview adds one to the retain count, so should be safe to release straight away:
[scrollView addSubview:beoordeling];
[beoordeling release];

Label display not instant with iPhone app

I am developing an application for the iPhone. The question I have is how to display a new label with a different text every .5 seconds. For example, it would display Blue, Red, Green, Orange and Purple; one right after one another. Right now I am doing this:
results = aDictionary;
NSArray *myKeys = [results allKeys];
NSArray *sortedKeys = [myKey sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
int keyCount = [sortedKeys count];
while (flag == NO) {
NSTimeInterval timeMS = [startDate timeIntervalSinceNow] * -10000.0;
if (timeMS >= i) {
ii++;
i += 1000;
NSLog(#"endDate = %f", timeMS);
int randomNumber = rand() % keyCount + 1;
lblResult.text = [results valueForKey:[sortedKeys objectAtIndex:(randomNumber - 1)]];
result = [results valueForKey:[sortedKeys objectAtIndex:(randomNumber - 1)]];
lblResult.text = result;
}
if (ii > 25) {
flag = YES;
}
}
lblResult.text = [results valueForKey:[sortedKeys objectAtIndex:(sortedKeys.count - 1)]];
this function is called at the viewDidAppear Function and currently isn't displaying the new labels. It only displays the one at the end. Am I doing anything wrong? What would be the best method to approach this?
The problem is that you're not giving the run loop a chance to run (and therefore, drawing to happen). You'll want to use an NSTimer that fires periodically and sets the next text (you could remember in an instance variable where you currently are).
Or use something like this (assuming that items is an NSArray holding your strings):
- (void)updateText:(NSNumber *)num
{
NSUInteger index = [num unsignedInteger];
[label setText:[items objectAtIndex:index]];
index++;
// to loop, add
// if (index == [items count]) { index = 0; }
if (index < [items count]) {
[self performSelector:#selector(updateText:) withObject:[NSNumber numberWithUnsignedInteger:index] afterDelay:0.5];
}
}
At the beginning (e.g. in viewDidAppear:), you could then call
[self updateText:[NSNumber numberWithUnsignedInteger:0]];
to trigger the initial update.
You'd of course need to ensure that the performs are not continuing when your view disappears, you could do this by canceling the performSelector, or if you're using a timer, by simply invalidating it, or using a boolean, or ...
And if you want to get really fancy, use GCD :)