How to load an UIDatePicker by tapping an UITableV

2019-08-30 08:14发布

问题:

I have a normal UITableView with some regular UITableViewCell on it. And I know how to connect an UIDatePicker to UITextField. But now I would like to know if I could present the picker by tapping the whole cell even there is no text field on it.

What I tried is that I added a UIToolBar as a subview on the picker and put code like [self showPicker] in one of the UITableViewDelegate methods: didSelectRowAtIndexPath and then when I tapped the cell the picker showed like I wish.

But the problem is that when I clicked the UIBarButtonItem button on the toolbar I put earlier, it didn't trigger its action even I added target and action like a normal button should have.

If you would like to see some code, here is the custom method showPicker and regular stuff:

-(void)loadBirthdayPicker
{
    CGFloat pickerWidth = kScreenWidth;
    CGFloat pickerHeight = kScreenHeight/3;

    CGFloat toolHeight = 40;
    CGFloat toolWidth = kScreenWidth;

    UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(cancelButtonPressed:)];
    UIBarButtonItem *flexibleSpaceMiddle = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
    UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(doneButtonPressed:)];
    UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, -toolHeight, toolWidth, toolHeight)];

    [toolbar setItems:@[cancelButton, flexibleSpaceMiddle, doneButton]];
    if (!_datePicker)
    {
        _datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, kScreenHeight, pickerWidth, pickerHeight)];
    }
    _datePicker.datePickerMode = UIDatePickerModeDate;

    [_datePicker addSubview:toolbar];
    [self.view addSubview:_datePicker];

    [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        [_datePicker setFrame:CGRectMake(0, kScreenHeight-pickerHeight-60, pickerWidth, pickerHeight)];
    }
        completion:nil];
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self loadBirthdayPicker];
}

-(void)doneButtonPressed:(UIBarButtonItem *)sender
{
    NSLog(@"done");
}

回答1:

Your issue here isn't that the actions aren't being called, but rather that the toolbar buttons are not receiving the tap events at all. Your toolbar is outside the bounds of the the date picker, and you normally cannot interact with any views outside the bounds of their superview. You can verify this by setting your toolbar to clip views

_datePicker.clipsToBounds = YES;

This is a solvable problem though, with a very simple UIDatePicker subclass. I created a new subclass named MyDatePicker, did not modify the .h file at all, and added this method to the implementation

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    // Check to see if the hit point is in any of our subviews, even if they are outside our bounds
    for (UIView *subview in self.subviews) {
        if (CGRectContainsPoint(subview.frame, point)) {
            // We need to convert the point to the subview's coordinate system
            CGPoint pointInSubview = [self convertPoint:point toView:subview];
            // And now have our subview continue with the normal hitTest:withEvent: so our controls work as expected
            return [subview hitTest:pointInSubview withEvent:event];
        }
    }

    // Our check failed to return anything, so defer to the super's implemenation
    return [super hitTest:point withEvent:event];
}

Now you just need to change your code to use the new MyDatePicker instead of the UIDatePicker and your toolbar buttons will receive the touch events and call their actions when tapped. Don't forget to change your property class in your interface to match.

        _datePicker = [[MyDatePicker alloc] initWithFrame:CGRectMake(0, kScreenHeight, pickerWidth, pickerHeight)];


回答2:

You want every row in the tableview to display a date picker?

Seems like an odd use case, but you can control drag from the cell to your .h file and create an action method called togglePicker.

Also control drag from wherever your date picker is and give it an outlet property datePicker.

You can then show or not show your date picker by toggling the .hidden property from within the action method.

Create a boolean property named datePickershowing.

Then your code in the method should be:

-(void) togglePicker {
    if (dateShowing==YES) {
        datePicker.hidden=NO;
        dateShowing=NO;
    }
    else if (dateShowing==NO) {
        datePicker.hidden=YES;
        dateShowing=YES;
    }
}