Adicionar UIPickerView e um botão na folha de ação - Como?

120

Meu aplicativo requer que as seguintes coisas sejam adicionadas em uma folha de ação.

  • UIToolbar
  • Botão no UIToolbar
  • Controle UIPicker

Eu incluí uma imagem para entender meus requisitos.

texto alternativo

Você poderia explicar como isso pode ser implementado?

Sagar R. Kothari
fonte
3
Obrigado por postar este problema interessante!
Tuyen Nguyen
Em vez de mexer com o gerenciamento do actionSheet, pickerView, etc., eu recomendaria o uso do EAActionSheetPicker . Realmente limpa muito seu código.
Ebandersen
@eckyzero Infelizmente, o EAActionSheetPicker parece estar quebrado no iOS 7, há muitos erros, todos começando com o "contexto inválido 0x0".
Magnus
é claro o seu bom demais para ser verdade ... me Fook, ios y b tão difícil
ChuckKelly
EAActionSheetPicker não funciona mais.
osxdirk

Respostas:

25

Atualização para iOS 7

Documentos da Apple para UIActionSheet :UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy

Eu recomendo não tentar personalizar o conteúdo de uma ActionSheet, pois isso pode levar a graves erros de contexto inválidos no iOS 7. Passei algumas horas trabalhando com esse problema e finalmente decidi adotar uma abordagem diferente. Substituí a chamada para mostrar a folha de ação por um controlador de exibição modal contendo uma simples visualização de tabela.

Existem muitas maneiras de conseguir isso. Aqui está uma maneira que acabei de implementar em um projeto atual. É bom porque eu posso reutilizá-lo entre 5 ou 6 telas diferentes, onde todos os usuários selecionam em uma lista de opções.

  1. Crie uma nova subclasse UITableViewController SimpleTableViewController,.
  2. Crie um UITableViewController no seu storyboard (incorporado em um controlador de navegação) e defina sua classe personalizada como SimpleTableViewController.
  3. Atribua ao controlador de navegação do SimpleTableViewController um ID do Storyboard de "SimpleTableVC".
  4. No SimpleTableViewController.h, crie uma propriedade NSArray que representará os dados na tabela.
  5. Também no SimpleTableViewController.h, crie um protocolo SimpleTableViewControllerDelegatecom um método necessário itemSelectedatRow:e uma propriedade fraca chamada delegado do tipo id<SimpleTableViewControllerDelegate>. É assim que passaremos a seleção de volta ao controlador pai.
  6. Em SimpleTableViewController.m, implementar a fonte de dados tableview e delegar métodos, chamando itemSelectedatRow:em tableView:didSelectRowAtIndexPath:.

Essa abordagem tem o benefício adicional de ser bastante reutilizável. Para usar, importe a classe SimpleTableViewController no seu ViewController.h, conheça o SimpleTableViewDelegate e implemente o itemSelectedAtRow:método Em seguida, para abrir o modal, instancie um novo SimpleTableViewController, defina os dados da tabela, delegue e apresente-os.

UINavigationController *navigationController = (UINavigationController *)[self.storyboard instantiateViewControllerWithIdentifier:@"SimpleTableVC"];
SimpleTableViewController *tableViewController = (SimpleTableViewController *)[[navigationController viewControllers] objectAtIndex:0];
tableViewController.tableData = self.statesArray;
tableViewController.navigationItem.title = @"States";
tableViewController.delegate = self;
[self presentViewController:navigationController animated:YES completion:nil];

Crio um exemplo simples e o publiquei no github .

Consulte também Mostrar a planilha de ações que causa erros de contexto inválidos do CGContext .

