2012-06-12 52 views
20

我正在制作一个计时器应用程序,需要显示小时,分钟和秒的用户。我尝试使用UIDatePicker,但它只显示小时和分钟作为选择。不是几秒钟。在网上做了一些研究之后,我发现没有办法在UIDatePicker中获得秒数,我必须从头开始编写我自己的UIPickerViewUIPickerView看起来像UIDatePicker,但与秒

所以我的问题是,是否有这样的示例代码,即有人写了CustomUIPickerView几小时,分钟和秒,我可以将其纳入我的项目? UIDatePicker有一个很好的覆盖时间&分钟文本,保持放在用户旋转拨号。如果有人在他们的自定义选取器中添加了它,那将会很好。如果我不需要,我宁愿不要从头开始编写自定义UIPickerView。谢谢。

+0

使用带有3个组件的uiPickerView,每个组件都有数组。 HourArray从(1到12)。 MinutesArray(1到60)。秒数组(1到60) –

+0

@safecase。我从技术上理解它是如何完成的。我所要求的是,如果有人想与我分享这段代码,而不是我从零开始写它 –

+3

@EmilioPelaez - 请不要使用“我们”。你不会在这里为整个iOS开发社区说话。有很多优秀的开发人员可以愉快地分享知识和代码。如果我最终编写代码,我会在这里与其他社区和任何未来可能感兴趣的人分享,并阅读我的文章 –

回答

40

Alrighty的人,这里是代码获得小时/分钟/秒在您的UIPickerView。您可以添加3个标签并将其置于选取器上。我也附上了一张照片。

如果你喜欢答案,请评价它!好的开发者分享知识并不像一些人所暗示的那样隐藏它玩得开心编码!

enter image description here

在你的头h文件在.m文件把这个

@interface v1AddTableViewController : UITableViewController 
{ 

    IBOutlet UIPickerView *pickerView;  
    NSMutableArray *hoursArray; 
    NSMutableArray *minsArray; 
    NSMutableArray *secsArray; 

    NSTimeInterval interval; 

} 

@property(retain, nonatomic) UIPickerView *pickerView; 
@property(retain, nonatomic) NSMutableArray *hoursArray; 
@property(retain, nonatomic) NSMutableArray *minsArray; 
@property(retain, nonatomic) NSMutableArray *secsArray; 

把这个

@synthesize pickerView; 
@synthesize hoursArray; 
@synthesize minsArray; 
@synthesize secsArray; 
@synthesize interval; 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 


    //initialize arrays 
    hoursArray = [[NSMutableArray alloc] init]; 
    minsArray = [[NSMutableArray alloc] init]; 
    secsArray = [[NSMutableArray alloc] init]; 
    NSString *strVal = [[NSString alloc] init]; 

    for(int i=0; i<61; i++) 
    { 
     strVal = [NSString stringWithFormat:@"%d", i]; 

     //NSLog(@"strVal: %@", strVal); 

     //Create array with 0-12 hours 
     if (i < 13) 
     { 
      [hoursArray addObject:strVal]; 
     } 

     //create arrays with 0-60 secs/mins 
     [minsArray addObject:strVal]; 
     [secsArray addObject:strVal]; 
    } 


    NSLog(@"[hoursArray count]: %d", [hoursArray count]); 
    NSLog(@"[minsArray count]: %d", [minsArray count]); 
    NSLog(@"[secsArray count]: %d", [secsArray count]); 

} 


//Method to define how many columns/dials to show 
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView 
{ 
    return 3; 
} 


// Method to define the numberOfRows in a component using the array. 
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent :(NSInteger)component 
{ 
    if (component==0) 
    { 
     return [hoursArray count]; 
    } 
    else if (component==1) 
    { 
     return [minsArray count]; 
    } 
    else 
    { 
     return [secsArray count]; 
    } 

} 


// Method to show the title of row for a component. 
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component 
{ 

    switch (component) 
    { 
     case 0: 
      return [hoursArray objectAtIndex:row]; 
      break; 
     case 1: 
      return [minsArray objectAtIndex:row]; 
      break; 
     case 2: 
      return [secsArray objectAtIndex:row]; 
      break;  
    } 
    return nil; 
} 


