UIPickerView, который выглядит как UIDatePicker, но с секундами
Я делаю приложение таймера и должен отображать час, минуту и секунды для пользователя. Я пробовал использовать UIDatePicker
, но он показывает только часы и минуты в качестве выбора. Не секунды. Проведя несколько исследований в Интернете, я обнаружил, что нет способа получить секунды в UIDatePicker
, и мне пришлось писать свой собственный UIPickerView
с нуля.
Итак, мой вопрос: есть ли пример кода для такого, например, кто-то написал CustomUIPickerView
за часы, минуты и секунды, которые я могу включить в свой проект? UIDatePicker
имеет хороший оверлей текста часов и минут, который остается, пока пользователь поворачивает циферблаты. Было бы неплохо, если бы кто-то добавил это в свой сборщик тоже. Я предпочитаю не писать пользовательские UIPickerView
с нуля, если мне это не нужно. Спасибо.
Ответы
Ответ 1
Alrighty folks, вот код для получения часов/мин/сек в вашем 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];
}
Ответ 2
В отличие от принятого решения выше, я придумал что-то менее страшное. Определенно не идеально, но он имеет желаемый эффект (я тестировал только в 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
быстрая реализация
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
}
}
Ответ 4
Я немного улучшил версию @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
Ответ 5
Мне не понравились ответы, которые не полагались на добавление UILabel
в качестве подзаголовков в UIPickerView
, потому что жесткое кодирование фреймов будет нарушено, если iOS решит изменить внешний вид когда-нибудь.
Простой трюк состоит в том, чтобы метки часа/мин/сек были компонентами с 1 строкой.
Лейблы часа/мин/сек будут дальше от их значений, но все в порядке. Большинство пользователей этого даже не заметят. Посмотрите сами:
![введите описание изображения здесь]()
Ответ 6
Один из вариантов - использовать ActionSheetPicker
https://github.com/skywinder/ActionSheetPicker-3.0
и используйте ActionSheetMultipleStringPicker. Вы можете следовать примеру кода в документах ActionSheetPicker.
Ответ 7
Здесь другое решение для наложения "час/мин/сек". Он использует метод pickerView(UIPickerView, didSelectRow: Int, inComponent: Int)
из делегата представления сборщика для обновления метки представления.
Таким образом, он будет работать независимо от ориентации экрана. Это еще не оптимально, но это довольно просто.
![Пример UIPickerView]()
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)
}
Ответ 8
У меня также была такая же проблема. Вот почему я сделал пользовательский таймер с секундами, днями и многими другими вариантами, и я опубликовал его на GitHub:
iOSSecondsTimerPicker
Попробуйте.