As beginner in iOS Developing I struggle with specific implementation ofUIPickerView.
I already know how to createUIPickerView with specific data.
My goal is a bit complicated though - I would like this PickerView to print me selected value. For example - like in simple currency calculator - I pick EUR currency and I have value "4.30" printed out.
FYI - I need to pass this value to another ViewController just to be multiplied.
Any help will be appreciated!
Here's sample code - for now I am still trying to understand what should I do here
#interface SecondViewController ()
{
NSArray *currency;
}
#property NSArray *currency;
#end
#implementation SecondViewController
#synthesize currencyValue;
#synthesize currency;
- (IBAction)Back:(id)sender {
[self dismissViewControllerAnimated:NO completion:NULL];
}
- (NSInteger) numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
- (NSInteger) pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return [self.currency count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:
(NSInteger)component {
return self.currency[row];
}
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
[currencyValue setText:[NSString stringWithFormat:#"Exchange rate of currency : %#",[currency objectAtIndex:row]]];
}
-(IBAction)currencyValue:(id)sender {
}
- (void)viewDidLoad {
[super viewDidLoad];
self.currency = #[#"EUR", #"PLN", #"CFH", #"DKK", #"SEK", #"NOK"];
In UIPickerViewDelegate you can set the rows' titles with pickerView:titleForRow:forComponent: as described in the documentation.
The UIPickerView's selectedRowInComponent: will return you the current selected row: use the previous data source with this index to retrieve the current selected title.
Related
Okay, I need a picker so that a user can select from a list of predefined options. Can someone give me the easy, simplified version of how to populate a picker view from an array of NSStrings? Then, how do I read that value from the picker? I'm noticing that things like nameOfPicker.value and nameOfPicker.text do not work here.
Thank you!
I have already read the following documents and I don't really understand what they are getting at.
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/UIKitUICatalog/UIPickerView.html
https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/DelegatesandDataSources/DelegatesandDataSources.html#//apple_ref/doc/uid/TP40010810-CH11
It is quite similar to how you populate data in a UITableView, by setting datasource and delegate.
1. First step is to set the delegate of the picker view. In .m file you set your datasource and delegate
#interface YourViewController () <UIPickerViewDataSource, UIPickerViewDelegate>
{
}
#property (strong, nonatomic) UIPickerView *yourPickerView;
2. Assign the datasource and delegate
self.yourPickerView.delegate = self;
self.yourPickerView.datasource = self;
3. Implement datasource and delegate
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return self.yourArrayofStrings.count;
}
//The title that should be shown in picker view
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *yourTitle = [self.yourArrayofStrings objectAtIndex:row]
return yourTitle;
}
//This is called when Picker view value is selected
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSLog #(#"Selected row = %#",[self.yourArrayofStrings objectAtIndex:row]);
}
I'm currently working on my first "big" project. The project is a simpel converter for different currencies. I wonder if it is possible to in some way invert the two arrays. I don't know how I should implement the if statement. Becouse if i put it in the title for row method i'm will probably get the control may reach non-void error message. I may explain this pretty bad but i just started programming.
if(!reverse) { // do nothing } else {
// swap the two pickerviews
}
//Toggle reverse on/off <->
- (IBAction)Reverse:(id)sender {
reverse = (reverse+1)%2;
NSLog(#"%d",reverse);
}
//what title for row
-(NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
if (component == 0) {
return [Datarray objectAtIndex:row];
}
return [Datarray2 objectAtIndex:row];
}
I see what you're trying to do. Instead of having two or multiple PickerViews. Just change the DataSource and reload the PickerView. if you only have two currencies just use a flag, otherwise create a NS_ENUM to identify which array the PickerView DataSource should use and in the DataSource methods like, pickerView:titleForRow:forComponent: use a switch case of if-else statements to identify the correct dataSource array.
// .h file
typedef NS_ENUM (NSInteger, CURRENCY_TYPE) {
CURRENCY_TYPE_US,
CURRENCY_TYPE_DK
};
#property (nonatomic, strong) NSArray *dataArrayUS; // In this example, these arrays contains NSStrings
#property (nonatomic, strong) NSArray *dataArrayDK;
#property (nonatomic) CURRENCY_TYPE currencyType;
// .m file
-(NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
switch (self.currencyType) {
case CURRENCY_TYPE_US:
return self.dataArrayUS[row];
break;
case CURRENCY_TYPE_DK:
return self.dataArrayDK[row];
break;
}
}
- (IBAction)currencyChangingAction:(id)sender
{
// Add some logic that changes to the self.currencyType to the correct currency.
self.currencyType = CURRENCY_TYPE_US; // or _DK
// And Reload Picker
}
EDITED:
Is this what you want? - This will only work if you have two Arrays though.
//what title for row
- (NSString *) pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return (component == 0) ? [Datarray objectAtIndex:row] : [Datarray2 objectAtIndex:row];
}
I am trying to save the selection in a UIPickerView as a string, but I seem to be losing the value after I dismiss the view. How can I retain this value?
.m file
/*********************************/
#pragma mark -
#pragma mark PickerView DataSource
//Below are the functions for the UIPicker:
- (NSInteger)numberOfComponentsInPickerView:
(UIPickerView *)pickerView
{
return 1;
}
//count of categories array denotes how many elements the picker will have
- (NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component
{
return arrCategorySelection.count;
}
//return the corresponding caregory
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return arrCategorySelection[row];
}
/*********************************/
#pragma mark -
#pragma mark PickerView Delegate
//Delegate method for the category picker
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
//trying to save the value as a string
selectedCategory = [arrCategorySelection objectAtIndex:row];
}
.h
#property (nonatomic, retain) NSString *selectedCategory;
A property is tied directly to the controller that it is declared in. To use the property, you need to access it before the controller is dismissed, normally with a delegate call. Apple has lots of example code on how to do this. Below is a summary.
Let's say MasterView is presenting PickerView. Normally, you want to do this with a segue.
[self performSegueWithIdentifier:#"Present PickerView" sender:nil];
In PickerView.h you declare a protocol before the #interface portion:
#protocol PickerViewDelegate <NSObject>
-(void)itemSelected:(NSString*)item;
#end
Then in the #interface portion, you declare a delegate property
#property(weak)id<PickerViewDelegate> delegate;
In MasterView, you need to populate this delegate in your prepareForSegue method
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"Present PickerView"]) {
PickerView *controller = segue.destinationViewController;
controller.delegate = self;
}
}
You also need to implement the delegate method (remember, it is best practice for the MasterView to both present and dismiss PickerView)
-(void)itemSelected:(NSString*)item {
// do something with item
[self dismissViewControllerAnimated:YES completion:nil];
// depending on the presentation, you may need this instead
// [self.navigationController popViewControllerAnimated:YES];
}
Now in PickerView.m, establish some way for the user to say he is done with his selection, say a tap of the save button on the upper right that calls this method:
-(IBAction)saveButtonTapped:(id)sender {
if (self.delegate && [self.delegate respondsToSelector:#selector(itemSelected:)]) {
[self.delegate itemSelected:self.selectedCategory];
}
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.
I have found similar questions here and here. I have tried the answers to these and other questions found on stackoverflow and Apple's developer forums, with no luck.
I created a fresh project to test this, and it works fine in that new project. I am iteratively removing differences between my new test project and the one exhibiting this issue. Any pointers would be most helpful.
I have a UIPickerView connected to my view controller. I want to initialize the UIPickerView to the last value selected by the user. However if this row is the last row in the picker, it shows the second-to-last row selected in the UI instead.
Meanwhile, logging shows the correct row index selected in the UIPickerView object instance.
Selecting any row besides the last row in the picker works fine.
I have tried calling the selectRow:inComponent:animated method from viewDidLoad, viewWillAppear, and viewDidAppear - none of these make any difference. I have also tried calling reloadAllComponents in various orders relative to row selection and data initialization - again, no difference.
Some code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSParameterAssert(self.pickerView);
// Set pickerView data
self.pickerOptions = #[#"zero", #"one", #"two", #"three", #"four"];
// Picker View config
self.pickerView.dataSource = self;
self.pickerView.delegate = self;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSInteger selectedIndex = ([self.pickerOptions count] -1);
NSLog(#"About to select row: %d", selectedIndex);
[self.pickerView selectRow:selectedIndex inComponent:0 animated:NO];
NSLog(#"Selected value is %d", [self.pickerView selectedRowInComponent:0]);
}
#pragma mark UIPickerViewDataSource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
NSInteger numRows = [self.pickerOptions count];
NSLog(#"numRows: %d", numRows);
return numRows;
}
#pragma mark UIPickerViewDelegate
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
NSString *rowTitle = [self.pickerOptions objectAtIndex:(NSUInteger)row];
return rowTitle;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
NSString *value = [self.pickerOptions objectAtIndex:(NSUInteger)row];
NSLog(#"User selected value: %#", value);
NSLog(#"index: %d", row);
}
Log output:
-[CCSelectorViewController viewDidAppear:] About to select row index: 4
-[CCSelectorViewController pickerView:numberOfRowsInComponent:] numRows: 5
-[CCSelectorViewController viewDidAppear:] Selected row index is 4
Here is the screenshot of the wrong row being selected:
http://imgur.com/FVvu9RA
This is using iOS6, XCode 4.6.1.
Any ideas?