我正在制作一个计时器应用程序,需要向用户显示小时,分钟和秒钟。我尝试使用UIDatePicker
,但它只显示了小时和分钟作为选择。不是秒。在网上进行了一些研究之后,我发现UIDatePicker
无法获得秒数,我不得不从头开始编写自己的UIPickerView
。
所以我的问题是,是否有样本代码,即有人写了CustomUIPickerView
几小时,分钟和秒,我可以在我的项目中加入? UIDatePicker
有一个很好的覆盖时间&分割用户旋转拨号时保持放置的文本。如果有人在他们的自定义选择器中添加它会很好。如果我不需要,我不想从头开始编写自定义UIPickerView
。谢谢。
答案 0 :(得分:42)
好的伙计们,这是在UIPickerView
中获得小时/分钟/秒的代码。您可以添加3个标签,策略性地将它们放在拾取器上。我也附上了一张照片。
如果你喜欢这个答案,请加以评分!优秀的开发人员分享知识并不像有些人建议那样隐藏它玩得开心!
在你的标题.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];
}
答案 1 :(得分:30)
与上面提到的解决方案不同,我想出了一些不太可怕的东西。绝对不是完美的,但它具有理想的效果(我只在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;
}
结果:
答案 2 :(得分:8)
迅速实施
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
}
}
答案 3 :(得分:6)
我不喜欢那些不依赖于将UILabel
作为子视图添加到UIPickerView
的答案,因为如果iOS决定有一天更改外观,则会对帧进行硬编码。
一个简单的技巧是将小时/分钟/秒标签设为具有1行的组件。
小时/分钟/秒标签将远离其值,但这没关系。大多数用户甚至不会注意到这一点。亲眼看看:
答案 4 :(得分: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 :(得分:1)
一种选择是使用ActionSheetPicker
https://github.com/skywinder/ActionSheetPicker-3.0
并使用ActionSheetMultipleStringPicker。您可以按照ActionSheetPicker文档中的示例代码进行操作。
答案 6 :(得分:1)
我这里有一个简单的解决方案,您可以为UIPickerView实现3种UIPickerViewDataSource方法
- (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;
}
}
答案 7 :(得分:0)
这是“小时/分钟/秒”叠加层的另一种解决方案。它使用选择器视图的委托中的pickerView(UIPickerView, didSelectRow: Int, inComponent: Int)
方法来更新视图的标签。
这样,无论屏幕方向如何,它都能正常工作。 它仍然不是最佳的,但它非常简单。
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 :(得分:-1)
我也面临同样的问题。这就是为什么我用秒,天和许多其他选项制作自定义时间选择器的原因我在GitHub上发布了它:
iOSSecondsTimerPicker
试一试。