-(IBAction)calculateTimeFromPicker 
{ 

    NSString *hoursStr = [NSString stringWithFormat:@"%@",[hoursArray objectAtIndex:[pickerView selectedRowInComponent:0]]]; 

    NSString *minsStr = [NSString stringWithFormat:@"%@",[minsArray objectAtIndex:[pickerView selectedRowInComponent:1]]]; 

    NSString *secsStr = [NSString stringWithFormat:@"%@",[secsArray objectAtIndex:[pickerView selectedRowInComponent:2]]]; 

    int hoursInt = [hoursStr intValue]; 
    int minsInt = [minsStr intValue]; 
    int secsInt = [secsStr intValue]; 


    interval = secsInt + (minsInt*60) + (hoursInt*3600); 

    NSLog(@"hours: %d ... mins: %d .... sec: %d .... interval: %f", hoursInt, minsInt, secsInt, interval); 

    NSString *totalTimeStr = [NSString stringWithFormat:@"%f",interval]; 

} 
+4

我们如何显示选择器中的“小时”,“分钟”,“秒”? –

+8

这是最糟糕的做事方式之一......为什么要预先分配所有的字符串!! ??它也没有设置所需的标签来显示“小时”,“分钟”,“秒”,如屏幕截图所示 – jyavenard

-1

我也面临着同样的问题。这就是为什么我用秒,天和许多其他选项制作了自定义时间选择器,并将其发布在GitHub上:
iOSSecondsTimerPicker
试试看。

+0

代码听起来非常熟悉,有什么发现... http://stackoverflow.com/questions/ 16734557/custom-uipickerview -with-three-components-each-showing-label-on-selection-indica ...把​​你的版权放到每个地方都听起来......鱼腥味......不会在iOS 7上工作 – jyavenard

+0

I不明白你为什么投下我的答案。我也在寻找解决方案很长一段时间,因为我没有找到任何工作例子,我只是自己做了,并与其他人分享,以便他们可以节省时间。我把我的答案放在我做这个选择器时经历的两个问题上,以便更多的人可以使用现成的组件。它是免费的商业用途,没有什么可疑的... –

+7

我投了弃权票,因为你拿了其他人发布的代码几个月前,重新包装它,并把你的名字作为作者,没有提及原作者。您甚至将原始文件重命名为包含首字母缩写。这是不好的形式... – jyavenard

29

与上面所接受的解决方案不同,我想出了一些不太可怕的东西。绝对不是完美的,但它具有预期的效果(我只在iOS 7上测试过iPhone,只能在写作时用于肖像)。欢迎编辑编辑以获得更好的效果。下面相关的显示代码:

// assumes you conform to UIPickerViewDelegate and UIPickerViewDataSource in your .h 
- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    // assumes global UIPickerView declared. Move the frame to wherever you want it 
    picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 200)]; 
    picker.dataSource = self; 
    picker.delegate = self; 

    UILabel *hourLabel = [[UILabel alloc] initWithFrame:CGRectMake(42, picker.frame.size.height/2 - 15, 75, 30)]; 
    hourLabel.text = @"hour"; 
    [picker addSubview:hourLabel]; 

    UILabel *minsLabel = [[UILabel alloc] initWithFrame:CGRectMake(42 + (picker.frame.size.width/3), picker.frame.size.height/2 - 15, 75, 30)]; 
    minsLabel.text = @"min"; 
    [picker addSubview:minsLabel]; 

    UILabel *secsLabel = [[UILabel alloc] initWithFrame:CGRectMake(42 + ((picker.frame.size.width/3) * 2), picker.frame.size.height/2 - 15, 75, 30)]; 
    secsLabel.text = @"sec"; 
    [picker addSubview:secsLabel]; 

    [self.view addSubview:picker]; 
} 

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

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component 
{ 
    if(component == 0) 
     return 24; 

    return 60; 
} 

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component 
{ 
    return 30; 
} 

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view 
{ 
    UILabel *columnView = [[UILabel alloc] initWithFrame:CGRectMake(35, 0, self.view.frame.size.width/3 - 35, 30)]; 
    columnView.text = [NSString stringWithFormat:@"%lu", (long) row]; 
    columnView.textAlignment = NSTextAlignmentLeft; 

    return columnView; 
} 

