ios UIPickerView 看起来像 UIDatePicker 但有几秒钟
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10999575/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIPickerView that looks like UIDatePicker but with seconds
提问by Sam B
I am making a timer app and needed to display hour, min and seconds to the user. I tried using UIDatePicker
but it shows only hours and mins as selections. Not seconds. After doing a bit of research online I found that there is no way to get seconds in UIDatePicker
and I had to write my own UIPickerView
from scratch.
我正在制作一个计时器应用程序,需要向用户显示小时、分钟和秒。我尝试使用,UIDatePicker
但它只显示小时和分钟作为选择。不是秒。在网上做了一些研究后,我发现没有办法进入UIDatePicker
,我不得不UIPickerView
从头开始写我自己的。
So my question is, is there sample code for such i.e. someone wrote a CustomUIPickerView
for hours, min and secs that I can incorporate in my project? UIDatePicker
has a nice overlay of Hours & Mins text that stays put while the user rotate the dials. It would be nice if someone added that in their custom picker too. I prefer not to write a custom UIPickerView
from scratch if I don't have to. Thank you.
所以我的问题是,是否有这样的示例代码,即有人写了CustomUIPickerView
几个小时、分钟和秒的代码,我可以将其合并到我的项目中?UIDatePicker
有一个很好的小时和分钟文本覆盖,当用户旋转表盘时会保持原样。如果有人也在他们的自定义选择器中添加了它,那就太好了。UIPickerView
如果没有必要,我不想从头开始编写自定义。谢谢你。
回答by Sam B
Alrighty folks, here is the code to get hours/mins/secs in your UIPickerView
. You can add 3 labels an strategically place them on the picker. I have attached a picture as well.
好的伙计们,这是在您的UIPickerView
. 您可以添加 3 个标签,并有策略地将它们放置在选择器上。我也附上了一张图片。
If you like the answer do rate it up! Good developers share knowledge not hide it like some people suggested. Have fun coding!
如果你喜欢做的答案评分吧!优秀的开发人员分享知识,而不是像某些人建议的那样隐藏它。玩得开心编码!
In your header .h file put this
在你的头文件 .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;
in your .m file put this
在你的 .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];
}
回答by Stonz2
Unlike the accepted solution above, I came up with something a little less terrible. Definitely not perfect, but it has the desired effect (I've only tested in iOS 7 on iPhone, only works in portrait as written). Edits to make better are welcome. Relevant display code below:
与上面公认的解决方案不同,我想出了一些不那么可怕的东西。绝对不是完美的,但它具有预期的效果(我只在 iPhone 上的 iOS 7 中进行了测试,只能在写的肖像中工作)。欢迎编辑以做得更好。相关显示代码如下:
// 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;
}
And the result:
结果:
回答by Mikael
swift implementation
迅速实施
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
}
}
回答by samwize
I did not like the answers that didn't rely on adding UILabel
as subviews to UIPickerView
, because hardcoding the frames will break if iOS decides to change the appearance someday.
我不喜欢那些不依赖于UILabel
作为子视图添加到的答案UIPickerView
,因为如果 iOS 决定有一天改变外观,硬编码框架将会中断。
A simple trick is to have the hour/min/sec labels as components with 1 row.
一个简单的技巧是将小时/分钟/秒标签作为具有 1 行的组件。
The hour/min/sec labels will be further from their values, but that's okay. Most users will not even notice that. See for yourself:
小时/分钟/秒标签将远离它们的值,但没关系。大多数用户甚至不会注意到这一点。你自己看:
回答by ph1lb4
I made some slight improvements to @Stonz2's version. There was also an error with the calculation of the y position of the labels.
我对@Stonz2 的版本做了一些细微的改进。计算标签的 y 位置也存在错误。
Here the .h file
这里是 .h 文件
@interface CustomUIDatePicker : UIPickerView <UIPickerViewDataSource, UIPickerViewDelegate>
@property NSInteger hours;
@property NSInteger mins;
@property NSInteger secs;
-(NSInteger) getPickerTimeInMS;
-(void) initialize;
@end
And here the .m file with the improvements
这里是带有改进的 .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
回答by Matthew Gabavics
One option is to use ActionSheetPicker
一种选择是使用 ActionSheetPicker
https://github.com/skywinder/ActionSheetPicker-3.0
https://github.com/skywinder/ActionSheetPicker-3.0
and utilize the ActionSheetMultipleStringPicker. You can follow the example code in the ActionSheetPicker documents.
并利用 ActionSheetMultipleStringPicker。您可以按照 ActionSheetPicker 文档中的示例代码进行操作。
回答by Hien.Nguyen
I have a simple solution here, you can implement 3 method of UIPickerViewDataSource for UIPickerView
我这里有一个简单的解决方案,您可以为 UIPickerView 实现 UIPickerViewDataSource 的 3 个方法
- (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;
}
}
回答by nyg
Here's another solution for the "hour/min/sec" overlay. It uses the pickerView(UIPickerView, didSelectRow: Int, inComponent: Int)
method from the picker view's delegate to update the view's label.
这是“小时/分钟/秒”叠加的另一种解决方案。它使用pickerView(UIPickerView, didSelectRow: Int, inComponent: Int)
选择器视图委托中的方法来更新视图的标签。
This way, it will work no matter the screen orientation. It still isn't optimalbut it's quite straightforward.
这样,无论屏幕方向如何,它都可以工作。它仍然不是最佳的,但它非常简单。
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"
}
}
}
To have the overlay appear when the picker view is displayed, rows must be programmatically selected...
要在显示选择器视图时显示叠加层,必须以编程方式选择行...
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)
}
回答by Konrad G
I also faced same problem. That's why I made a custom time picker with seconds, days and many other options and I published it on GitHub:
iOSSecondsTimerPicker
Give it a try.
我也面临同样的问题。这就是为什么我制作了一个带有秒、天和许多其他选项的自定义时间选择器,并将其发布在 GitHub 上:
iOSSecondsTimerPicker
试试看。