Kyle Clegg
fonte
2
Ah, iOS 7! Você arruinou tudo o que foi desenvolvido até agora. :(
Sagar R. Kothari
@Kyle Você pode expandir sua resposta dizendo qual foi sua abordagem? Obrigado
Daniel Sanchez
1
@DanielSanchez Atualizado com uma sugestão alternativa e um exemplo de código.
Kyle Clegg #
3
Uma solução muito mais elegante O IMHO é definir a visualização de entrada do seu campo de texto como UIPickerView e seu acessório como UIToolbar. Você pode conferir o projeto QuickDialog para um exemplo.
Steve Moser
111

Mais uma solução:

  • nenhuma barra de ferramentas, mas um controle segmentado (ocular)

    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil 
                                                        delegate:nil
                                                        cancelButtonTitle:nil
                                                        destructiveButtonTitle:nil
                                                        otherButtonTitles:nil];
    
    [actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
    
    CGRect pickerFrame = CGRectMake(0, 40, 0, 0);
    
    UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:pickerFrame];
    pickerView.showsSelectionIndicator = YES;
    pickerView.dataSource = self;
    pickerView.delegate = self;
    
    [actionSheet addSubview:pickerView];
    [pickerView release];
    
    UISegmentedControl *closeButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:@"Close"]];
    closeButton.momentary = YES; 
    closeButton.frame = CGRectMake(260, 7.0f, 50.0f, 30.0f);
    closeButton.segmentedControlStyle = UISegmentedControlStyleBar;
    closeButton.tintColor = [UIColor blackColor];
    [closeButton addTarget:self action:@selector(dismissActionSheet:) forControlEvents:UIControlEventValueChanged];
    [actionSheet addSubview:closeButton];
    [closeButton release];
    
    [actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
    
    [actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
marcio
fonte
1
Estou recebendo o UIApplication pode não responder ao aviso da janela principal e o aplicativo é encerrado.
Mahesh Babu
Estou tentando usar o UIPickerView, mas não consegui integrá-lo ao meu aplicativo. Desejo que o UIPickerView seja exibido ao clicar em um botão cuja ação está registrada no MYViewController: UIViewController. No método de ação, eu coloquei o código acima da pickerview. o que mais devo fazer? Por favor ajude.
Namratha 15/02/11
1
Na verdade, fredrik, você deve usar [[UIApplication sharedApplication] keyWindow]. Fonte editada para mudar isso.
Eric Goldberg
3
Van Du Tran - (nulo) dispensActionSheet: (UISegmentedControl *) remetente {UIActionSheet actionSheet = (UIActionSheet ) [ supervisor do remetente]; [actionSheet dispensWithClickedButtonIndex: 0 animado: SIM]; }
WINSergey 04/07/2013
1
Atenção: isso causa muitos erros de CGContext no iOS 7. Consulte stackoverflow.com/questions/19129091/…
Kyle Clegg
75

Embora essa pergunta seja antiga, mencionarei rapidamente que reuni uma classe ActionSheetPicker com uma função de conveniência, para que você possa gerar uma ActionSheet com um UIPickerView em uma linha. É baseado no código das respostas a esta pergunta.

Editar: agora também suporta o uso de um DatePicker e DistancePicker.


UPD:

Esta versão está obsoleta: use o ActionSheetPicker-3.0 .

animação

TimCinel
fonte
1
Super ... usando isso no meu aplicativo.
Michael Morrison
Impressionante. Usando isso agora.
21412 James Skidmore
@Sick eu preciso fazer para adicionar seu nome no meu projeto se eu usar seu código, graças
vinothp
Olá, estou usando esta classe no meu aplicativo e funciona muito bem. Obrigado. Eu tenho uma pergunta. No ActionSheetDatePickermodo, você pode adicionar vários botões à barra de ferramentas na parte superior. Isso é possível com apenas normal ActionSheetStringPickertambém?
Isuru 18/04
Ele pode fazer seleção múltipla?
Kyle Clegg
32

Sim ! Eu finalmente o encontrei.

implemente o código a seguir no evento de clique no botão para exibir a folha de ação conforme indicado na imagem da pergunta.

UIActionSheet *aac = [[UIActionSheet alloc] initWithTitle:@"How many?"
                                             delegate:self
                                    cancelButtonTitle:nil
                               destructiveButtonTitle:nil
                                    otherButtonTitles:nil];

UIDatePicker *theDatePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0.0, 44.0, 0.0, 0.0)];
if(IsDateSelected==YES)
{
    theDatePicker.datePickerMode = UIDatePickerModeDate;
    theDatePicker.maximumDate=[NSDate date];
}else {
    theDatePicker.datePickerMode = UIDatePickerModeTime;
}