而结果:

H/M/S Picker

+3

你有没有尝试过与自动布局?我想知道它将如何解释设备旋转,不同的屏幕尺寸等等。干得好! – Rod

+2

我没有。正如现在写的,它几乎只适用于iPhone纵向视图,所以肯定有一些限制。 – Stonz2

+0

看起来很漂亮。这可能是打包和共享? – fatuhoku

4

我作出@一些略有改善Stonz2的版本。计算标签的y位置时也有错误。

这里.h文件

@interface CustomUIDatePicker : UIPickerView <UIPickerViewDataSource, UIPickerViewDelegate> 

@property NSInteger hours; 
@property NSInteger mins; 
@property NSInteger secs; 

-(NSInteger) getPickerTimeInMS; 
-(void) initialize; 

@end 

这里与改进

@implementation CustomUIDatePicker 
-(instancetype)init { 
self = [super init]; 
[self initialize]; 
return self; 
} 

-(id)initWithCoder:(NSCoder *)aDecoder { 
self = [super initWithCoder:aDecoder]; 
[self initialize]; 
return self; 
} 

-(instancetype)initWithFrame:(CGRect)frame { 
self = [super initWithFrame:frame]; 
[self initialize]; 
return self; 
} 

-(void) initialize { 
self.delegate = self; 
self.dataSource = self; 

int height = 20; 
int offsetX = self.frame.size.width/3; 
int offsetY = self.frame.size.height/2 - height/2; 
int marginX = 42; 
int width = offsetX - marginX; 

UILabel *hourLabel = [[UILabel alloc] initWithFrame:CGRectMake(marginX, offsetY, width, height)]; 
hourLabel.text = @"hour"; 
[self addSubview:hourLabel]; 

UILabel *minsLabel = [[UILabel alloc] initWithFrame:CGRectMake(marginX + offsetX, offsetY, width, height)]; 
minsLabel.text = @"min"; 
[self addSubview:minsLabel]; 

UILabel *secsLabel = [[UILabel alloc] initWithFrame:CGRectMake(marginX + offsetX * 2, offsetY, width, height)]; 
secsLabel.text = @"sec"; 
[self addSubview:secsLabel]; 
} 

-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { 
if (component == 0) { 
    self.hours = row; 
} else if (component == 1) { 
    self.mins = row; 
} else if (component == 2) { 
    self.secs = row; 
} 
} 

-(NSInteger)getPickerTimeInMS { 
return (self.hours * 60 * 60 + self.mins * 60 + self.secs) * 1000; 
} 

-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { 
return 3; 
} 
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component 
{ 
if(component == 0) 
    return 24; 

return 60; 
} 

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component 
{ 
return 30; 
} 

