2012-06-12 7 views
20

Ich mache eine Timer-App und musste Stunden, Minuten und Sekunden für den Benutzer anzeigen. Ich habe versucht, UIDatePicker, aber es zeigt nur Stunden und Minuten als Auswahl. Keine Sekunden. Nachdem ich ein wenig online recherchiert habe, habe ich festgestellt, dass es keine Möglichkeit gibt, Sekunden in UIDatePicker zu bekommen und ich musste meine eigene UIPickerView von Grund auf schreiben.UIPickerView, das aussieht wie UIDatePicker aber mit Sekunden

Also meine Frage ist, gibt es Beispielcode für solche, d. H. Jemand schrieb eine CustomUIPickerView für Stunden, Minuten und Sekunden, die ich in meinem Projekt einbinden kann? UIDatePicker hat eine nette Überlagerung von Stunden & Mins Text, der gesetzt bleibt, während der Benutzer die Vorwahlknüppel dreht. Es wäre schön, wenn jemand das in seinem benutzerdefinierten Picker hinzufügen würde. Ich bevorzuge es, eine benutzerdefinierte UIPickerView von Grund auf neu zu schreiben, wenn ich nicht muss. Vielen Dank.

+0

Verwenden Sie uiPickerView mit 3 Komponenten mit jeweils Array. HourArray von (1 bis 12). MinutesArray mit (1 bis 60). SekundenArray (1 bis 60) –

+0

@safecase. Ich verstehe technisch, wie es gemacht werden muss. Ich frage nur, ob jemand dieses Stück Code mit mir teilen möchte, anstatt es von Grund auf neu zu schreiben. –

+3

@EmilioPelaez - bitte unterlassen Sie die Verwendung von "uns". Sie sprechen hier nicht für die gesamte iOS-Entwicklungsgemeinschaft. Es gibt viele gute Entwickler, die Wissen und Code teilen. Wenn ich den Code schreibe, teile ich ihn hier mit dem Rest der Community und allen, die sich für die Zukunft interessieren und meinen Beitrag lesen. –

Antwort

40

Alrighty Leute, hier ist der Code zu Stunden/Minuten/Sekunden in Ihrem UIPickerView bekommen. Sie können 3 Etiketten hinzufügen und diese strategisch auf dem Picker platzieren. Ich habe auch ein Bild beigefügt.

Wenn Sie die Antwort mögen, bewerten Sie es! Gute Entwickler teilen ihr Wissen nicht so, wie manche Leute es vorgeschlagen haben. Viel Spaß beim Programmieren!

enter image description here

In Ihrem Header .h diese Datei

@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; 

in .m Datei dieses

@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

Wie können wir "Stunden", "Min", "Sec" in Picker anzeigen? –

+8

Dies war eine der schrecklichsten Art, Dinge zu tun ... Warum sollten Sie alle Strings vorbelegen? es stellt auch nicht die erforderlichen Etiketten zur Anzeige von "Stunde", "Min", "Sekunden", wie auf dem Screenshot gezeigt – jyavenard

-1

ich auch konfrontiert gleiche Problem gestellt setzen. Aus diesem Grund habe ich eine benutzerdefinierte Zeitauswahl mit Sekunden, Tagen und vielen anderen Optionen erstellt und sie auf GitHub veröffentlicht:
iOSSecondsTimerPicker
Probieren Sie es aus.

+0

Code klingt sehr vertraut, was dort gefunden wird ... http://stackoverflow.com/questions/ 16734557/custom-uipickerview-mit-drei-komponenten-each-show-label-on-selection-indica ... Setzen Sie Ihr Copyright überall klingt eher .... fishy ... funktioniert nicht auf iOS 7 entweder – jyavenard

+0

I Versteh nicht, warum du meine Antwort abgelehnt hast. Ich suchte lange nach einer Lösung und da ich kein funktionierendes Beispiel fand, habe ich es einfach selbst gemacht und mit anderen geteilt, damit sie ihre Zeit sparen können. Ich habe meine Antwort in zwei Fragen gestellt, die ich während der Herstellung dieses Pickers gemacht habe, damit mehr Leute gebrauchsfertige Komponenten verwenden können. Es ist frei für kommerzielle Nutzung und nichts fishy darüber ... –

+7

