Dodaj widok UIPickerView i przycisk w arkuszu akcji - jak?

120

Moja aplikacja wymaga dodania następujących elementów w arkuszu działań.

  • UIToolbar
  • Przycisk na UIToolbar
  • Kontrola UIPicker

Dołączam obraz, aby zrozumieć moje wymagania.

tekst alternatywny

Czy mógłbyś wyjaśnić, jak można to wdrożyć?

Sagar R. Kothari
źródło
3
Dziękujemy za przesłanie tego interesującego problemu!
Tuyen Nguyen
Zamiast majstrować przy zarządzaniu actionSheet, pickerView itp., Poleciłbym użycie EAActionSheetPicker . Naprawdę bardzo czyści twój kod.
ebandersen
@eckyzero Niestety, EAActionSheetPicker wydaje się być uszkodzony w iOS 7, jest wiele błędów, które zaczynają się od „nieprawidłowego kontekstu 0x0.”.
Magnus
oczywiście, że zbyt dobrze, żeby było prawdziwe ... Fook me, y ios b so
hard
EAActionSheetPicker już nie działa.
osxdirk

Odpowiedzi:

25

Aktualizacja dla iOS 7

Dokumentacja Apple dla UIActionSheet :UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy

Odradzam dostosowywanie zawartości ActionSheet, ponieważ może to prowadzić do poważnych błędów nieprawidłowego kontekstu w iOS 7. Właśnie spędziłem kilka godzin na pracy nad tym problemem i ostatecznie zdecydowałem się na inne podejście. Zastąpiłem wywołanie pokazania arkusza akcji kontrolerem widoku modalnego zawierającym prosty widok tabeli.

Można to osiągnąć na wiele sposobów. Oto jeden sposób, który właśnie wdrożyłem w bieżącym projekcie. To fajne, ponieważ mogę go ponownie użyć między 5 lub 6 różnymi ekranami, na których wszyscy użytkownicy wybierają z listy opcji.

  1. Utwórz nowy UITableViewController podklasy SimpleTableViewController.
  2. Utwórz UITableViewController w swoim scenorysie (osadzonym w kontrolerze nawigacji) i ustaw jego klasę niestandardową na SimpleTableViewController.
  3. Nadaj kontrolerowi nawigacji dla SimpleTableViewController identyfikator scenorysu „SimpleTableVC”.
  4. W SimpleTableViewController.h utwórz właściwość NSArray, która będzie reprezentować dane w tabeli.
  5. Również w SimpleTableViewController.h utwórz protokół SimpleTableViewControllerDelegatez wymaganą metodąitemSelectedatRow: i słabą właściwością o nazwie delegat typu id<SimpleTableViewControllerDelegate>. W ten sposób przekażemy wybór z powrotem do kontrolera nadrzędnego.
  6. W SimpleTableViewController.m, wdrożenie metod i źródeł danych tableview delegata, nazywając itemSelectedatRow:wtableView:didSelectRowAtIndexPath: .

Takie podejście ma dodatkową zaletę w postaci możliwości ponownego wykorzystania. Aby użyć, zaimportuj klasę SimpleTableViewController w swoim ViewController.h, dostosuj się do SimpleTableViewDelegate i zaimplementuj itemSelectedAtRow:metodę. Następnie, aby otworzyć modal, po prostu utwórz wystąpienie nowego SimpleTableViewController, ustaw dane tabeli i delegata, a następnie przedstaw je.

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

Tworzę prosty przykład i umieściłem go na githubie .

Zobacz także Wyświetlanie arkusza działań powoduje błędy w nieprawidłowym kontekście CGContext .

