Im using a uiPickerView that haves images instead of strings for the selections, is working ok for showing the images, I got inspiration from the apple UIcatalog example on how to put the images,
Im implementing it programatically no IB,
So the question is, how to change an image according to the selected cell?
i have
* MainVC (my main view controller)
* CustomView (defining picker size)
* CustomPickerDataSource (the data source for the picker :)
in CustomPickerDataSource, send the data for wich row was selected
- (void)pickerView:(UIPickerView *)pickerView didSelectRow: (NSInteger)row inComponent:(NSInteger)component {
// Handle the selection
NSLog(#"seleccionokkkk: %d", row);
[MainVC entro:row];
}
and in my MainVC
+(void) entro: (int) cuca {
NSLog(#"sumbalo :%d", cuca);
}
I get the number of cell selected on my MainVC, which is where I want to show the different images,
but when selecting the image in my +(void) entro: (int) cuca
I get warnings of course as Im setting instance variables with a class method,
so how can I show the image according to which cell number I receive?
Pseudocode:
if image == 0, show image0
Where to put my image showing code?, and how to set the variable for the incoming message?
thanks a lot!
I'd assume you have as many images as you have items in the picker. Put them into an array in the same order as you did in the picker view. Then take the UIImageView that you want to change to the selected picture, and set it to the picture in the array with the given index.
You can do this in your entro: method (which should be an instance method, no reason that it shouldn't or can't be), or you can just go ahead and do it in the pickerView:didSelectRow: method.
You can set images like this:
UIImageView *myImageView;
NSArray *myImageArray;
...
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:
(NSInteger)row inComponent:(NSInteger)component {
[myImageView setImage:[myImageArray objectAtIndex:row]];
}
Related
I'm trying to display a UIPickerView that has the selected row displayed in a unique text color. So the selected row should be displayed in a red font, and all other (unselected) rows are displayed in a black/default font.
I have implemented this:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
UILabel *label = (UILabel*)[pickerView viewForRow:row forComponent:component];
label.textColor = [UIColor redColor];
UILabel *oldLabel = (UILabel*)[pickerView viewForRow:self.previouslySelectedRow forComponent:component];
oldLabel.textColor = [UIColor blackColor];
self.previouslySelectedRow = row;
}
Which works when changing selections flawlessly, but does not do anything for the initial row that is displayed.
I am calling:
[pickerView selectRow:initialRow inComponent:0 animated:NO];
After I display the UIPickerView, but I have realized that this does not result in didSelectRow being called (that only happens when the user changes the selection manually).
I have tried to set the UILabel textColor value myself - something like:
UILabel *label = (UILabel*)[pickerView viewForRow:startingRow forComponent:0];
label.textColor = [UIColor redColor];
But unfortunately that results in nothing happening. I call this AFTER displaying the pickerview.
Is there some easy way of doing this? Am I missing something? Thanks for any/all help!
Zach
I had this issue myself just recently working in Xamarin Monotouch (.net for iOS) I couldnt find a "clean" fix, but I made a very small hack which seems to work fine thus far. I will provide my solution in C#, apologies as I can read ObjC however I would only embarrass myself by trying to write it. You should get the idea pretty easy I hope.
Override UIPickerViewDelegate. Add an int field, with which we will populate the index of the dataitem we need to select upon the picker controls first use.
protected class PickerDelegate : UIPickerViewDelegate
{
// Contruction...overrides etc
public int SelectIndexOnLoad { get; set; }
}
Now in the area of code where you load/instantiate the pickercontrol (ViewDidLoad etc) locate the index of the datasource, which contains the data you want to display/select first in the picker.
// First get the index value of the current set of data you
// want to display, assuming here I have a list of items as my
// picker datasource
var x = this.items.IndexOf(data_value_to_display);
// Then assign it to our PickerDelegate.SelectIndexOnLoad
this.myPickerDelegate.SelectIndexOnLoad = x;
this.myPickerView.selectRow(x, 0, true);
// Note in Xamarin, the objc delegate call selectRow() is mapped to Select()
In the pickerdelegates viewForRow() call (Xamarin objC call is mapped to GetView()) we compare the PickerDelegate.SelectIndexOnLoad to the passed row variable, and decide on UI values
public override UIView viewForRow(UIPickerView pickerView, int row, int component, UIView view)
{
// Forget reusing the passed view
// there is a bug in ios 7,8,9 which ensures its ALWAYS null, nice Apple!
var view1 = new UILabel(predefined_rect_size);
if (this.SelectIndexOnLoad == row)
{
view1.BackgroundColor = UIColor.Pink;
}
else
{
view1.BackgroundColor = UIColor.White;
}
// Optionally reset the SelectIndexOnLoad so that as the user moves
// the picker (viewForRow is called constantly for redraws)
// it goes back to normal color once moved.
// If you want to keep it colored so the user knows the old original value
// Simply omit this line
this.SelectIndexOnLoad = row;
return view1;
}
This works fine, however, I dont like it. Im hoping an ObjC guru will enlighten us, but until then, this hack does the trick.
Kindest Regards
3 things to check
1. where is ‘pickerView.selectRow’ called ?
it shouldn’t be called in viewDidLoad or viewWillAppear
Instead place them in viewDidLayoutSubviews (prefer) or viewDidappear
to give some time for
pickerView(_ pickerView: UIPickerView, viewForRow row: Int ..)
to return all the UIView
(for iphone6 and later, if you place it in viewDidLayoutSubviews,
add 'self.yourPIckerView.layoutIfNeeded()' before selecting row)
2. didSelectRow should be called manually
‘pickerView.selectRow’ doesn’t automatically trigger didSelectRow.
After the line, place this to manually trigger it.
self.pickerView(self.yourPickerView, didSelectRow: row, inComponent: comp)
3. animated parameter should be ‘false’
‘pickerView.selectRow(row, inComponent: comp, animated: false)’
If it’s ’true’, it will take some time for the picker to eventually get to the row you manually selected
and color change could be ignored by the delay
UPDATE: I solved this using a workaround with custom views on the picker instead of strings. Still really curious why this was happening though.
Only two of our users reported this bug and so far and it's pretty strange. I am unable to replicate it on the sim or any of our test devices. Basically, for this one user, a UIPickerView displays everything very dark. Here is an image of how it's supposed to look:
Here is what it looks like on the user's phone who reported the bug:
At first glance, the bugged pickerview appears black. But if you turn up your screen brightness all the way and look really closely, you'll see that the picker view is actually there (also, the textview wouldn't have populated if it wasn't there). The picker view is displaying with an almost black background and black text.
I'm not doing anything tricky or messing with the frame of the picker view to create it or manage it:
- (UIPickerView *)pickerView
{
if (!_pickerView) {
_pickerView = [[UIPickerView alloc] init];
_pickerView.delegate = self;
_pickerView.dataSource = self;
}
return _pickerView;
}
I'm not using any custom views, just assigning strings in pickerView:titleForRow:forComponent
#pragma mark picker datasource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return self.rowTitlesForComponent.count;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return ((NSArray *)self.rowTitlesForComponent[component]).count;
}
#pragma mark - picker delegate
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
return self.rowTitlesForComponent[component][row];
}
Here's my hunch: I'm assigning the picker view to the input view of the textfield so that it pops up as a "keyboard":
self.textField.inputView = self.pickerView;
The textview is a subview of a custom tableview cell. This custom tableview cell is a subclass of another type of tableview cell that contains textviews which pop up ordinary uikeyboards. In this superclass, I'm assigning the keyboard appearance to UIKeyboardAppearanceDark. The odd thing is that this is affecting <1% of our users, so perhaps it's some off combination of OS version and code or something?
I tried messing around with all the accessibility settings on the phone, but could not replicate.
Do you have any idea what might cause this?
The UIPickerView class has a method selectedRowInComponent that returns the selected row for the component. That may or may not be the item that is in the center of the picker view. What I'd like is to be able to tell what index of the pickerView data is currently being displayed (not selected).
To illustrate the difference, if you tap a value in the UIPickerView dial, the row for that value seems to always be returned in selectedRowInComponent. However, if the user scrolls the picker through several values and then lifts the finger, selectedRowInComponent is not updated, or it is updated to the value that just scrolled off.
Is there anyway to determine where the picker component is actually dialed?
The value is always available in method pickerView:didSelectRow:inComponent: but I would like to query it in method pickerView:titleForRow:forComponent:
Why? Because while the UIPickerView is being scrolled selectedRowInComponent is not being called. If for some reason I get to the end of the data and need to add more, I need to do it in a method that is being called. That would seem to be pickerView:titleForRow:forComponent:, which is called for every row.
I know this question is a bit old, but by answer it I could help someone else.
I think I found a solution to this problem you had.
Solution
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
// Passing the row being viewed to a function that does something with it.
[self handleRowBeingViewed:[pickerView selectedRowInComponent:component]];
}
- (void)pickerView:(UIPickerView *)pickerView
didSelectRow:(NSInteger)row
inComponent:(NSInteger)component
{
// Passing the row being viewed to a function that does something with it.
[self handleRowBeingViewed:[pickerView selectedRowInComponent:component]];
}
/**
* It receives, in input 'rowBeingViewed', the row being viewed by the user in the center of the picker view, and use it to XYZW...
*
*
* #param rowBeingViewed Row currently being viewed by the user in the center of the picker view.
* #return
*/
- (void) handleRowBeingViewed:(NSInteger)rowBeingViewed
{
// Printing for debugging.
NSLog(#"String Being Viewed: %#", pickerViewArray[rowBeingViewed]);
// DO YOUR STUFF HERE
// ...
}
Explanation
The UIPickerView allows you to know which row is selected (or viewed in the center, which I think is the same) at any time by using the method selectedRowInComponent.
If you use that method selectedRowInComponent inside the delegate's method pickerView:titleForRow:forComponent, you can know which row is being viewed in the center every time a new title is being "printed" to the user in the picker view.
Sometimes, if in the Picker View you scroll only 1 or 2 rows, the delegate's method pickerView:titleForRow:forComponent does not get called and you won't know which row is being viewed in the center. To solve that, also use the same method selectedRowInComponent inside the delegate's method pickerView:didSelectRow:inComponent:.
Hope this helps someone.
I have 2 pickerviews on screen. Both populate rotate and taps return
correct and expected results. They are distinguished by the TAG
property using the "if/switch" statement in the necessary delegate
methods.
What I'd like is forpicker1 to change the selected row in picker2
dynamically during runtime as the user interacts.
E.g.
picker1 has values 1 to 10
Picker2 has values red, blue, green, purple etc
User taps row with value 2 in picker1 and automatically picker2
rotates/animates to predetermined row say purple in this case, user then taps picker1 again row 5 and again picker2 is animated/rotated to another predetermined row, and so on
What works:
The two pickers are created in viewDidLoad and
[picker2 selectRow:row inComponent:component animated:NO];
works with no issues, but only first time round at initial view load.
Its does not change the selected row if called from
What does NOT work is calls to:
[picker2 selectRow:row inComponent:component animated:NO]; from other (delegate) methods, even if I call:
[self.thePicker reloadAllComponents];
Does this work at all, or is it not supposed to do this? I'm new to this forum, so apologies in advance if I'm being thick! I have trolled look for the answer though
Cheers
I have multiple textfields on my view, and each time a textfield is taped a picker appears(the picker was made by code). This works fine for the first textfield, I can also select a row and the textfield receives it. But when I tap the second one and the picker appears, the row selected appears on the first textfield. I know I can use "tag" to distinguish them, but then I get stuck...it doesn´t work.
Does anyone have/has this problem? What method do I have to change?
try creating one picker for each textfield pick1,pick2.......then in the
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
method u check
if( pickerview==pick1)
{
text1.text= (pick1 value at row);
}
else if(pickerview==pick2)
{
text2.text= (pick2 value at row);
}