Objective C implementing a UIPickerView with a “Do

2019-01-11 11:43发布

问题:

I am trying to implement a "Done" button in a UIPickerView Similar to the one under this link

I looked in the class reference but I couldn t find it

Thanks

回答1:

I added a UIToolbar with a UIBarButtonItem for the 'done' button in my xib with the frame set so that it's not initially visible (y value equal to the height of the parent view).

Every time the user access the picker, I changed the frame (the y value) of the UIDatePicker and the UIToolbar with an animation so that it slides up along with the picker from the bottom of the screen similar to the keyboard.

Check out my code below.

- (IBAction)showPicker
{
    if(pickerVisible == NO)
    {
        // create the picker and add it to the view
        if(self.datePicker == nil) self.datePicker = [[[UIDatePicker alloc] initWithFrame:CGRectMake(0, 460, 320, 216)] autorelease];
        [self.datePicker setMaximumDate:[NSDate date]];
        [self.datePicker setDatePickerMode:UIDatePickerModeDate];
        [self.datePicker setHidden:NO];
        [self.view addSubview:datePicker];

        // the UIToolbar is referenced 'using self.datePickerToolbar'
        [UIView beginAnimations:@"showDatepicker" context:nil];
        // animate for 0.3 secs.
        [UIView setAnimationDuration:0.3];

        CGRect datepickerToolbarFrame = self.datePickerToolbar.frame;
        datepickerToolbarFrame.origin.y -= (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
        self.datePickerToolbar.frame = datepickerToolbarFrame;

        CGRect datepickerFrame = self.datePicker.frame;
        datepickerFrame.origin.y -= (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
        self.datePicker.frame = datepickerFrame;

        [UIView commitAnimations];
        pickerVisible = YES;
    }
}

- (IBAction)done
{
    if(pickerVisible == YES)
    {
        [UIView beginAnimations:@"hideDatepicker" context:nil];
        [UIView setAnimationDuration:0.3];

        CGRect datepickerToolbarFrame = self.datePickerToolbar.frame;
        datepickerToolbarFrame.origin.y += (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
        self.datePickerToolbar.frame = datepickerToolbarFrame;

        CGRect datepickerFrame = self.datePicker.frame;
        datepickerFrame.origin.y += (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
        self.datePicker.frame = datepickerFrame;
        [UIView commitAnimations];

        // remove the picker after the animation is finished
        [self.datePicker performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:0.3];
    }
}


回答2:

The easiest way to do it is to model it in Interface Builder. It is a UIView containing a UIToolbar and a UIPickerView.

Then create an outlet for the UIView and connect it.

If you then have a UITextField you can assign your custom view to its inputView property.

[self.textField setInputView:self.customPicker];

Alternatively you can add the picker to your main view...

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.customPicker.frame = CGRectMake(0, CGRectGetMaxY(self.view.frame), CGRectGetWidth(self.customPicker.frame), CGRectGetHeight(self.customPicker.frame));
    [self.view addSubview:self.customPicker];
}

... and then use this method to show or hide the picker.

- (void)setPickerHidden:(BOOL)hidden
{
    CGAffineTransform transform = hidden ? CGAffineTransformIdentity : CGAffineTransformMakeTranslation(0, -CGRectGetHeight(self.customPicker.frame));

    [UIView animateWithDuration:0.3 animations:^{
        self.customPicker.transform = transform;
    }];
}


回答3:

I create a custom class, this supports multiple orientation:

DateTimePicker.h

    @interface DateTimePicker : UIView {
}

@property (nonatomic, assign, readonly) UIDatePicker *picker;

- (void) setMode: (UIDatePickerMode) mode;
- (void) addTargetForDoneButton: (id) target action: (SEL) action;

@end

DateTimePicker.m

#define MyDateTimePickerToolbarHeight 40

@interface DateTimePicker()

@property (nonatomic, assign, readwrite) UIDatePicker *picker;

@property (nonatomic, assign) id doneTarget;
@property (nonatomic, assign) SEL doneSelector;

- (void) donePressed;

@end


@implementation DateTimePicker

@synthesize picker = _picker;

@synthesize doneTarget = _doneTarget;
@synthesize doneSelector = _doneSelector;

- (id) initWithFrame: (CGRect) frame {
    if ((self = [super initWithFrame: frame])) {
        self.backgroundColor = [UIColor clearColor];

        UIDatePicker *picker = [[UIDatePicker alloc] initWithFrame: CGRectMake(0, MyDateTimePickerToolbarHeight, frame.size.width, frame.size.height - MyDateTimePickerToolbarHeight)];
        [self addSubview: picker];

        UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame: CGRectMake(0, 0, frame.size.width, MyDateTimePickerToolbarHeight)];
        toolbar.barStyle = UIBarStyleBlackOpaque;
        toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;

        UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle: @"Done" style: UIBarButtonItemStyleBordered target: self action: @selector(donePressed)];
        UIBarButtonItem* flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
        toolbar.items = [NSArray arrayWithObjects:flexibleSpace, doneButton, nil];

        [self addSubview: toolbar];

        self.picker = picker;
        picker.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;

        self.autoresizesSubviews = YES;
        self.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
    }
    return self;
}

- (void) setMode: (UIDatePickerMode) mode {
    self.picker.datePickerMode = mode;
}

- (void) donePressed {
    if (self.doneTarget) {
        [self.doneTarget performSelector:self.doneSelector withObject:nil afterDelay:0];
    }
}

- (void) addTargetForDoneButton: (id) target action: (SEL) action {
    self.doneTarget = target;
    self.doneSelector = action;
}

Using custom view in your view controller:

- (void)viewDidLoad
{
    [super viewDidLoad];
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [button addTarget:self
               action:@selector(buttonPressed:)
     forControlEvents:UIControlEventTouchDown];
    [button setTitle:@"Show picker" forState:UIControlStateNormal];
    button.frame = CGRectMake(100, 50, 100, 40.0);
    [self.view addSubview:button];

    CGRect screenRect = [[UIScreen mainScreen] bounds];
    CGFloat screenWidth = screenRect.size.width;
    CGFloat screenHeight = screenRect.size.height;
    picker = [[DateTimePicker alloc] initWithFrame:CGRectMake(0, screenHeight/2 - 35, screenWidth, screenHeight/2 + 35)];
    [picker addTargetForDoneButton:self action:@selector(donePressed)];
    [self.view addSubview:picker];
    picker.hidden = YES;
    [picker setMode:UIDatePickerModeDate];
}

-(void)donePressed {
    picker.hidden = YES;
}

-(void)buttonPressed:(id)sender {
    picker.hidden = NO;
}

Hope this helps. :)