Kyle Clegg
źródło
2
Ahh iOS 7! Zrujnowałeś wszystko, co zostało opracowane do tej pory. :(
Sagar R. Kothari
@Kyle Czy możesz rozszerzyć swoją odpowiedź, mówiąc, jakie było Twoje podejście? Dzięki
Daniel Sanchez
1
@DanielSanchez Zaktualizowano o alternatywną sugestię i przykładowy kod.
Kyle Clegg
3
O wiele bardziej eleganckim rozwiązaniem IMHO jest ustawienie widoku wejściowego pola tekstowego na UIPickerView i jego akcesorium na UIToolbar. Możesz sprawdzić przykład projektu QuickDialog.
Steve Moser
111

Jeszcze jedno rozwiązanie:

  • bez paska narzędzi, ale podzielona na segmenty kontrolka (oko)

    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
źródło
1
Otrzymuję UIApplication może nie odpowiadać na ostrzeżenie mainwindow i aplikacja kończy pracę.
Mahesh Babu
Próbuję użyć UIPickerView, ale nie udało mi się zintegrować go z moją aplikacją. Chcę, aby UIPickerView był wyświetlany po kliknięciu przycisku, którego akcja jest zarejestrowana w MYViewController: UIViewController. W metodzie akcji umieściłem powyższy kod pickerview. co jeszcze powinienem zrobić? Proszę pomóż.
Namratha
1
Właściwie Fredrik, powinieneś użyć [[UIApplication sharedApplication] keyWindow]. Edytowane źródło, aby to zmienić.
Eric Goldberg,
3
Van Du Tran - (void) dismissActionSheet: (UISegmentedControl *) sender {UIActionSheet actionSheet = (UIActionSheet ) [sender superview]; [actionSheet discissWithClickedButtonIndex: 0 animowany: YES]; }
WINSergey,
1
Uwaga: powoduje to wiele błędów CGContext w iOS 7. Zobacz stackoverflow.com/questions/19129091/ ...
Kyle Clegg
75

Chociaż to pytanie jest stare, szybko wspomnę, że utworzyłem razem klasę ActionSheetPicker z wygodną funkcją, dzięki czemu możesz odrodzić ActionSheet z UIPickerView w jednej linii. Opiera się na kodzie z odpowiedzi na to pytanie.

Edycja: teraz obsługuje również użycie DatePicker i DistancePicker.


UPD:

Ta wersja jest przestarzała: zamiast tego użyj ActionSheetPicker-3.0 .

animacja

TimCinel
źródło
1
Super ... używając tego w mojej aplikacji.
Michael Morrison
Niesamowite. Używam tego teraz.
James Skidmore,
@Sick, czy muszę dodać twoje imię i nazwisko w moim projekcie, jeśli używam twojego kodu, dziękuję
vinothp
Witam, używam tej klasy w mojej aplikacji i działa świetnie. Dzięki. Mam pytanie. W tym ActionSheetDatePickertrybie możesz dodać wiele przycisków do paska narzędzi u góry. Czy jest to możliwe również z po prostu normalnym ActionSheetStringPicker?
Isuru
Czy może dokonać wielokrotnego wyboru?
Kyle Clegg
32

Tak ! W końcu to znalazłem.

zaimplementuj następujący kod na zdarzeniu kliknięcia przycisku, aby wyświetlić arkusz akcji, jak podano na obrazku pytania.

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
źródło
cześć sagar, dzięki za kod, zdarzenie przycisku DatePickerDoneClick, jak to zadeklarować dzięki
Apache
sagar, jak zamknąć wyskakujący arkusz akcji i dodać wybraną wartość do pola tekstowego, dziękuję
Apache,
[aac dimisswithclickedindex] // coś podobnego do tej metody. (patrz: Umieściłem przycisk gotowe w arkuszu akcji i dodaj cel przycisku gotowego - selektor i kod dimissal miejsca selektora.
Sagar R. Kothari
dzięki za odpowiedź sagar, dodaję [aac dismissWithClickedButtonIndex]; ale otrzymuję ostrzeżenie: „UIActionSheet” może nie odpowiadać na „-dismissWithClickedButtonIndex”, wtedy tworzę nową metodę dla selektora „DatePickerDoneClick”, jak poniżej - (void) DatePickerDoneClick {NSLog (@ „Done clicked”); ratings.text = pickerView objectAtIndex: wiersz]} Co mam zrobić, więc po kliknięciu przycisku Gotowe UIActionSheet (AAC) oddalił i textfield (ratings.text) wypełnione wybranej wartości od kompletacji dzięki Sagar
Apache
1
@Spark czy można dać jakieś wyobrażenie o pobraniu tekstu selektora .. dzięki za twój post + 1
vinothp
10

Doskonałe rozwiązanie Marcio na to pytanie bardzo mi pomogło w dodawaniu podglądów podrzędnych do arkusza UIActionSheet.

Z powodów, które nie są (jeszcze) całkowicie dla mnie jasne, granice arkusza UIActionSheet można ustawić dopiero po jego wyświetleniu; zarówno sagar, jak i marcio rozwiązują ten problem, wysyłając do arkusza akcji komunikat setBounds: CGRectMake (...) po jego wyświetleniu.

Jednak ustawienie granic UIActionSheet po wyświetleniu arkusza tworzy gwałtowne przejście, gdy arkusz ActionSheet pojawia się, gdzie pojawia się w widoku, a następnie przewija się tylko przez ostatnie 40 pikseli lub więcej.

Podczas określania rozmiaru UIPickerView po dodaniu podglądów podrzędnych, zalecam zawijanie wiadomości setBounds wysyłanej do actionSheet wewnątrz bloku animacji. Dzięki temu wejście actionSheet będzie wyglądać płynniej.

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]; 
trzcina
źródło
6
To świetna wskazówka. W systemie iOS 4 i nowszych ten styl animacji jest „odradzany”, zgodnie z dokumentacją. W systemie iOS 4 lub nowszym spróbuj tego zamiast tego: UIView animateWithDuration: 0.3f delay: 0 options: UIViewAnimationOptionCurveEaseInOut animations: ^ {[actionSheet setBounds: CGRectMake (0,0,320,485)];} complete: NULL];
ceperry
9

