Episode #26

Building a Custom Picker Component - Part 2

13 minutes
Published on July 26, 2012

This video is only available to subscribers. Get access to this video and 572 others.

In this episode, I continue where I left of in episode 25. I add a nice animation to present & dismiss the picker, as well as a backdrop view that allows you to tap anywhere to cancel.

Links

Animating in & out

I found that using an animation with opposite curves looked best:

    // animating in...
    [UIView animateWithDuration:0.25 delay:0
                        options:<b>UIViewAnimationCurveEaseIn</b>
                     animations:^{
                        // ...
                     } completion:^(BOOL finished) {
                        // ...
                     }];


    // animating out...
    [UIView animateWithDuration:0.25 delay:0
                        options:<b>UIViewAnimationCurveEaseOut</b>
                     animations:^{
                        // ...
                     } completion:^(BOOL finished) {
                        // ...
                     }];

Adding the backdrop

- (UIView *)backdropView {
    UIView *backdropView = [[UIView alloc] initWithFrame:self.bounds];
    backdropView.backgroundColor = [UIColor colorWithWhite:0 alpha:BSMODALPICKER_BACKDROP_OPACITY];
    backdropView.alpha = 0;

    UIGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onBackdropTap:)];
    [backdropView addGestureRecognizer:tapRecognizer];
    return backdropView;
}
- (void)presentInView:(UIView *)view withBlock:(BSModalPickerViewCallback)callback {
    self.frame = view.bounds;
    self.callbackBlock = callback;

    [_panel removeFromSuperview];
    <b>[_backdropView removeFromSuperview];</b>

    _panel = [[UIView alloc] initWithFrame:CGRectMake(0, self.bounds.size.height - BSMODALPICKER_PANEL_HEIGHT, self.bounds.size.width, BSMODALPICKER_PANEL_HEIGHT)];
    _picker = [self picker];
    _toolbar = [self toolbar];

    <b>_backdropView = [self backdropView];
    [self addSubview:_backdropView];</b>

    [_panel addSubview:_picker];
    [_panel addSubview:_toolbar];

    [self addSubview:_panel];
    [view addSubview:self];

    CGRect oldFrame = _panel.frame;
    CGRect newFrame = _panel.frame;
    newFrame.origin.y += newFrame.size.height;
    _panel.frame = newFrame;

    [UIView animateWithDuration:0.25 delay:0
                        options:UIViewAnimationCurveEaseOut
                     animations:^{
                         _panel.frame = oldFrame;
                         <b>_backdropView.alpha = 1;</b>
                     } completion:^(BOOL finished) {

                     }];
}

- (void)dismissPicker {
    [UIView animateWithDuration:0.25 delay:0
                        options:UIViewAnimationCurveEaseOut
                     animations:^{
                         CGRect newFrame = _panel.frame;
                         newFrame.origin.y += _panel.frame.size.height;
                         _panel.frame = newFrame;
                         <b>_backdropView.alpha = 0;</b>
                     } completion:^(BOOL finished) {
                         [_panel removeFromSuperview];
                         _panel = nil;

                         <b>[_backdropView removeFromSuperview];
                         _backdropView = nil;</b>

                         [self removeFromSuperview];
                     }];
}

Finally, we just need to cancel the dialog if the user taps on the backdrop:

- (void)onBackdropTap:(id)sender {
    [self onCancel:sender];
}