webentwicklung-frage-antwort-db.com.de

UIPickerView, das wie UIDatePicker aussieht, jedoch mit Sekunden

Ich mache eine Timer-App und musste dem Benutzer Stunde, Min und Sekunden anzeigen. Ich habe versucht, UIDatePicker zu verwenden, aber es werden nur Stunden und Minuten als Auswahl angezeigt. Nicht sekunden Nach ein paar Recherchen im Internet stellte sich heraus, dass es keine Möglichkeit gibt, Sekunden in UIDatePicker zu bekommen, und ich musste meine eigene UIPickerView von Grund auf neu schreiben. 

Meine Frage ist also: Gibt es Beispielcode für einen solchen, d. H. Jemand hat eine CustomUIPickerView für Stunden, Minuten und Sekunden geschrieben, die ich in mein Projekt integrieren kann? UIDatePicker verfügt über eine schöne Überlagerung von Stunden und Minuten, die angezeigt wird, während der Benutzer die Drehregler dreht. Es wäre schön, wenn jemand das auch in seinem benutzerdefinierten Picker hinzufügt. Ich ziehe vor, keine benutzerdefinierte UIPickerView von Grund auf neu zu schreiben, wenn ich nicht muss. Vielen Dank.

20
Sam B

In Ordnung, Leute, hier ist der Code, um Stunden/Minuten/Sekunden in Ihre UIPickerView zu bekommen. Sie können 3 Labels hinzufügen und diese strategisch auf dem Picker platzieren. Ich habe auch ein Bild angehängt.

Wenn Ihnen die Antwort gefällt, bewerten Sie sie! Gute Entwickler teilen Wissen und verbergen es nicht, wie manche Leute vorgeschlagen haben. Viel Spaß beim Codieren!

enter image description here

Fügen Sie dies in Ihre Header-H-Datei ein

@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 Ihre .m-Datei setzen Sie dies

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

}
42
Sam B

Im Gegensatz zu der oben akzeptierten Lösung hatte ich etwas weniger Schreckliches. Definitiv nicht perfekt, aber es hat den gewünschten Effekt (ich habe nur in iOS 7 auf dem iPhone getestet, funktioniert nur im Hochformat wie geschrieben). Bearbeitungen zur Verbesserung sind willkommen. Relevanter Anzeigecode unten:

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

30
Stonz2

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

}
8
Mikael

Ich mochte die Antworten, die nicht darauf angewiesen waren, UILabel als Subviews zu UIPickerView hinzuzufügen, nicht gut, da die Frames durch Hardcoding beschädigt werden, wenn iOS das Erscheinungsbild eines Tages ändert.

Ein einfacher Trick ist, die Stunden/Min/Sek. Als Komponenten mit 1 Zeile zu kennzeichnen.

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

 enter image description here

6
samwize

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

Hier 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
4
ph1lb4

Ich habe hier eine einfache Lösung, Sie können 3 UIPickerViewDataSource-Methoden für UIPickerView implementieren

    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    return 5;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    switch (component) {
        case 0:
            return 24;
            break;
        case 1:
        case 3:
            return 1;
            break;
        case 2:
        case 4:
            return 60;
            break;
        default:
            return 1;
            break;
    }
}

- (NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    switch (component) {
        case 1:
        case 3:
            return @":";
            break;
        case 0:
        case 2:
        case 4:
            return [NSString stringWithFormat:@"%lu", (long) row];
            break;
        default:
            return @"";
            break;
    }
}

 enter image description here

1
Hien.Nguyen

Eine Option ist die Verwendung von ActionSheetPicker 

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

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

1

Hier ist eine weitere Lösung für die Überlagerung "Stunde/Minute/Sekunde". Es verwendet die pickerView(UIPickerView, didSelectRow: Int, inComponent: Int)-Methode des Delegaten der Auswahlansicht, um die Bezeichnung der Ansicht zu aktualisieren.

Auf diese Weise funktioniert es unabhängig von der Bildschirmausrichtung. 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"
        }
    }
}

Damit die Überlagerung angezeigt wird, wenn die Auswahlansicht angezeigt wird, müssen Zeilen programmgesteuert ausgewählt werden ...

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