UIPickerView & eine Schaltfläche im Aktionsblatt hinzufügen - Wie?

120

Für meine Anwendung müssen folgende Elemente in einem Aktionsblatt hinzugefügt werden.

  • UIToolbar
  • Schaltfläche auf der UIToolbar
  • UIPicker-Steuerung

Ich habe ein Bild beigefügt, um meine Anforderungen zu verstehen.

Alt-Text

Könnten Sie bitte erklären, wie dies umgesetzt werden kann?

Sagar R. Kothari
quelle
3
Vielen Dank für die Veröffentlichung dieses interessanten Problems!
Tuyen Nguyen
Anstatt mit der Verwaltung von actionSheet, pickerView usw. herumzuspielen, würde ich die Verwendung von EAActionSheetPicker empfehlen . Es bereinigt Ihren Code wirklich sehr.
Ebandersen
@eckyzero Leider scheint der EAActionSheetPicker in iOS 7 defekt zu sein. Es gibt viele Fehler, die alle mit "ungültiger Kontext 0x0" beginnen.
Magnus
Natürlich ist es zu gut, um wahr zu sein ... hat mich gefickt, es ist so schwierig
ChuckKelly
EAActionSheetPicker funktioniert nicht mehr.
Osxdirk

Antworten:

25

Update für iOS 7

Apple-Dokumente für UIActionSheet :UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy

Ich empfehle, nicht zu versuchen, den Inhalt eines ActionSheets anzupassen, da dies in iOS 7 zu schwerwiegenden ungültigen Kontextfehlern führen kann. Ich habe nur ein paar Stunden damit verbracht, dieses Problem zu lösen, und mich letztendlich für einen anderen Ansatz entschieden. Ich habe den Aufruf zum Anzeigen des Aktionsblatts durch einen Modal View Controller ersetzt, der eine einfache Tabellenansicht enthält.

Es gibt viele Möglichkeiten, dies zu erreichen. Hier ist eine Möglichkeit, die ich gerade in einem aktuellen Projekt implementiert habe. Es ist schön, weil ich es zwischen 5 oder 6 verschiedenen Bildschirmen wiederverwenden kann, auf denen ich alle Benutzer aus einer Liste von Optionen auswählen kann.

  1. Erstellen Sie eine neue UITableViewController-Unterklasse SimpleTableViewController.
  2. Erstellen Sie einen UITableViewController in Ihrem Storyboard (eingebettet in einen Navigationscontroller) und setzen Sie seine benutzerdefinierte Klasse auf SimpleTableViewController.
  3. Geben Sie dem Navigationscontroller für SimpleTableViewController die Storyboard-ID "SimpleTableVC".
  4. Erstellen Sie in SimpleTableViewController.h eine NSArray-Eigenschaft, die die Daten in der Tabelle darstellt.
  5. Erstellen Sie auch in SimpleTableViewController.h ein Protokoll SimpleTableViewControllerDelegatemit einer erforderlichen Methode itemSelectedatRow:und einer schwachen Eigenschaft namens delegate of typeid<SimpleTableViewControllerDelegate> . Auf diese Weise geben wir die Auswahl an den übergeordneten Controller zurück.
  6. In SimpleTableViewController.m implementieren Methoden , um die Tableview Datenquelle und delegieren, rufen itemSelectedatRow:in tableView:didSelectRowAtIndexPath:.

Dieser Ansatz hat den zusätzlichen Vorteil, dass er ziemlich wiederverwendbar ist. Importieren Sie zur Verwendung die SimpleTableViewController-Klasse in Ihre ViewController.h, passen Sie sie an SimpleTableViewDelegate an und implementieren Sie die itemSelectedAtRow:Methode. Um das Modal zu öffnen, instanziieren Sie einfach einen neuen SimpleTableViewController, legen Sie die Tabellendaten fest, delegieren Sie sie und präsentieren Sie sie.

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

Ich erstelle ein einfaches Beispiel und habe es auf github gepostet .

Siehe auch Anzeigen des Aktionsblatts verursacht ungültige CGContext-Kontextfehler .