self.dtpicker = theDatePicker;
[theDatePicker release];
[dtpicker addTarget:self action:@selector(dateChanged) forControlEvents:UIControlEventValueChanged];

pickerDateToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
pickerDateToolbar.barStyle = UIBarStyleBlackOpaque;
[pickerDateToolbar sizeToFit];

NSMutableArray *barItems = [[NSMutableArray alloc] init];

UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
[barItems addObject:flexSpace];

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

[pickerDateToolbar setItems:barItems animated:YES];

[aac addSubview:pickerDateToolbar];
[aac addSubview:dtpicker];
[aac showInView:self.view];
[aac setBounds:CGRectMake(0,0,320, 464)];
Sagar R. Kothari
fonte
oi sagar, obrigado pelo código, DatePickerDoneClick evento de botão, como declarar isso graças
Apache
Sagar, como descartar o pop-up folha de ação, e adicionar valor selecionado no campo de texto graças
Apache
[aac dimisswithclickedindex] // algo parecido com este método. (Ver eu coloquei um botão feito em folha de ação e adicionar alvo botão feito - seletor e no seletor de código lugar dimissal.
Sagar R. Kothari
obrigado pela resposta sagar, eu adiciono [aacmissWithClickedButtonIndex]; mas estou recebendo aviso: 'UIActionSheet' pode não responder a '-dismissWithClickedButtonIndex' e, em seguida, crio um novo método para o seletor 'DatePickerDoneClick' conforme abaixo - (void) DatePickerDoneClick {NSLog (@ "Concluído, clique em"); ratings.text = pickerView objectAtIndex: linha]} O que devo fazer, então quando eu clique no botão feito UIActionSheet (AAC) descartar e campo de texto (ratings.text) ser preenchido com o valor selecionado de selecionador graças sagar
Apache
1
@Spark é possível dar uma ideia sobre como obter o texto picker .. obrigado por seu post + 1
vinothp
10

A excelente solução de Marcio para essa pergunta foi de grande ajuda para adicionar subviews de qualquer tipo a um UIActionSheet.

Por razões que ainda não estão totalmente claras para mim, os limites do UIActionSheet só podem ser definidos após a exibição; as soluções da sagar e da marcio resolvem isso com êxito com uma mensagem setBounds: CGRectMake (...) sendo enviada para a planilha de ações depois que ela é mostrada.

No entanto, a definição dos limites do UIActionSheet após a exibição da folha cria uma transição irregular quando o ActionSheet é exibido, onde "aparece" na exibição e, em seguida, rola apenas os 40 pixels finais.

Ao dimensionar um UIPickerView após adicionar subvisões, recomendo agrupar a mensagem setBounds enviada para o actionSheet dentro de um bloco de animação. Isso tornará a entrada da actionSheet mais suave.