回答4:

There is a more elegant solution. I'm not sure if this is recent (as of iOS7), but this has been working for me splendidly.

TJDatePicker.h

@protocol TJDatePickerActionDelegate <NSObject>
- (void)cancel:(id)sender;
- (void)done:(id)sender;
@end

@interface TJDatePicker : UIDatePicker
@property (strong, nonatomic) UIView *navInputView;
@property (weak, nonatomic) id<TJDatePickerActionDelegate> actionDelegate;
@end

TJDatePicker.m

#import "TJDatePicker.h"

@interface TJDatePicker ()
@property (strong, nonatomic) TJButton *cancelButton;
@property (strong, nonatomic) TJButton *doneButton;
@end

@implementation TJDatePicker

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        [self updateSubviews];
    }

    return self;
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    [self updateSubviews];
}

- (void)updateSubviews
{
    self.navInputView.frame = CGRectMake(0, 0, self.width, 45);
    self.cancelButton.frame = CGRectMake(5, 5, 80, 35);
    CGFloat width = 80;
    self.doneButton.frame = CGRectMake(CGRectGetMaxX(self.navInputView.frame) - width, self.cancelButton.frame.origin.y, width, self.cancelButton.height);
}

- (UIView *)navInputView
{
    if (!_navInputView)
    {
        _navInputView = [[UIView alloc] init];
        _navInputView.backgroundColor = [UIColor whiteColor];

        self.cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [self.cancelButton setTitle:@"CANCEL" forState:UIControlStateNormal];
        [self.cancelButton addTarget:self action:@selector(cancelButtonPressed) forControlEvents:UIControlEventTouchUpInside];
        [_navInputView addSubview:self.cancelButton];

        self.doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [self.doneButton setTitle:@"DONE" forState:UIControlStateNormal];
        [self.doneButton addTarget:self action:@selector(doneButtonPressed) forControlEvents:UIControlEventTouchUpInside];
        [_navInputView addSubview:self.doneButton];
    }

    return _navInputView;
}

