当前位置:  开发笔记 > IOS > 正文

修复了UIPickerView选择栏中的标签

如何解决《修复了UIPickerView选择栏中的标签》经验,为你挑选了3个好方法。

在时钟应用程序,计时器屏幕显示了一个选择器(可能是一个UIPickerUIDatePickerModeCountDownTimer模式),在选择栏一些文本("小时",并在这种情况下,"分钟").

(编辑)请注意,这些标签是固定的:当拣选轮滚动时,它们不会移动.

有没有办法在标准UIPickerView组件的选择栏中显示这样的固定标签?

我没有找到任何有助于此的API.建议是添加一个UILabel作为选择器的子视图,但这不起作用.


回答

我按照Ed Marty的建议(下面回答),它的确有效!不完美,但它应该骗人.作为参考,这是我的实现,随意让它变得更好......

- (void)viewDidLoad {
    // Add pickerView
    self.pickerView = [[UIPickerView alloc] initWithFrame:CGRectZero];
    [pickerView release];
    CGSize pickerSize = [pickerView sizeThatFits:CGSizeZero];
    CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
    #define toolbarHeight           40.0
    CGFloat pickerTop = screenRect.size.height - toolbarHeight - pickerSize.height;
    CGRect pickerRect = CGRectMake(0.0, pickerTop, pickerSize.width, pickerSize.height);
    pickerView.frame = pickerRect;

    // Add label on top of pickerView
    CGFloat top = pickerTop + 2;
    CGFloat height = pickerSize.height - 2;
    [self addPickerLabel:@"x" rightX:123.0 top:top height:height];
    [self addPickerLabel:@"y" rightX:183.0 top:top height:height];
    //...
}

- (void)addPickerLabel:(NSString *)labelString rightX:(CGFloat)rightX top:(CGFloat)top height:(CGFloat)height {
#define PICKER_LABEL_FONT_SIZE 18
#define PICKER_LABEL_ALPHA 0.7
    UIFont *font = [UIFont boldSystemFontOfSize:PICKER_LABEL_FONT_SIZE];
    CGFloat x = rightX - [labelString sizeWithFont:font].width;

    // White label 1 pixel below, to simulate embossing.
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(x, top + 1, rightX, height)];
    label.text = labelString;
    label.font = font;
    label.textColor = [UIColor whiteColor];
    label.backgroundColor = [UIColor clearColor];
    label.opaque = NO;
    label.alpha = PICKER_LABEL_ALPHA;
    [self.view addSubview:label];
    [label release];

    // Actual label.
    label = [[UILabel alloc] initWithFrame:CGRectMake(x, top, rightX, height)];
    label.text = labelString;
    label.font = font;
    label.backgroundColor = [UIColor clearColor];
    label.opaque = NO;
    label.alpha = PICKER_LABEL_ALPHA;
    [self.view addSubview:label];
    [label release];
}

dizy.. 13

创建选择器,创建带阴影的标签,并将其推送到selectionIndicator视图下方的选择器子视图.

它看起来像这样

UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(135, 93, 80, 30)] autorelease];
label.text = @"Label";
label.font = [UIFont boldSystemFontOfSize:20];
label.backgroundColor = [UIColor clearColor];
label.shadowColor = [UIColor whiteColor];
label.shadowOffset = CGSizeMake (0,1);
[picker insertSubview:label aboveSubview:[picker.subviews objectAtIndex:5]]; 
//When you have multiple components (sections)...
//you will need to find which subview you need to actually get under
//so experiment with that 'objectAtIndex:5'
//
//you can do something like the following to find the view to get on top of
// define @class UIPickerTable;
// NSMutableArray *tables = [[NSMutableArray alloc] init];
// for (id i in picker.subviews) if([i isKindOfClass:[UIPickerTable class]]) [tables addObject:i];
// etc...

- 支付它



1> dizy..:

创建选择器,创建带阴影的标签,并将其推送到selectionIndicator视图下方的选择器子视图.

它看起来像这样

UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(135, 93, 80, 30)] autorelease];
label.text = @"Label";
label.font = [UIFont boldSystemFontOfSize:20];
label.backgroundColor = [UIColor clearColor];
label.shadowColor = [UIColor whiteColor];
label.shadowOffset = CGSizeMake (0,1);
[picker insertSubview:label aboveSubview:[picker.subviews objectAtIndex:5]]; 
//When you have multiple components (sections)...
//you will need to find which subview you need to actually get under
//so experiment with that 'objectAtIndex:5'
//
//you can do something like the following to find the view to get on top of
// define @class UIPickerTable;
// NSMutableArray *tables = [[NSMutableArray alloc] init];
// for (id i in picker.subviews) if([i isKindOfClass:[UIPickerTable class]]) [tables addObject:i];
// etc...

- 支付它


对于任何想知道为什么这种方法在iOS 5+中不起作用的人:你仍然可以在PickerView中添加一个Label,但它将保留在后台.方法"insertSubview:aboveSubview:"存在,但无论选择栏是否已激活或您拥有多少组件,子视图始终为空.解决方案是(如显示@squelart的问题)使用视图,将PickerView嵌入为子视图并向视图添加标签,定位良好.