UIActionSheet *actionSheet = [[[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];


// add one or more subviews to the UIActionSheet
// this could be a UIPickerView, or UISegmentedControl buttons, or any other 
// UIView.  Here, let's just assume it's already set up and is called 
// (UIView *)mySubView
[actionSheet addSubview:myView];

// show the actionSheet
[actionSheet showInView:[UIApplication mainWindow]];


// Size the actionSheet with smooth animation
    [UIView beginAnimations:nil context:nil];
    [actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
    [UIView commitAnimations]; 
cana
fonte
6
Esta é uma ótima dica. Nos iOS 4 e posteriores, esse estilo de animação é "desencorajado", de acordo com os documentos. No iOS 4 ou posterior, tente o seguinte: UIView animateWithDuration: 0.3f delay: 0 opções: UIViewAnimationOptionCurveEaseInOut animações: ^ {[actionSheet setBounds: CGRectMake (0,0,320,485)];} conclusão: NULL];
ceperry
9

Para aqueles que estão tentando encontrar a função DatePickerDoneClick ... aqui está o código simples para descartar a folha de ação. Obviamente, aac deve ser um ivar (aquele que aparece no seu arquivo .h de implementação)


- (void)DatePickerDoneClick:(id)sender{
    [aac dismissWithClickedButtonIndex:0 animated:YES];
}
Accilies
fonte
9

Eu realmente não entendo porque isso UIPickerViewestá acontecendo UIActionSheet. Esta parece ser uma solução confusa e hacky, que pode ser quebrada em uma versão futura do iOS. (Eu já tive coisas como essa interrupção em um aplicativo antes, onde o UIPickerViewitem não estava sendo apresentado na primeira torneira e tinha que ser repetido - peculiaridades estranhas com o UIActionSheet).

O que eu fiz foi simplesmente implementar um UIPickerViewe, em seguida, adicioná-lo como uma subvisão à minha visão, e animá-lo subindo como se estivesse sendo apresentado como uma folha de ação.

/// Add the PickerView as a private variable
@interface EMYourClassName ()

@property (nonatomic, strong) UIPickerView *picker;
@property (nonatomic, strong) UIButton *backgroundTapButton;

@end

///
/// This is your action which will present the picker view
///
- (IBAction)showPickerView:(id)sender {

    // Uses the default UIPickerView frame.
    self.picker = [[UIPickerView alloc] initWithFrame:CGRectZero];

    // Place the Pickerview off the bottom of the screen, in the middle set the datasource delegate and indicator
    _picker.center = CGPointMake([[UIScreen mainScreen] bounds].size.width / 2.0, [[UIScreen mainScreen] bounds].size.height + _picker.frame.size.height);
    _picker.dataSource = self;
    _picker.delegate = self;
    _picker.showsSelectionIndicator = YES;

    // Create the toolbar and place it at -44, so it rests "above" the pickerview.
    // Borrowed from @Spark, thanks!
    UIToolbar *pickerDateToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, -44, 320, 44)];
    pickerDateToolbar.barStyle = UIBarStyleBlackTranslucent;
    [pickerDateToolbar sizeToFit];

    NSMutableArray *barItems = [[NSMutableArray alloc] init];

    UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
    [barItems addObject:flexSpace];

    // The action can whatever you want, but it should dimiss the picker.
    UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(backgroundTapped:)];
    [barItems addObject:doneBtn];

    [pickerDateToolbar setItems:barItems animated:YES];
    [_picker addSubview:pickerDateToolbar];

    // If you have a UITabBarController, you should add the picker as a subview of it
    // so it appears to go over the tabbar, not under it. Otherwise you can add it to 
    // self.view
    [self.tabBarController.view addSubview:_picker];

    // Animate it moving up
    [UIView animateWithDuration:.3 animations:^{
        [_picker setCenter:CGPointMake(160, [[UIScreen mainScreen] bounds].size.height - 148)]; //148 seems to put it in place just right.
    } completion:^(BOOL finished) {
        // When done, place an invisible button on the view behind the picker, so if the
        // user "taps to dismiss" the picker, it will go away. Good user experience!
        self.backgroundTapButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _backgroundTapButton.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
        [_backgroundTapButton addTarget:self action:@selector(backgroundTapped:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:_backgroundTapButton];
    }];

}