- (void)cancelButtonPressed
{
    [self.actionDelegate cancel:self];
}

- (void)doneButtonPressed
{
    [self.actionDelegate done:self];
}

And then at implementation time...

self.datePicker = [[TJDatePicker alloc] init];
self.datePicker.actionDelegate = self;
self.textField.inputAccessoryView = self.datePicker.navInputView;

The key here is to use the inputAccessoryView of the UITextField that you are planning on setting the UIDatePicker to.



回答5:

You get the "Done" button in the toolbar using the ActionSheetPicker. Its is a great alternative to building it yourself.

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



回答6:

Success! Ok, I would never suggest doing this, but here's where the done button is created in your particular tutorial code:

Looking at the storyboard, we can see that when you click the "Role" box within "AddPersonTVC.h" (class at the top right of the storyboard), it pops up a class called "RollPickerTVCell.h"

Looking into RollPickerTVCell.h, we notice that the whole class is a subclass of "CoreDataTableViewCell"

@interface RolePickerTVCell : CoreDataTableViewCell <UIPickerViewDataSource, UIPickerViewDelegate>

Looking at the class "CoreDataTableViewCell.m", we finally find our uibarbuttonitem!

UIBarButtonItem *doneBtn =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)];


回答7:

In case you are working on a Table View Cell and you are not using a UITextField (hence you won't be using the Accessory View), here's what I did:

I created a table view cell called GWDatePickerCell that looks like this (no .nib files involved).

GWDatePickerCell.h:

#import <UIKit/UIKit.h>

@interface GWDatePickerCell : UITableViewCell

@property (nonatomic, strong) UIDatePicker *datePicker;
@property (nonatomic, strong) UIToolbar *toolbar;
@property (nonatomic, strong) UIBarButtonItem *buttonDone;

@end

GWDatePickerCell.m:

    #import "GWDatePickerCell.h"

    @implementation GWDatePickerCell

    - (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
        if(!(self=[super initWithStyle:style reuseIdentifier:reuseIdentifier])) return nil;

    _datePicker = [[UIDatePicker alloc] init];
    [_datePicker setMinuteInterval:5];
    [_datePicker setDatePickerMode:UIDatePickerModeDateAndTime];
    [self.contentView addSubview:_datePicker];

    _toolbar = [[UIToolbar alloc] init];
    _buttonDone = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:nil action:nil];
    _toolbar.items = @[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], _buttonDone];
    [self.contentView addSubview:_toolbar];

    return self;
}

- (void)layoutSubviews{
    [super layoutSubviews];
    CGRect r = self.contentView.bounds;
    r.origin.y +=44;
    r.size.height = 216;
    CGRect tb = self.contentView.bounds;
    tb.size.height = 44;
    _datePicker.frame = r;
    _toolbar.frame = tb;
}

@end

Now all I had to do when creating the cells in the Table View:

  • Specify the @selector for the Done button.
  • Set the correct cell height in heightForRowAtIndexPath