2> Andrey Taran..:

UIPickerView几年前我把dizy的答案变成了一个类别.刚刚验证它仍适用于iOS SDK 4.3,并在此处发布.它允许您添加标签(XX小时)并对此标签进行动画更改(例如1小时 - > 3小时)UIDatePicker.

// UIPickerView_SelectionBarLabelSupport.h
//
// This file adds a new API to UIPickerView that allows to easily recreate
// the look and feel of UIDatePicker labeled components.
//
// Copyright (c) 2009, Andrey Tarantsov 
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.


#import 


// useful constants for your font size-related code
#define kPickerViewDefaultTitleFontSize 20.0f
#define kDatePickerTitleFontSize 25.0f
#define kDatePickerLabelFontSize 21.0f


@interface UIPickerView (SelectionBarLabelSupport)

// The primary API to add a label to the given component.
// If you want to match the look of UIDatePicker, use 21pt as pointSize and 25pt as the font size of your content views (titlePointSize).
// (Note that UIPickerView defaults to 20pt items, so you need to use custom views. See a helper method below.)
// Repeated calls will change the label with an animation effect similar to UIDatePicker's one.
//
// To call this method on viewDidLoad, please call [pickerView layoutSubviews] first so that all subviews
// get created.
- (void)addLabel:(NSString *)label ofSize:(CGFloat)pointSize toComponent:(NSInteger)component leftAlignedAt:(CGFloat)offset baselineAlignedWithFontOfSize:(CGFloat)titlePointSize;

// A helper method for your delegate's "pickerView:viewForRow:forComponent:reusingView:".
// Creates a propertly positioned right-aligned label of the given size, and also handles reuse.
// The actual UILabel is a child of the returned view, use [returnedView viewWithTag:1] to retrieve the label.
- (UIView *)viewForShadedLabelWithText:(NSString *)label ofSize:(CGFloat)pointSize forComponent:(NSInteger)component rightAlignedAt:(CGFloat)offset reusingView:(UIView *)view;

// Creates a shaded label of the given size, looking similar to the labels used by UIPickerView/UIDatePicker.
- (UILabel *)shadedLabelWithText:(NSString *)label ofSize:(CGFloat)pointSize;

@end

并实施:

// UIPickerView_SelectionBarLabelSupport.m
//
// This file adds a new API to UIPickerView that allows to easily recreate
// the look and feel of UIDatePicker labeled components.
//
// Copyright (c) 2009, Andrey Tarantsov 
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#import "UIPickerView_SelectionBarLabelSupport.h"


// used to find existing component labels among UIPicker's children
#define kMagicTag 89464534
// a private UIKit implementation detail, but we do degrade gracefully in case it stops working
#define kSelectionBarClassName @"_UIPickerViewSelectionBar"

// used to sort per-component selection bars in a left-to-right order
static NSInteger compareViews(UIView *a, UIView *b, void *context) {
    CGFloat ax = a.frame.origin.x, bx = b.frame.origin.x;
    if (ax < bx)
        return -1;
    else if (ax > bx)
        return 1;
    else
        return 0;
}


@implementation UIPickerView (SelectionBarLabelSupport)

- (UILabel *)shadedLabelWithText:(NSString *)label ofSize:(CGFloat)pointSize {
    UIFont *font = [UIFont boldSystemFontOfSize:pointSize];
    CGSize size = [label sizeWithFont:font];
    UILabel *labelView = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)] autorelease];
    labelView.font = font;
    labelView.adjustsFontSizeToFitWidth = NO;
    labelView.shadowOffset = CGSizeMake(1, 1);
    labelView.textColor = [UIColor blackColor];
    labelView.shadowColor = [UIColor whiteColor];
    labelView.opaque = NO;
    labelView.backgroundColor = [UIColor clearColor];
    labelView.text = label;
    labelView.userInteractionEnabled = NO;
    return labelView;
}

- (UIView *)viewForShadedLabelWithText:(NSString *)title ofSize:(CGFloat)pointSize forComponent:(NSInteger)component rightAlignedAt:(CGFloat)offset reusingView:(UIView *)view {
    UILabel *label;
    UIView *wrapper;
    if (view != nil) {
        wrapper = view;
        label = (UILabel *)[wrapper viewWithTag:1];
    } else {
        CGFloat width = [self.delegate pickerView:self widthForComponent:component];

        label = [self shadedLabelWithText:title ofSize:pointSize];
        CGSize size = label.frame.size;
        label.frame = CGRectMake(0, 0, offset, size.height);
        label.tag = 1;
        label.textAlignment = UITextAlignmentRight;
        label.autoresizingMask = UIViewAutoresizingFlexibleHeight;

        wrapper = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, width, size.height)] autorelease];
        wrapper.autoresizesSubviews = NO;
        wrapper.userInteractionEnabled = NO;
        [wrapper addSubview:label];
    }
    label.text = title;
    return wrapper;
}