Dla tych facetów, którzy szukają funkcji DatePickerDoneClick ... oto prosty kod, aby zamknąć Arkusz działań. Oczywiście aac powinien być ivar (tym, który znajduje się w twoim pliku implmentacji .h)


- (void)DatePickerDoneClick:(id)sender{
    [aac dismissWithClickedButtonIndex:0 animated:YES];
}
Accilies
źródło
9

Naprawdę nie rozumiem, dlaczego UIPickerViewdzieje się wewnątrz pliku UIActionSheet. Wydaje się, że jest to niechlujne i hakerskie rozwiązanie, które może zostać zepsute w przyszłej wersji iOS. (Miałem już takie rzeczy jak ta przerwa w aplikacji, w której UIPickerViewnie były wyświetlane przy pierwszym dotknięciu i musiały zostać ponownie zmapowane - dziwne dziwactwa zUIActionSheet ).

To, co zrobiłem, to po prostu zaimplementowałem a, UIPickerViewa następnie dodałem go jako podwidok do mojego widoku i ożywiłem go tak, jakby był prezentowany jak arkusz akcji.

/// 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
źródło
To wielkie dzięki. Czy zauważyłeś, że to działa dobrze z iOS 7?
avance
1
+1 za wspaniały, prosty widok selektora animowany na ekranie. Ale masz błąd w kodzie. Widok backgroundTapButton pojawia się na górze widoku selektora i tam blokuje widok selektora przed interakcją użytkownika. co naprawdę chciałeś zrobić, to zrobić ten widok na pozostałym obszarze ekranu, którego widok selektora jeszcze nie wypełnia ... (nie możesz zrobić widoku za widokiem selektora, tak jak zamierzasz)
aZtraL-EnForceR
7

Aby dodać do niesamowitego rozwiązania marcio, dismissActionSheet:można je zaimplementować w następujący sposób.

  1. Dodaj obiekt ActionSheet do pliku .h, zsyntetyzuj go i odwołaj do niego w pliku .m.
  2. Dodaj tę metodę do swojego kodu.

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

Myślę, że to najlepszy sposób na zrobienie tego.

ActionSheetPicker-3.0

To prawie to, co wszyscy sugerują, ale używa klocków, co jest miłym akcentem!

Tony
źródło
Cóż, jeśli przeczytasz powyżej, zobaczysz, że ta klasa ActionSheetPicker powstała w pierwszej kolejności z powodu tego wątku. Więc tak, to najlepszy sposób, dzięki przyjętemu rozwiązaniu (¬_¬). stackoverflow.com/questions/1262574/…
OpenUserX03
2
Wygląda na to, że firma Apple niedługo zacznie egzekwować swoją regułę, zgodnie z którą arkusze działań nie powinny być dzielone na podklasy, ponieważ otrzymuję ten komunikat o błędzie - „<Error>: CGContextSetFillColorWithColor: nieprawidłowy kontekst 0x0. To poważny błąd. Ta aplikacja lub używana przez nią biblioteka , używa nieprawidłowego kontekstu i tym samym przyczynia się do ogólnego pogorszenia stabilności i niezawodności systemu. To powiadomienie jest grzecznościowe: napraw ten problem. Stanie się on błędem krytycznym w nadchodzącej aktualizacji ”.
Stuart P.
@StuartP. zobacz moją odpowiedź
Kyle Clegg
2

Od iOS 8 nie możesz, to nie działa, ponieważ Apple zmieniło wewnętrzną implementację UIActionSheet. Zapoznaj się z dokumentacją Apple :

Uwagi dotyczące podklas

Arkusz UIActionSheet nie jest przeznaczony do podklasy ani nie należy dodawać widoków do jego hierarchii . Jeśli chcesz przedstawić arkusz z większym dostosowaniem niż zapewnia interfejs API UIActionSheet, możesz utworzyć własny i zaprezentować go modalnie za pomocą presentViewController: animated: Complete :.

Mutawe
źródło
1

Podobało mi się podejście przyjęte przez Wayfarera i flexaddicted, ale stwierdziłem (podobnie jak aZtral), że nie działa, ponieważ backgroundTapButton był jedynym elementem, który reagował na interakcję użytkownika. To doprowadziło mnie do umieszczenia wszystkich trzech jego podglądów podrzędnych: _picker, _pickerToolbar i backgroundTapButton wewnątrz widoku zawierającego (popup), który był następnie animowany na ekranie i poza nim. Potrzebowałem również przycisku Anuluj na pasku _pickerToolbar. Oto odpowiednie elementy kodu dla widoku wyskakującego (musisz podać własne źródło danych selektora i metody delegata).

#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
źródło