2012-06-12 50 views
20

我正在製作一個計時器應用程序,需要顯示小時,分鐘和秒的用戶。我嘗試使用UIDatePicker,但它只顯示小時和分鐘作爲選擇。不是幾秒鐘。在網上做了一些研究之後,我發現沒有辦法在UIDatePicker中獲得秒數,我必須從頭開始編寫我自己的UIPickerViewUIPickerView看起來像UIDatePicker,但與秒

所以我的問題是,是否有這樣的示例代碼,即有人寫了CustomUIPickerView幾小時,分鐘和秒,我可以將其納入我的項目? UIDatePicker有一個很好的覆蓋時間&分鐘文本,保持放在用戶旋轉撥號。如果有人在他們的自定義選取器中添加了它,那將會很好。如果我不需要,我寧願不要從頭開始編寫自定義UIPickerView。謝謝。

+0

使用帶有3個組件的uiPickerView,每個組件都有數組。 HourArray從(1到12)。 MinutesArray(1到60)。秒數組(1到60) –

+0

@safecase。我從技術上理解它是如何完成的。我所要求的是,如果有人想與我分享這段代碼,而不是我從零開始寫它 –

+3

@EmilioPelaez - 請不要使用「我們」。你不會在這裏爲整個iOS開發社區說話。有很多優秀的開發人員可以愉快地分享知識和代碼。如果我最終編寫代碼,我會在這裏與其他社區和任何未來可能感興趣的人分享,並閱讀我的文章 –

回答

40

Alrighty的人,這裏是代碼獲得小時/分鐘/秒在您的UIPickerView。您可以添加3個標籤並將其置於選取器上。我也附上了一張照片。

如果你喜歡答案,請評價它!好的開發者分享知識並不像一些人所暗示的那樣隱藏它玩得開心編碼!

enter image description here

在你的頭h文件在.m文件把這個

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

把這個

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

} 
+4

我們如何顯示選擇器中的「小時」,「分鐘」,「秒」? –

+8

這是最糟糕的做事方式之一......爲什麼要預先分配所有的字符串!! ??它也沒有設置所需的標籤來顯示「小時」,「分鐘」,「秒」,如屏幕截圖所示 – jyavenard

-1

我也面臨着同樣的問題。這就是爲什麼我用秒,天和許多其他選項製作了自定義時間選擇器,並將其發佈在GitHub上:
iOSSecondsTimerPicker
試試看。

+0

代碼聽起來非常熟悉,有什麼發現... http://stackoverflow.com/questions/ 16734557/custom-uipickerview -with-three-components-each-showing-label-on-selection-indica ...把​​你的版權放到每個地方都聽起來......魚腥味......不會在iOS 7上工作 – jyavenard

+0

I不明白你爲什麼投下我的答案。我也在尋找解決方案很長一段時間,因爲我沒有找到任何工作例子,我只是自己做了,並與其他人分享,以便他們可以節省時間。我把我的答案放在我做這個選擇器時經歷的兩個問題上,以便更多的人可以使用現成的組件。它是免費的商業用途,沒有什麼可疑的... –

+7

我投了棄權票,因爲你拿了其他人發佈的代碼幾個月前,重新包裝它,並把你的名字作爲作者,沒有提及原作者。您甚至將原始文件重命名爲包含首字母縮寫。這是不好的形式... – jyavenard

29

與上面所接受的解決方案不同,我想出了一些不太可怕的東西。絕對不是完美的,但它具有預期的效果(我只在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

你有沒有嘗試過與自動佈局?我想知道它將如何解釋設備旋轉,不同的屏幕尺寸等等。幹得好! – Rod

+2

我沒有。正如現在寫的,它幾乎只適用於iPhone縱向視圖,所以肯定有一些限制。 – Stonz2

+0

看起來很漂亮。這可能是打包和共享? – fatuhoku

4

我作出@一些略有改善Stonz2的版本。計算標籤的y位置時也有錯誤。

這裏.h文件

@interface CustomUIDatePicker : UIPickerView <UIPickerViewDataSource, UIPickerViewDelegate> 

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

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

@end 

這裏與改進

@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 
+0

ty!我可以問你是否只需要2列(分鐘,秒)我應該改變什麼?我試圖編輯一些代碼,但無法得到我想要的結果 – Signo

+1

'numberOfComponentsInPickerView'必須返回2。 和'initialize'你應該只創建兩個子視圖。 offsetX也應該是'self.frame.size.width/2;' – ph1lb4

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 
    } 

} 
5

我不喜歡那個沒」答案.m文件t依賴於將UILabel作爲子視圖UIPickerView,因爲硬編碼fr如果iOS決定在某一天改變外觀,則Ames將會中斷。

一個簡單的訣竅是將小時/分鐘/秒的標籤標記爲組件,其中1行爲

小時/分鐘/秒的標籤將遠離它們的值,但沒關係。大多數用戶甚至不會注意到這一點。見自己:

enter image description here

+2

這種情況下,小時,分和秒組件也滾動。這有可能防止嗎? – Aliens

0

下面是「小時/分/秒」覆蓋另一種解決方案。它使用拾取器視圖委託中的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,但你不應該使用label.text?.append(「min」),就好像你選擇了兩行,你得到了兩次這個詞。更好地使用label.text = String(row)+「min」..但是謝謝你很好 – Pierre

+0

@Pierre是的,的確,你是對的! – nyg

相關問題