UIPickerView with Multiline UILabel
I'm currently working on a program that populates a picker view dynamically from my Core Data set up. I have everything working data-wise but the problem i'm running into now is formatting on my labels.
The picker is presented with it's own toolbar in an acti开发者_StackOverflow社区onsheet with a button on the right side of the toolbar. It's initial state is with 2 dials visible. when the button is pressed it changes to 3 dials.
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
UILabel *pickerLabel = (UILabel *)view;
CGSize limitSize = CGSizeMake(100.0f, 45.0f);
CGSize textSize;
CGRect labelRect;
NSString *title = @"";
switch (numberOfComponents){
case 2:
{
...gets strings from fetched data (varying length from 4 to 20+)
title = someString
}
case 3:
{
...same as above but for the second set of data.
title = someString
}
}
textSize = [title sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:limitSize lineBreakMode:UILineBreakModeWordWrap];
labelRect = CGRectMake(0, 0, textSize.width, textSize.height);
NSLog(@"length:%i title:%@",[title length],title);
NSLog(@"h:%f w:%f",textSize.height,textSize.width);
if (pickerLabel == nil)
{
pickerLabel = [[[UILabel alloc] initWithFrame:labelRect] autorelease];
[pickerLabel setFont:[UIFont systemFontOfSize:14]];
[pickerLabel setBackgroundColor:[UIColor clearColor]];
[pickerLabel setLineBreakMode:UILineBreakModeWordWrap];
[pickerLabel setTextAlignment:UITextAlignmentCenter];
[pickerLabel setNumberOfLines:2];
}
[pickerLabel setText:title];
return pickerLabel;
}
i've manually set the row height at 32.0f. I'm getting very strange results in that some of the Labels in the second component are working perfectly. but others are not wrapping at all, and some are just showing as blank space.
ie: Brussels sprout wraps fine (right component). but Milk and Cream doesn't display (only milk is visible) vegetables doesn't appear at all. Where am i going wrong in my code?
I managed to get it behaving nicely. I changed the last part by removing
textSize = [title sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:limitSize lineBreakMode:UILineBreakModeWordWrap];
and i set the frame manually
labelRect = CGRectMake(0,0,100.0,36.0);
not sure why this worked while the dynamically sized didn't.
Here's a version for swift.
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView {
var label : UILabel
if view == nil {
label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: UIFont.systemFontOfSize(UIFont.systemFontSize()).lineHeight * 2 * UIScreen.mainScreen().scale))
label.textAlignment = NSTextAlignment.Center
label.numberOfLines = 2
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
label.autoresizingMask = UIViewAutoresizing.FlexibleWidth
} else {
label = view as UILabel
}
label.text = line1 + "\n" + line2
return label;
}
func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return UIFont.systemFontOfSize(UIFont.systemFontSize()).lineHeight * 2 * UIScreen.mainScreen().scale
}
I corrected your code, in order to let the label width to fit the picker width. I used the koushi approach. It works very well now. See my code here appended.
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
//assegna i nomi alle caselle del picker e assegna anche la dimensione del font e del rettangolo che contiene le scritte
UILabel *pickerLabel = (UILabel *)view;
CGRect labelRect;
NSString *title=@"";
switch (numberOfComponents){
case 2:
{
...gets strings from fetched data (varying length from 4 to 20+)
title = someString
}
case 3:
{
...same as above but for the second set of data.
title = someString
}
}
CGFloat labelWidth=pickerView.frame.size.width-50;
labelRect = CGRectMake( 0,0,labelWidth,45.0);
if (pickerLabel == nil)
{
pickerLabel = [[UILabel alloc] initWithFrame:labelRect];
[pickerLabel setFont:[UIFont systemFontOfSize:16]];
[pickerLabel setBackgroundColor:[UIColor clearColor]];
[pickerLabel setNumberOfLines:2];
}
[pickerLabel setText:title];
return pickerLabel;
}
About your original code: i think that to have a picker with elements of different rect size is not good for appeareance (user experience) matter. I suspect that the different labels rect size is gnerating the problem in your code. If the text that you want to display can be bigger than the defined rect, i think that you should use different app structure approach.
NOTE: in my app i use the picker tag property to identify which picker was selected, because i have more than one picker in my view. For this reason i replaced the "switch" statement in your code with the following code:
if (pickerView.tag==1)
title= globalSubcategoryArray[row];
else
title= globalAreasName[row];
and obviously i added also:
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (pickerView.tag==1)
return globalSubcategoryArray.count;
else
return globalAreasName.count;
}
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
if (pickerView.tag==1){
self.subcategoryTextview.text = globalSubcategoryArray[row];
globalSelectedSubcategoryIndex=row;
[self.subcategoryTextview resignFirstResponder];
}else{
self.areaTextview.text= globalAreasName[row];
globalSelectedAreaIndex=row;
[self.areaTextview resignFirstResponder];
}
}
精彩评论