// And lastly, the method to hide the picker.  You should handle the picker changing
// in a method with UIControlEventValueChanged on the pickerview.
- (void)backgroundTapped:(id)sender {

    [UIView animateWithDuration:.3 animations:^{
        _picker.center = CGPointMake(160, [[UIScreen mainScreen] bounds].size.height + _picker.frame.size.height);
    } completion:^(BOOL finished) {
        [_picker removeFromSuperview];
        self.picker = nil;
        [self.backgroundTapButton removeFromSuperview];
        self.backgroundTapButton = nil;
    }];
}
Ethan Mick
fonte
Isso é ótimo, obrigado. Você achou que isso funciona bem com o iOS 7?
avance
1
+1 para uma excelente exibição de selecionador simples e animada para a tela. Mas você tem um erro no código. O backgroundTapButton da exibição aparece na parte superior da exibição do selecionador e bloqueia a exibição do selecionador da interação do usuário. o que você realmente pretende fazer é tornar essa visualização no espaço restante da tela que a visualização do selecionador ainda não preenche ... (você não pode fazer uma visualização por trás da visualização do selecionador como deseja)
aZtraL-EnForceR
7

Para adicionar à incrível solução de marcio, dismissActionSheet:pode ser implementado da seguinte maneira.

  1. Adicione um objeto ActionSheet ao seu arquivo .h, sintetize-o e faça referência a ele no seu arquivo .m.
  2. Adicione este método ao seu código.

    - (void)dismissActionSheet:(id)sender{
      [_actionSheet dismissWithClickedButtonIndex:0 animated:YES];
      [_myButton setTitle:@"new title"]; //set to selected text if wanted
    }
Kyle Clegg
fonte
3

Eu acho que essa é a melhor maneira de fazer isso.

ActionSheetPicker-3.0

É praticamente o que todo mundo sugere, mas usa blocos, o que é um toque legal!

Tony
fonte
Bem, se você ler acima, verá que essa classe ActionSheetPicker surgiu em primeiro lugar, devido a esta discussão. Então sim, essa é a melhor maneira, graças à solução aceita (¬_¬). stackoverflow.com/questions/1262574/…
OpenUserX03
2
Parece que a apple está prestes a começar a impor a regra de que as planilhas de ação não devem ser subclassificadas, pois estou recebendo esta mensagem de erro - "<Erro>: CGContextSetFillColorWithColor: contexto inválido 0x0. Este é um erro grave. Este aplicativo ou uma biblioteca que ele usa , está usando um contexto inválido e, portanto, está contribuindo para uma degradação geral da estabilidade e confiabilidade do sistema. Este aviso é uma cortesia: corrija esse problema. Ele se tornará um erro fatal em uma atualização futura ".
Stuart P.
@StuartP. veja a minha resposta #
213 Kyle Clegg
2

Desde o iOS 8, você não pode, ele não funciona porque a Apple mudou a implementação interna do UIActionSheet. Consulte a documentação da Apple :

Notas de subclassificação

UIActionSheet não foi projetado para ser subclassificado, nem você deve adicionar visualizações à sua hierarquia . Se você precisar apresentar uma planilha com mais personalização do que a fornecida pela API UIActionSheet, poderá criar sua própria e apresentá-la modalmente com presentViewController: animated: conclusão :.

Mutawe
fonte
1

Gostei da abordagem adotada por Wayfarer e pela flexaddicted, mas descobri (como aZtral) que não funcionava, pois o backgroundTapButton era o único elemento que respondia à interação do usuário. Isso me levou a colocar todas as três subvisões dele: _picker, _pickerToolbar e backgroundTapButton dentro de uma exibição contendo (pop-up) que foi animada dentro e fora da tela. Eu também precisava de um botão Cancelar na barra de ferramentas _picker. Aqui estão os elementos de código relevantes para a exibição pop-up (você precisa fornecer sua própria fonte de dados do selecionador e métodos de delegação).

#define DURATION            0.4
#define PICKERHEIGHT        162.0
#define TOOLBARHEIGHT       44.0

@interface ViewController ()
@property (nonatomic, strong) UIView        *popup;
@property (nonatomic, strong) UIPickerView  *picker;
@property (nonatomic, strong) UIToolbar     *pickerToolbar;
@property (nonatomic, strong) UIButton      *backgroundTapButton;
@end

-(void)viewDidLoad {
    // These are ivars for convenience
    rect = self.view.bounds;
    topNavHeight = self.navigationController.navigationBar.frame.size.height;
    bottomNavHeight = self.navigationController.toolbar.frame.size.height;
    navHeights = topNavHeight + bottomNavHeight;
}

