it-swarm.com.ru

UIPickerView, который выглядит как UIDatePicker, но с секундами

Я делаю приложение таймера, и мне нужно было показать пользователю часы, минуты и секунды. Я попытался использовать UIDatePicker, но он показывает только часы и минуты в качестве выбора. Не секунды. Проведя небольшое исследование в Интернете, я обнаружил, что нет способа получить секунды в UIDatePicker, и мне пришлось написать свой собственный UIPickerView с нуля. 

Итак, мой вопрос, есть ли пример кода для такого, то есть кто-то написал CustomUIPickerView для часов, минут и секунд, которые я могу включить в свой проект? У UIDatePicker есть хорошее наложение текста «Часы и минуты», которое остается на месте, пока пользователь вращает диски. Было бы хорошо, если бы кто-то добавил это в свой пользовательский подборщик тоже. Я предпочитаю не писать собственные UIPickerView с нуля, если мне не нужно. Спасибо.

20
Sam B

Ладно, ребята, вот код для получения часов/минут/секунд в вашей UIPickerView. Вы можете добавить 3 метки, чтобы стратегически разместить их на сборщике. Я также приложил картинку.

Если вам нравится ответ, оцените его! Хорошие разработчики делятся знаниями, а не скрывают их, как предлагали некоторые люди. Веселого программирования!

enter image description here

В вашем заголовочном файле .h поместите это

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

в вашем .m файле поместите это

@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

В отличие от принятого выше решения, я придумал что-то менее страшное. Определенно не идеальный, но он дает желаемый эффект (я тестировал только в 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

30
Stonz2

Быстрая реализация

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

Мне не понравились ответы, которые не основывались на добавлении UILabel в качестве подпредставлений к UIPickerView, потому что жесткое кодирование фреймов сломается, если iOS решит когда-нибудь изменить внешний вид.

Простой трюк состоит в том, чтобы метки часа/минуты/секунды были компонентами с 1 строкой.

Метки часов/минут/секунд будут дальше от своих значений, но это нормально. Большинство пользователей даже не заметят этого. Посмотреть на себя:

 enter image description here

6
samwize

Я сделал несколько небольших улучшений в версии @ Stonz2. Также произошла ошибка с вычислением y-позиции надписей.

Здесь файл .h

@interface CustomUIDatePicker : UIPickerView <UIPickerViewDataSource, UIPickerViewDelegate>

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

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

@end

А вот файл .m с улучшениями

@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

У меня есть простое решение здесь, вы можете реализовать 3 метода UIPickerViewDataSource для 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
Hien.Nguyen

Одним из вариантов является использование ActionSheetPicker 

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

и использовать ActionSheetMultipleStringPicker. Вы можете следовать примеру кода в документах ActionSheetPicker.

1
Matthew Gabavics

Вот еще одно решение для наложения «час/мин/сек». Он использует метод 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