I'm using UIPickerView with (for example) 4 rows. The first value is "Pick a value" with gray text. The others are values the user should pick with black text.
The picking is optional, so users could just skip it. But if they don't, how to make first value unselectable back after user will start picking?
Thanks.
Regards.
Use the UIPickerView delegate method - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component to change the selected row if the first row is selected :
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
if (row == 0) {
[pickerView selectRow:row+1 inComponent:component animated:YES];
}
}
Edit : you may be able to change the text color using this :
- (NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component {
if (row == 0)
return [[NSAttributedString alloc] initWithString:#"Pick a value" attributes:#{NSForegroundColorAttributeName:[UIColor lightGrayColor]}];
else {
// Return titles
}
}
This is if you target iOS 6+, and it replaces the previously used -pickerView:titleForRow:forComponent: method.
Related
I have put a UIPickerView for the user to select how they are feeling; annoyed, happy, sad etc. However I cannot convert what they have selected to a string or text. Is it possible to do this? If not how can I save the row/option they have selected in the picker?
If i understood your question correctly, here's what is needed. Check out the project at this gitHub commit or download zip.
Using typedef enum: create a enumeration that holds all values of emotions; happy, okay, neutral, sad, unhappy, etc. All with unique values assigned to each one like so:
Header File
//Number Values for each value of emotion. Add new emotions to the bottom of list, sort will not
//be effected in this declartion
typedef enum : NSUInteger {
CTEmotionNone = 0,
CTEmotionHappy = 1,
CTEmotionOkay = 2,
CTEmotionNeutral = 3,
CTEmotionSad = 4,
CTEmotionUnhappy = 5,
CTEmotionVeryHappy = 6
} CDEmotions;
Translating Number Values to text: There's different ways to doing this part but i liked this. Create an inline method, or function, that will return a string for the corresponding value of emotion:
Header File
//Here is where the title for each number value will be transalated
static inline NSString * NSEmotionTitleForEmotion( CDEmotions emotion) {
switch (emotion) {
case CTEmotionNone:
return #"Empty"; break;
case CTEmotionVeryHappy:
return #"Very Happy"; break;
case CTEmotionHappy:
return #"Happy"; break;
case CTEmotionOkay:
return #"Okay"; break;
case CTEmotionNeutral:
return #"Neutral"; break;
case CTEmotionSad:
return #"Sad"; break;
case CTEmotionUnhappy:
return #"Unhappy"; break;
}
}
Now the Order: creating another inline method, but this time returning an array with the order you want to display the emotions:
Header File
//Sorted int values in this array. Sort will be shown here. Do not put text in here, because then
//to know what "Very Happy" is you'll ahve to compare it to a string vs just saying 1 == 1, that
//means CTEmotionHappy
static inline NSArray * NSEmotionsList() {
return [NSArray arrayWithObjects:
#(CTEmotionNone),
#(CTEmotionVeryHappy),
#(CTEmotionHappy),
#(CTEmotionOkay),
#(CTEmotionNeutral),
#(CTEmotionSad),
#(CTEmotionUnhappy), nil];
}
Now using these functions will be fun :) I'll do it in your case using - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component from the UIPickerViewDataSource:
ViewController.h
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return [NSEmotionsList() count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return NSEmotionTitleForEmotion( [[NSEmotionsList() objectAtIndex: row] intValue]);
}
And lastly implement the delegate method - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
[labelEmotion setText: NSEmotionTitleForEmotion( [[NSEmotionsList() objectAtIndex: row] intValue])];
}
I have an app where the user scans a QR code into an NSString, which I then need to put into a UIPickerView.
What would I use to set the text of the UIPickerView row as the NSString from the QR code?
Firstly, you need to have an array of strings and implement the UIPickerViewDataSource and UIPickerViewDelegate in your .h file. After this, you will have to make use of the delegate methods of UIPickerView like as shown :
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
//return number.
}
This will return the number of sections that you want in your pickerView.
(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return array.count;
}
The above method will return the number of rows in particular component. If you have an array, then probably it will be equal to the number of elements in your array. And finally this last one.
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *str;
if(pickerView == yourPickerName)
{
str = [array objectAtIndex:row];
}
return str;
}
This method will return the text value for each row in your picker. And don't forget to connect your pickerView's datasource and delegate in your Storyboard.
Hope this helps.
I have a viewcontroller showing items from a core data entity. I also have a tableview listing records from the same entity. The table is editable, and the user could remove all the records. When this happens, the view controller holding the pickerview bombs because it's looking for records in an empty array. How to prevent this? I'm assuming I need to do something different at objectAtIndex:row...
# pragma mark PickerView Section
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1; // returns the number of columns to display.
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [profiles count]; // returns the number of rows
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
// Display the profiles we've fetched on the picker
Profiles *prof = [profiles objectAtIndex:row];
return prof.profilename;
}
//If the user chooses from the pickerview
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
selectedProfile = [[profiles objectAtIndex:row]valueForKey:#"profilename"];
}
EDIT**
Ok, I found what was causing the problem...on the PickerView I was setting a default..
self.profiles = [[self.managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
selectedProfile = [[profiles objectAtIndex:0]valueForKey:#"profilename"];
[pickerView reloadAllComponents];
When I take that out, it works like a champ.
I have a pickerview that loads from a core data fetch on the view controller did load method. Everything works great, however I'm finding that I'm passing null values quite often, and that I'm having to spin the picker back and forth and click several times to get the value to hold.
I also have a problem if the user doesn't manually pick something, I need it to pass the value that the picker is on. I have a datepicker on the same viewcontroller and it passes whatever date it is sitting on without any problems. I'm probably overlooking something..any help would be appreciated
# pragma mark PickerView Section
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1; // returns the number of columns to display.
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [profiles count]; // returns the number of rows
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
// Display the profiles we've fetched on the picker
Profiles *prof = [profiles objectAtIndex:row];
return prof.profilename;
}
//If the user chooses from the pickerview
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
selectedProfile = [[profiles objectAtIndex:row]valueForKey:#"profilename"];
}
# pragma mark Segue Section
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"resultsSegue"]) {
ResultsVC *result = segue.destinationViewController;
result.profileName = [NSString stringWithFormat:#"%#",selectedProfile];
NSDate *selectedDate = [datePicker date];
result.trialDate = selectedDate;
}
}
You need to initialize selectedProfile to the 1st value in the picker. Do this in viewDidLoad. This way if the user never explicitly picks a value, the selectedProfile will be set to the 1st value by default.
On the app that I am developing I have a list of schedule on a UIPickerView and what I want to do is to enable a button once the 6th item on the list was selected.
I have this code but I it's not working
- (void)pickerView:(UIPickerView *)pickerView didSelectRow: (NSInteger)row inComponent:(NSInteger)component {
// Handle the selection
[trainSchedule setText:[NSString stringWithFormat:#"%#",[schedArray objectAtIndex:[pickerView selectedRowInComponent:0]]]];
if ([schedArray objectAtIndex:[schedArray objectAtIndex:[pickerView selectedRowInComponent:6]]]) { sendTrainRequest.enabled = YES; } else { sendTrainRequest.enabled = NO; }
}
I have this warning also...
Incompatible pointer to integer conversion sending 'id' to parameter of type 'NSUInteger' (aka 'unsigned int
How will a able to do what I want to happen?
I think you're looking for a UIPickerViewDelegate method called pickerView:didSelectRow:inComponent: documented here
I think the problem is in your if statement. If I am parsing what you are trying to say correctly, you want sendTrainRequest.enabled to be set to YES if the sixth item in the picker is selected. Your if statement now is confusing, and the warning is because you are sending on object to the objectAtIndex method of schedArray, when you should be sending an integer. Try this:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow: (NSInteger)row inComponent:(NSInteger)component {
// Handle the selection
[trainSchedule setText:[NSString stringWithFormat:#"%#",[schedArray objectAtIndex:[pickerView selectedRowInComponent:0]]]];
if ([pickerView selectedRowInComponent:0] == 5)
{ sendTrainRequest.enabled = YES; }
else
{ sendTrainRequest.enabled = NO; }
}
Note that the hard-coded 5 in this snippet will evaluate to the sixth item in the picker view, since it is zero-referenced.