-(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view 
{ 
if (view != nil) { 
    ((UILabel*)view).text = [NSString stringWithFormat:@"%lu", row]; 
    return view; 
} 
UILabel *columnView = [[UILabel alloc] initWithFrame:CGRectMake(35, 0, self.frame.size.width/3 - 35, 30)]; 
columnView.text = [NSString stringWithFormat:@"%lu", row]; 
columnView.textAlignment = NSTextAlignmentLeft; 

return columnView; 
} 

@end 
+0

ty!我可以问你是否只需要2列(分钟,秒)我应该改变什么?我试图编辑一些代码,但无法得到我想要的结果 – Signo

+1

'numberOfComponentsInPickerView'必须返回2。 和'initialize'你应该只创建两个子视图。 offsetX也应该是'self.frame.size.width/2;' – ph1lb4

8

迅速落实

class TimePickerView: UIPickerView, UIPickerViewDataSource, UIPickerViewDelegate { 
    var hour:Int = 0 
    var minute:Int = 0 


    override init() { 
     super.init() 
     self.setup() 
    } 

    required internal init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     self.setup() 
    } 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
     self.setup() 
    } 

    func setup(){ 
     self.delegate = self 
     self.dataSource = self 

     /*let height = CGFloat(20) 
     let offsetX = self.frame.size.width/3 
     let offsetY = self.frame.size.height/2 - height/2 
     let marginX = CGFloat(42) 
     let width = offsetX - marginX 

     let hourLabel = UILabel(frame: CGRectMake(marginX, offsetY, width, height)) 
     hourLabel.text = "hour" 
     self.addSubview(hourLabel) 

     let minsLabel = UILabel(frame: CGRectMake(marginX + offsetX, offsetY, width, height)) 
     minsLabel.text = "min" 
     self.addSubview(minsLabel)*/ 
    } 

    func getDate() -> NSDate{ 
     let dateFormatter = NSDateFormatter() 
     dateFormatter.dateFormat = "HH:mm" 
     let date = dateFormatter.dateFromString(String(format: "%02d", self.hour) + ":" + String(format: "%02d", self.minute)) 
     return date! 
    } 

    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { 
     return 2 
    } 

    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 
     switch component { 
     case 0: 
      self.hour = row 
     case 1: 
      self.minute = row 
     default: 
      println("No component with number \(component)") 
     } 
    } 

    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
     if component == 0 { 
      return 24 
     } 

     return 60 
    } 

    func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { 
     return 30 
    } 

    func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView { 
     if (view != nil) { 
      (view as UILabel).text = String(format:"%02lu", row) 
      return view 
     } 
     let columnView = UILabel(frame: CGRectMake(35, 0, self.frame.size.width/3 - 35, 30)) 
     columnView.text = String(format:"%02lu", row) 
     columnView.textAlignment = NSTextAlignment.Center 

     return columnView 
    } 

} 
5

我不喜欢那个没”答案.m文件t依赖于将UILabel作为子视图UIPickerView,因为硬编码fr如果iOS决定在某一天改变外观,则Ames将会中断。

一个简单的诀窍是将小时/分钟/秒的标签标记为组件,其中1行为

小时/分钟/秒的标签将远离它们的值,但没关系。大多数用户甚至不会注意到这一点。见自己:

enter image description here

+2

这种情况下,小时,分和秒组件也滚动。这有可能防止吗? – Aliens

0

下面是“小时/分/秒”覆盖另一种解决方案。它使用拾取器视图委托中的pickerView(UIPickerView, didSelectRow: Int, inComponent: Int)方法来更新视图的标签。

这样,无论屏幕方向如何,它都能正常工作。 它仍然不是最佳的但它非常简单。

UIPickerView example

func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { 
    let label = UILabel() 
    label.text = String(row) 
    label.textAlignment = .center 
    return label 
} 

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 

    if let label = pickerView.view(forRow: row, forComponent: component) as? UILabel { 

     if component == 0, row > 1 { 
      label.text = String(row) + " hours" 
     } 
     else if component == 0 { 
      label.text = String(row) + " hour" 
     } 
     else if component == 1 { 
      label.text = String(row) + " min" 
     } 
     else if component == 2 { 
      label.text = String(row) + " sec" 
     } 
    } 
} 

已经是显示选择器视图时,行必须以编程方式选择的重叠出现...

func selectPickerViewRows() { 

    pickerView.selectRow(0, inComponent: 0, animated: false) 
    pickerView.selectRow(0, inComponent: 1, animated: false) 
    pickerView.selectRow(30, inComponent: 2, animated: false) 

    pickerView(pickerView, didSelectRow: 0, inComponent: 0) 
    pickerView(pickerView, didSelectRow: 0, inComponent: 1) 
    pickerView(pickerView, didSelectRow: 30, inComponent: 2) 
} 
+0

好的答案@nyg,但你不应该使用label.text?.append(“min”),就好像你选择了两行,你得到了两次这个词。更好地使用label.text = String(row)+“min”..但是谢谢你很好 – Pierre

+0

@Pierre是的,的确,你是对的! – nyg

相关问题