Kyle Clegg
quelle
2
Ahh iOS 7! Sie haben alles ruiniert, was bisher entwickelt wurde. :(
Sagar R. Kothari
@Kyle Kannst du deine Antwort erweitern, indem du sagst, was dein Ansatz war? Vielen Dank
Daniel Sanchez
1
@DanielSanchez Aktualisiert mit einem alternativen Vorschlag und einem Codebeispiel.
Kyle Clegg
3
Eine viel elegantere Lösung besteht meiner Meinung nach darin, die Eingabeansicht Ihres Textfelds auf UIPickerView und das Zubehör auf UIToolbar zu setzen. Sie können sich das QuickDialog-Projekt als Beispiel ansehen.
Steve Moser
111

Noch eine Lösung:

  • Keine Symbolleiste, sondern ein segmentiertes Steuerelement (Eyecandy)

    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
quelle
1
Ich erhalte UIApplication reagiert möglicherweise nicht auf die Warnung im Hauptfenster und die Anwendung wird beendet.
Mahesh Babu
Ich versuche, UIPickerView zu verwenden, konnte es jedoch nicht in meine App integrieren. Ich möchte, dass UIPickerView auf Knopfdruck angezeigt wird, dessen Aktion in MYViewController: UIViewController registriert ist. In die Aktionsmethode habe ich den obigen Code von pickerview eingefügt. Was soll ich sonst machen? Bitte helfen Sie.
Namratha
1
Eigentlich sollten Sie [[UIApplication sharedApplication] keyWindow] verwenden. Quelle bearbeitet, um das zu ändern.
Eric Goldberg
3
Van Du Tran - (nichtig) entlassenActionSheet: (UISegmentedControl *) Absender {UIActionSheet actionSheet = (UIActionSheet ) [Absenderübersicht]; [actionSheet entlassenWithClickedButtonIndex: 0 animiert: JA]; }
WINSergey
1
Heads up: Dies verursacht viele CGContext-Fehler in iOS 7. Siehe stackoverflow.com/questions/19129091/…
Kyle Clegg
75

Obwohl diese Frage alt ist, werde ich schnell erwähnen, dass ich eine ActionSheetPicker-Klasse mit einer praktischen Funktion zusammengestellt habe, sodass Sie ein ActionSheet mit einer UIPickerView in einer Zeile erzeugen können. Es basiert auf Code aus Antworten auf diese Frage.

Bearbeiten: Es wird jetzt auch die Verwendung eines DatePickers und eines DistancePickers unterstützt.


UPD:

Diese Version ist veraltet: Verwenden Sie stattdessen ActionSheetPicker-3.0 .

Animation

TimCinel
quelle
1
Super ... mit dem in meiner App.
Michael Morrison
Genial. Verwenden Sie dies jetzt.
James Skidmore
@ Krank muss ich Ihren Namen in meinem Projekt hinzufügen, wenn ich Ihren Code verwende, danke
vinothp
Hallo, ich verwende diese Klasse in meiner App und sie funktioniert hervorragend. Vielen Dank. Ich habe eine Frage. Im ActionSheetDatePickerModus können Sie der Symbolleiste oben mehrere Schaltflächen hinzufügen. Ist das auch mit normal möglich ActionSheetStringPicker?
Isuru
Kann es Mehrfachauswahl machen?
Kyle Clegg
32

Ja! Ich finde es endlich.

Implementieren Sie den folgenden Code in Ihr Schaltflächenklickereignis, um das im Bild der Frage angegebene Aktionsblatt aufzurufen.

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
quelle
Hallo Sagar, danke für den Code, DatePickerDoneClick Button Event, wie man es deklariert danke
Apache
sagar, wie man das Popup-Aktionsblatt schließt und den ausgewählten Wert in das Textfeld einfügt, danke
Apache
[aac dimisswithclickedindex] // so etwas wie diese Methode. (Sehe ich eine Schaltfläche Fertig in Aktion Blatt gesetzt habe und füge Ziel done button - Selektor & in der Wahl Ort dimissal Code.
Sagar R. Kothari
danke für die antwort sagar, ich füge hinzu [aac Entlassung mit ClickedButtonIndex]; aber ich erhalte eine Warnung: 'UIActionSheet' antwortet möglicherweise nicht auf '-dismissWithClickedButtonIndex', dann erstelle ich eine neue Methode für den Selektor 'DatePickerDoneClick' wie folgt - (void) DatePickerDoneClick {NSLog (@ "Done clicked"); reviews.text = pickerView objectAtIndex: row]} Was soll ich tun? Wenn ich also auf die Schaltfläche "Fertig" klicke, wird UIActionSheet (aac) geschlossen und das Textfeld (reviews.text) wird mit dem ausgewählten Wert von picker gefüllt, danke sagar
Apache
1
@ Park ist es möglich, eine Vorstellung davon zu geben, wie man den Auswahltext erhält. Danke für Ihren Beitrag + 1
vinothp
10

Marcios hervorragende Lösung für diese Frage hat mir sehr geholfen, einem UIActionSheet Unteransichten jeglicher Art hinzuzufügen.

Aus Gründen, die mir (noch) nicht ganz klar sind, können die Grenzen des UIActionSheets erst festgelegt werden, nachdem es angezeigt wurde. beide Sagar ist und marcio Lösungen erfolgreich diese Adresse mit einem setBounds: CGRectMake (...) Nachricht an den actionsheet gesendet werden , nachdem es gezeigt wird.

Wenn Sie jedoch die UIActionSheet-Grenzen festlegen, nachdem das Blatt angezeigt wurde, wird ein sprunghafter Übergang erstellt, wenn das ActionSheet angezeigt wird, in dem es "angezeigt" wird und dann nur über die letzten 40 Pixel oder so gescrollt wird.

Wenn Sie die Größe einer UIPickerView nach dem Hinzufügen von Unteransichten ändern, empfehle ich, die an das actionSheet gesendete setBounds-Nachricht in einen Animationsblock zu packen. Dadurch wird der Eingang des Aktionsblatts flüssiger.

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]; 
Schilf
quelle
6
Dies ist ein großartiger Tipp. Unter iOS 4 und höher wird dieser Animationsstil jedoch gemäß den Dokumenten "entmutigt". Versuchen Sie dies stattdessen unter iOS 4 oder höher: UIView animateWithDuration: 0.3f Verzögerung: 0 Optionen: UIViewAnimationOptionCurveEaseInOut-Animationen: ^ {[actionSheet setBounds: CGRectMake (0,0,320,485)];} Vervollständigung: NULL];
Ceperry
9