-(void)showPickerView:(id)sender {
    [self createPicker];
    [self createToolbar];

    // create view container
    _popup = [[UIView alloc] initWithFrame:CGRectMake(0.0, topNavHeight, rect.size.width, rect.size.height - navHeights)];
    // Initially put the centre off the bottom of the screen
    _popup.center = CGPointMake(rect.size.width / 2.0, rect.size.height + _popup.frame.size.height / 2.0);
    [_popup addSubview:_picker];
    [_popup insertSubview:_pickerToolbar aboveSubview:_picker];

    // Animate it moving up
    // This seems to work though I am not sure why I need to take off the topNavHeight
    CGFloat vertCentre = (_popup.frame.size.height - topNavHeight) / 2.0;

    [UIView animateWithDuration:DURATION animations:^{
        // move it to a new point in the middle of the screen
        [_popup setCenter:CGPointMake(rect.size.width / 2.0, vertCentre)];
    } completion:^(BOOL finished) {
        // When done, place an invisible 'button' on the view behind the picker,
        // so if the user "taps to dismiss" the picker, it will go away
        self.backgroundTapButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _backgroundTapButton.frame = CGRectMake(0, 0, _popup.frame.size.width, _popup.frame.size.height);
        [_backgroundTapButton addTarget:self action:@selector(doneAction:) forControlEvents:UIControlEventTouchUpInside];
        [_popup insertSubview:_backgroundTapButton belowSubview:_picker];
        [self.view addSubview:_popup];
    }];
}

-(void)createPicker {
    // To use the default UIPickerView frame of 216px set frame to CGRectZero, but we want the 162px height one
    CGFloat     pickerStartY = rect.size.height - navHeights - PICKERHEIGHT;
    self.picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0.0, pickerStartY, rect.size.width, PICKERHEIGHT)];
    _picker.dataSource = self;
    _picker.delegate = self;
    _picker.showsSelectionIndicator = YES;
    // Otherwise you can see the view underneath the picker
    _picker.backgroundColor = [UIColor whiteColor];
    _picker.alpha = 1.0f;
}

-(void)createToolbar {
    CGFloat     toolbarStartY = rect.size.height - navHeights - PICKERHEIGHT - TOOLBARHEIGHT;
    _pickerToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, toolbarStartY, rect.size.width, TOOLBARHEIGHT)];
    [_pickerToolbar sizeToFit];

    NSMutableArray *barItems = [[NSMutableArray alloc] init];
    UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAction:)];
    [barItems addObject:cancelButton];

    // Flexible space to make the done button go on the right
    UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
    [barItems addObject:flexSpace];

    // The done button
    UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneAction:)];
    [barItems addObject:doneButton];
    [_pickerToolbar setItems:barItems animated:YES];
}

// The method to process the picker, if we have hit done button
- (void)doneAction:(id)sender {
    [UIView animateWithDuration:DURATION animations:^{
        _popup.center = CGPointMake(rect.size.width / 2.0, rect.size.height + _popup.frame.size.height / 2.0);
    } completion:^(BOOL finished) { [self destroyPopup]; }];
    // Do something to process the returned value from your picker
}

// The method to process the picker, if we have hit cancel button
- (void)cancelAction:(id)sender {
    [UIView animateWithDuration:DURATION animations:^{
        _popup.center = CGPointMake(rect.size.width / 2.0, rect.size.height + _popup.frame.size.height / 2.0);
    } completion:^(BOOL finished) { [self destroyPopup]; }];
}

-(void)destroyPopup {
    [_picker removeFromSuperview];
    self.picker = nil;
    [_pickerToolbar removeFromSuperview];
    self.pickerToolbar = nil;
    [self.backgroundTapButton removeFromSuperview];
    self.backgroundTapButton = nil;
    [_popup removeFromSuperview];
    self.popup = nil;
}
VaughanR
fonte