UIPickerView qui ressemble à UIDatePicker mais avec des secondes

je fais une app et nécessaire à l'affichage heure, minute et secondes de l'utilisateur. J'ai essayé d'utiliser UIDatePicker mais il montre seulement les heures et les minutes comme sélections. Pas secondes. Après avoir fait un peu de recherche en ligne, j'ai trouvé qu'il n'y a aucun moyen d'obtenir secondes UIDatePicker et j'ai eu à écrire mes propres UIPickerView à partir de zéro.

alors ma question Est, y a-t-il un exemple de code pour un tel i.e. quelqu'un a écrit un CustomUIPickerView pendant des heures, min et sec que je peux intégrer dans mon projet? UIDatePicker a une belle superposition D'heures et de minutes de texte qui reste mis pendant que l'utilisateur tourne les cadrans. Ce serait bien si quelqu'un ajoutait cela dans leur picker personnalisé aussi. Je préfère ne pas écrire un custom UIPickerView à partir de zéro si je n'ai pas. Remercier.

20
demandé sur Atulkumar V. Jain 2012-06-12 19:13:02

9 réponses

très bien les amis, voici le code pour obtenir des heures / Minutes / secondes dans votre UIPickerView. Vous pouvez ajouter 3 étiquettes un placer stratégiquement sur le sélecteur. J'ai joint une photo.

Si vous aimez la réponse ne taux de! Les bons développeurs partagent leurs connaissances et ne les cachent pas comme certains l'ont suggéré. Ont le plaisir de codage!

enter image description here

Dans votre en-tête .h du dossier de ce

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

dans votre .m du dossier de ce

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

}
41
répondu Sam B 2013-05-24 12:28:32

contrairement à la solution acceptée ci-dessus, j'ai trouvé quelque chose d'un peu moins terrible. Certainement pas parfait, mais il a l'effet désiré (j'ai seulement testé dans iOS 7 sur iPhone, ne fonctionne que dans portrait tel qu'écrit). Les modifications pour faire mieux sont les bienvenues. Code d'affichage pertinent ci-dessous:

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

et le résultat:

H/M/S Picker

30
répondu Stonz2 2015-05-12 23:05:03

mise en œuvre de swift

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
répondu Mikael 2015-04-09 10:50:52

je n'ai pas aimé les réponses ne comptent plus sur l'ajout d' UILabel comme subviews à UIPickerView, parce que le codage dur les cadres se casseront si iOS décide de changer l'apparence un jour.

un truc simple est d'avoir les étiquettes heure/min/sec comme composants avec 1 ligne.

les étiquettes heure/min/sec seront plus éloignées de leurs valeurs, mais ce n'est pas grave. La plupart des utilisateurs ne le remarqueront même pas. Pour voir vous-même:

enter image description here

5
répondu samwize 2015-10-16 02:26:53

j'ai apporté quelques petites améliorations à la version de @Stonz2. Il y avait aussi une erreur dans le calcul de la position y des étiquettes.

Ici le .h fichier

@interface CustomUIDatePicker : UIPickerView <UIPickerViewDataSource, UIPickerViewDelegate>

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

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

@end

Et ici la .m fichier avec les améliorations

@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
répondu ph1lb4 2015-03-01 19:00:50

une option est D'utiliser ActionSheetPicker

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

et d'utiliser L'ActionSheetMultipleStringPicker. Vous pouvez suivre le code d'exemple dans les documents ActionSheetPicker.

1
répondu Matthew Gabavics 2017-08-01 20:39:27

j'ai une solution simple ici, vous pouvez implémenter la méthode 3 D'UIPickerViewDataSource pour UIPickerView

    - (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
répondu Hien.Nguyen 2018-07-19 03:31:22

Voici une autre solution pour la superposition" heure/min/sec". Il utilise le pickerView(UIPickerView, didSelectRow: Int, inComponent: Int) méthode du délégué de la vue du picker pour mettre à jour l'étiquette de la vue.

de cette façon, cela fonctionnera quelle que soit l'orientation de l'écran. Il n'est toujours pas optimale mais c'est assez simple.

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

pour que la superposition apparaisse lorsque la vue de picker est affichée, les lignes doivent être programmées sélectionné...

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
répondu nyg 2017-08-01 09:44:17

j'ai également fait face à un même problème. C'est pourquoi j'ai fait un chronomètre personnalisé avec des secondes, des jours et beaucoup d'autres options et je l'ai publié sur GitHub:

ioss secondstimerpicker

Lui donner un essai.

-1
répondu Konrad G 2013-09-03 12:54:59