- (void)addLabel:(NSString *)label ofSize:(CGFloat)pointSize toComponent:(NSInteger)component leftAlignedAt:(CGFloat)offset baselineAlignedWithFontOfSize:(CGFloat)titlePointSize {
    NSParameterAssert(component < [self numberOfComponents]);

    NSInteger tag = kMagicTag + component;
    UILabel *oldLabel = (UILabel *) [self viewWithTag:tag];
    if (oldLabel != nil && [oldLabel.text isEqualToString:label])
        return;

    NSInteger n = [self numberOfComponents];
    CGFloat total = 0.0;
    for (int c = 0; c < component; c++)
        offset += [self.delegate pickerView:self widthForComponent:c];
    for (int c = 0; c < n; c++)
        total += [self.delegate pickerView:self widthForComponent:c];
    offset += (self.bounds.size.width - total) / 2;

    offset += 2 * component; // internal UIPicker metrics, measured on a screenshot
    offset += 4; // add a gap

    CGFloat baselineHeight = [@"X" sizeWithFont:[UIFont boldSystemFontOfSize:titlePointSize]].height;
    CGFloat labelHeight = [@"X" sizeWithFont:[UIFont boldSystemFontOfSize:pointSize]].height;

    UILabel *labelView = [self shadedLabelWithText:label ofSize:pointSize];
    labelView.frame = CGRectMake(offset,
                                 (self.bounds.size.height - baselineHeight) / 2 + (baselineHeight - labelHeight) - 1,
                                 labelView.frame.size.width,
                                 labelView.frame.size.height);
    labelView.tag = tag;

    UIView *selectionBarView = nil;
    NSMutableArray *selectionBars = [NSMutableArray array];
    for (UIView *subview in self.subviews) {
        if ([[[subview class] description] isEqualToString:kSelectionBarClassName])
            [selectionBars addObject:subview];
    }
    if ([selectionBars count] == n) {
        [selectionBars sortUsingFunction:compareViews context:NULL];
        selectionBarView = [selectionBars objectAtIndex:component];
    }
    if (oldLabel != nil) {
        [UIView beginAnimations:nil context:oldLabel];
        [UIView setAnimationDuration:0.25];
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDidStopSelector:@selector(YS_barLabelHideAnimationDidStop:finished:context:)];
        oldLabel.alpha = 0.0f;
        [UIView commitAnimations];
    }
    // if the selection bar hack stops working, degrade to using 60% alpha
    CGFloat normalAlpha = (selectionBarView == nil ? 0.6f : 1.0f);
    if (selectionBarView != nil)
        [self insertSubview:labelView aboveSubview:selectionBarView];
    else
        [self addSubview:labelView];
    if (oldLabel != nil) {
        labelView.alpha = 0.0f;
        [UIView beginAnimations:nil context:oldLabel];
        [UIView setAnimationDuration:0.25];
        [UIView setAnimationDelay:0.25];
        labelView.alpha = normalAlpha;
        [UIView commitAnimations];
    } else {
        labelView.alpha = normalAlpha;
    }
}

- (void)YS_barLabelHideAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(UIView *)oldLabel {
    [oldLabel removeFromSuperview];
}

@end

用法示例(在视图控制器中):

- (void)updateFloorLabel {
    NSInteger floor = [self.pickerView numberOfRowsInComponent:0] - [self.pickerView selectedRowInComponent:0];
    NSString *suffix = @"th";
    if (((floor % 100) / 10) != 1) {
        switch (floor % 10) {
            case 1:  suffix = @"st"; break;
            case 2:  suffix = @"nd"; break;
            case 3:  suffix = @"rd"; break;
        }
    }
    [self.pickerView addLabel:[NSString stringWithFormat:@"%@ Floor", suffix]
                       ofSize:21
                  toComponent:0
                leftAlignedAt:50
baselineAlignedWithFontOfSize:25];    
}

- (void)viewDidLoad {
  ...
  [self.pickerView layoutSubviews];
  [self updateFloorLabel];
  ...
}

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
    NSString *s = [NSString stringWithFormat:@"%d", [pickerView numberOfRowsInComponent:0] - row];
    return [pickerView viewForShadedLabelWithText:s ofSize:25 forComponent:0 rightAlignedAt:46 reusingView:view];
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
    [self updateFloorLabel];
}

请享用!



3> Kun Hu..:

假设我们想要实现一个选择距离的选择器视图,有2列,一列用于距离,一列用于单位,即km.然后我们想要修复第二列.我们可以通过一些委托方法来实现.

- (NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    if (component == 0) {
        return self.distanceItems[row];
    }
    else {
        return @"km";
    }
}

-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    return 2;
}

-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    if (component == 0) {
        return [self.distanceItems count];
    }
    else {
    // when it comes to the second column, only one row.
        return 1;
    }
}

现在我们有了这个: 在此输入图像描述

我想这是最简单的方法.


最初这个解决方案看起来不错,但是:(1)数字和单位之间的距离太大(任何想法如何使它变小?),(2)单位"km"对触摸作出反应并向上/向下移动,而iOS计时器中的单位是固定的(任何想法如何让它仍然?)
推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有