Ich habe es abgelehnt, weil Sie den Code von jemand anderem vor Monaten gebucht, umgepackt und Ihren Namen als Autor ohne Bezug auf den ursprünglichen Autor. Sie haben sogar die Originaldatei umbenannt, sodass sie Ihre Initialen enthält. Das ist eine schlechte Form ... – jyavenard

29

Im Gegensatz zu der oben genannten Lösung, kam ich etwas weniger schrecklich. Definitiv nicht perfekt, aber es hat den gewünschten Effekt (Ich habe nur in iOS 7 auf dem iPhone getestet, funktioniert nur im Portrait wie beschrieben). Bearbeitungen zur Verbesserung sind willkommen. Relevante Anzeigecode unter:

// 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; 
} 

Und das Ergebnis:

H/M/S Picker

+3

Haben Sie das mit Auto Layout probiert? Ich frage mich, wie es für die Gerätedrehung, verschiedene Bildschirmgrößen, etc. gut wäre. Gute Arbeit! – Rod

+2

Ich habe nicht.Wie es jetzt geschrieben ist, ist es nur für iPhone-Porträt-Ansicht, so gibt es definitiv einige Einschränkungen. – Stonz2

+0

Sieht sehr hübsch aus. Könnte das möglicherweise verpackt und geteilt werden? – fatuhoku

4

Ich habe einige leichte Verbesserungen @ Stonz2-Version. Es gab auch einen Fehler bei der Berechnung der y-Position der Etiketten.

Hier ist die H-Datei

@interface CustomUIDatePicker : UIPickerView <UIPickerViewDataSource, UIPickerViewDelegate> 

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

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

@end 

Und hier die .m-Datei mit den Verbesserungen

@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! Darf ich Sie fragen, ob ich nur 2 Spalten (Minuten, Sekunden) möchte, was soll ich ändern? Ich habe versucht, den Code ein wenig zu bearbeiten, konnte aber nicht das Ergebnis erhalten, das ich wollte – Signo

+1

'numberOfComponentsInPickerView' muss stattdessen 2 zurückgeben. und in 'initialize' sollten Sie nur zwei Unteransichten erstellen. auch sollte der offsetX nur etwas wie 'self.frame.size.width/2;' – ph1lb4

8

rasche Umsetzung

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

ich die Antworten nicht gefallen hat, die ‚didn t verlassen sich auf das Hinzufügen UILabel als Subviews zu UIPickerView, weil Hardcoding der fr Ames wird brechen, wenn iOS beschließt, das Aussehen eines Tages zu ändern.

Ein einfacher Trick besteht darin, die Stunden/Minute/Sek. Beschriftungen als Komponenten mit 1 Zeile zu haben.

Die Stunden/Min/Sek-Etiketten sind weiter von ihren Werten entfernt, aber das ist in Ordnung. Die meisten Benutzer werden das nicht einmal bemerken. Überzeugen Sie sich selbst:

enter image description here

+2

sein. In diesem Fall scrollen auch die Komponenten hour, min und sec. Kann dies verhindert werden? – Aliens

0

Hier ist eine andere Lösung für die "Stunde/min/sec" Overlay. Es verwendet die pickerView(UIPickerView, didSelectRow: Int, inComponent: Int)-Methode aus dem Delegat der Auswahlansicht, um das Label der Ansicht zu aktualisieren.

Auf diese Weise wird es unabhängig von der Bildschirmausrichtung funktionieren. Es ist immer noch nicht optimal aber es ist ziemlich einfach.

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" 
     } 
    } 
} 

das Overlay angezeigt haben, wenn die Picker-Ansicht angezeigt wird, Reihen ...

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

Gute Antwort @nyg, aber Sie sollten nicht verwenden label.text? .append ("min"), als ob Sie zweimal die Zeile auswählen, haben Sie das Wort zweimal. Viel besser zu verwenden label.text = String (Zeile) + "min" .. Aber Danke funktioniert super – Pierre

+0

@Pierre Ja, tatsächlich hast du Recht! – nyg

1

Eine Option programmatisch ausgewählt werden muss, ist ActionSheetPicker

https://github.com/skywinder/ActionSheetPicker-3.0 zu verwenden

und Verwenden Sie den ActionSheetMultipleStringPicker. Sie können dem Beispielcode in den ActionSheetPicker-Dokumenten folgen.

Verwandte Themen