Für diejenigen, die versuchen, die DatePickerDoneClick-Funktion zu finden ... hier ist der einfache Code zum Schließen des Aktionsblatts. Offensichtlich sollte aac ein ivar sein (derjenige, der in Ihrer .h-Datei für die Implementierung enthalten ist)


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

Ich verstehe nicht wirklich, warum das UIPickerViewin einem geht UIActionSheet. Dies scheint eine chaotische und hackige Lösung zu sein, die in einer zukünftigen iOS-Version beschädigt werden kann. (Ich hatte UIPickerViewsolche Dinge schon einmal in einer App, in der das beim ersten Tippen nicht präsentiert wurde und erneut getippt werden musste - seltsame Macken mit dem UIActionSheet).

Ich habe einfach ein implementiert UIPickerViewund es dann als Unteransicht zu meiner Ansicht hinzugefügt und es nach oben animiert, als würde es wie ein Aktionsblatt dargestellt.

/// 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
quelle
Das ist großartig, danke. Haben Sie festgestellt, dass dies mit iOS 7 gut funktioniert?
Avance
1
+1 für eine großartige einfache Auswahlansicht, die auf dem Bildschirm animiert ist. Aber Sie haben einen Fehler im Code. Die Ansicht backgroundTapButton wird über der Auswahlansicht angezeigt und blockiert dort die Auswahlansicht für die Benutzerinteraktion. Was Sie wirklich tun wollten, war, diese Ansicht auf dem verbleibenden Bildschirmbereich zu
erstellen, den die Auswahlansicht
7

Um die fantastische Lösung von marcio zu erweitern, dismissActionSheet:kann sie wie folgt implementiert werden.

  1. Fügen Sie Ihrer .h-Datei ein ActionSheet-Objekt hinzu, synthetisieren Sie es und verweisen Sie in Ihrer .m-Datei darauf.
  2. Fügen Sie diese Methode Ihrem Code hinzu.

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

Ich denke, das ist der beste Weg, es zu tun.

ActionSheetPicker-3.0

Es ist so ziemlich das, was jeder vorschlägt, aber es werden Blöcke verwendet, was eine nette Geste ist!

Tony
quelle
Wenn Sie oben lesen, werden Sie feststellen, dass diese ActionSheetPicker-Klasse aufgrund dieses Threads überhaupt erst entstanden ist. Ja, das ist der beste Weg, dank der akzeptierten Lösung (¬_¬). stackoverflow.com/questions/1262574/…
OpenUserX03
2
Es sieht so aus, als würde Apple damit beginnen, die Regel durchzusetzen, dass Aktionsblätter nicht in Unterklassen unterteilt werden sollen, da diese Fehlermeldung angezeigt wird: "<Fehler>: CGContextSetFillColorWithColor: Ungültiger Kontext 0x0. Dies ist ein schwerwiegender Fehler. Diese Anwendung oder eine von ihr verwendete Bibliothek verwendet einen ungültigen Kontext und trägt damit zu einer allgemeinen Verschlechterung der Systemstabilität und -zuverlässigkeit bei. Dieser Hinweis ist eine Höflichkeit: Bitte beheben Sie dieses Problem. Bei einem bevorstehenden Update wird dies zu einem schwerwiegenden Fehler. "
Stuart P.
@StuartP. siehe meine Antwort
Kyle Clegg
2

Seit iOS 8 können Sie nicht, es funktioniert nicht, weil Apple die interne Implementierung von geändert hat UIActionSheet. Weitere Informationen finden Sie in der Apple-Dokumentation :

Anmerkungen zur Unterklasse

UIActionSheet kann weder in Unterklassen unterteilt werden, noch sollten Sie seiner Hierarchie Ansichten hinzufügen . Wenn Sie ein Blatt mit mehr Anpassungsmöglichkeiten als von der UIActionSheet-API bereitgestellt präsentieren müssen, können Sie ein eigenes erstellen und es mit presentViewController modal präsentieren: animiert: Fertigstellung:.

Mutawe
quelle
1

Ich mochte den Ansatz von Wayfarer und flexaddicted, fand aber (wie aZtral), dass er nicht funktionierte, da der backgroundTapButton das einzige Element war, das auf Benutzerinteraktion reagierte. Dies führte mich dazu, alle drei seiner Unteransichten: _picker, _pickerToolbar und backgroundTapButton in eine enthaltende Ansicht (Popup) zu setzen, die dann auf und neben dem Bildschirm animiert wurde. Ich brauchte auch eine Schaltfläche Abbrechen in der _pickerToolbar. Hier sind die relevanten Codeelemente für die Popup-Ansicht (Sie müssen Ihre eigene Picker-Datenquelle angeben und Methoden delegieren).

#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
quelle