Thêm UIPickerView & một nút trong trang tính Hành động - Làm thế nào?


120

Ứng dụng của tôi yêu cầu phải thêm những thứ sau vào một tờ hành động.

  • Thanh công cụ
  • Nút trên UIToolbar
  • Kiểm soát UIPicker

Tôi đã bao gồm một hình ảnh để hiểu yêu cầu của tôi.

văn bản thay thế

Bạn có thể vui lòng giải thích, làm thế nào điều này có thể được thực hiện?


3
Cảm ơn bạn đã đăng vấn đề thú vị này!
Tuyền Nguyễn

Thay vì gặp rắc rối với việc quản lý actionSheet, pickerView, v.v., tôi khuyên bạn nên sử dụng EAActionSheetPicker . Nó thực sự làm sạch mã của bạn rất nhiều.
ebandersen

@eckyzero Thật không may, EAActionSheetPicker dường như bị hỏng trong iOS 7, có rất nhiều lỗi đều bắt đầu bằng "ngữ cảnh không hợp lệ 0x0.".
Magnus

tất nhiên nó phải tốt đến mức khó tin ... Fook tôi, ios y b rất khó khăn
ChuckKelly

EAActionSheetPicker không hoạt động nữa.
osxdirk

Câu trả lời:


25

Cập nhật cho iOS 7

Tài liệu của Apple cho UIActionSheet :UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy

Tôi khuyên bạn không nên cố gắng tùy chỉnh nội dung của ActionSheet, vì nó có thể dẫn đến lỗi ngữ cảnh không hợp lệ nghiêm trọng trong iOS 7. Tôi chỉ dành vài giờ để khắc phục sự cố này và cuối cùng quyết định thực hiện một cách tiếp cận khác. Tôi đã thay thế lời gọi hiển thị trang hành động bằng bộ điều khiển chế độ xem phương thức có chứa chế độ xem bảng đơn giản.

Có nhiều cách để thực hiện điều này. Đây là một cách mà tôi vừa thực hiện trong một dự án hiện tại. Thật tuyệt vì tôi có thể sử dụng lại nó giữa 5 hoặc 6 màn hình khác nhau, nơi tất cả người dùng tôi đều có thể chọn từ danh sách các tùy chọn.

  1. Tạo một lớp con UITableViewController mới SimpleTableViewController,.
  2. Tạo một UITableViewController trong bảng phân cảnh của bạn (được nhúng trong bộ điều khiển điều hướng) và đặt lớp tùy chỉnh của nó thành SimpleTableViewController.
  3. Cung cấp cho bộ điều khiển điều hướng cho SimpleTableViewController ID bảng phân cảnh của "SimpleTableVC".
  4. Trong SimpleTableViewController.h, hãy tạo thuộc tính NSArray sẽ đại diện cho dữ liệu trong bảng.
  5. Cũng trong SimpleTableViewController.h, hãy tạo một giao thức SimpleTableViewControllerDelegatevới một phương thức bắt buộc itemSelectedatRow:và một thuộc tính yếu được gọi là kiểu ủy quyềnid<SimpleTableViewControllerDelegate> . Đây là cách chúng tôi sẽ chuyển lựa chọn trở lại bộ điều khiển mẹ.
  6. Trong SimpleTableViewController.m, triển khai nguồn dữ liệu tableview và các phương thức ủy quyền, gọi itemSelectedatRow:vào tableView:didSelectRowAtIndexPath:.

Cách tiếp cận này có thêm lợi ích là có thể tái sử dụng khá tốt. Để sử dụng, hãy nhập lớp SimpleTableViewController trong ViewController.h của bạn, tuân theo SimpleTableViewDelegate và triển khai itemSelectedAtRow:phương thức. Sau đó, để mở phương thức, chỉ cần khởi tạo một SimpleTableViewController mới, đặt dữ liệu bảng và ủy quyền rồi trình bày nó.

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

Tôi tạo một ví dụ đơn giản và đăng nó lên github .

Ngoài ra, hãy xem Hiển thị trang hành động gây ra lỗi ngữ cảnh không hợp lệ CGContext .


2
Ahh iOS 7! Bạn đã làm hỏng mọi thứ đã được phát triển cho đến bây giờ. :(
Sagar R. Kothari

@Kyle Bạn có thể mở rộng câu trả lời của mình bằng cách cho biết cách tiếp cận của bạn là gì không? Cảm ơn
Daniel Sanchez

1
@DanielSanchez Đã cập nhật một đề xuất thay thế và mẫu mã.
Kyle Clegg

3
Một giải pháp thanh lịch hơn nhiều IMHO là đặt chế độ xem đầu vào của trường văn bản của bạn thành UIPickerView và phụ kiện của nó thành UIToolbar. Bạn có thể xem dự án QuickDialog để làm ví dụ.
Steve Moser

111

Một giải pháp khác:

  • không có thanh công cụ nhưng có một điều khiển được phân đoạn (phức tạp)

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

1
Tôi nhận được UIA Ứng dụng có thể không phản hồi với cảnh báo mainwindow và ứng dụng chấm dứt.
Mahesh Babu

Tôi đang cố gắng sử dụng UIPickerView nhưng không thể tích hợp nó vào ứng dụng của mình. Tôi muốn UIPickerView được hiển thị khi nhấp vào nút có hành động được đăng ký trong MYViewController: UIViewController. Trong phương thức hành động, tôi đã đặt mã pickerview ở trên. Tôi nên làm điều gì khác nữa? Xin vui lòng giúp đỡ.
Namratha

1
Trên thực tế, bạn nên sử dụng keyWindow [[UIApplication sharedApplication] [UIApplication sharedApplication]]. Đã chỉnh sửa nguồn để thay đổi điều đó.
Eric Goldberg

3
Van Du Tran - (void) allowActionSheet: (UISegmentedControl *) sender {UIActionSheet actionSheet = (UIActionSheet ) [sender superview]; [actionSheet allowWithClickedButtonIndex: 0 animation: YES]; }
WINSergey

1
Người đứng đầu lên: điều này gây ra nhiều lỗi CGContext trong iOS 7. Xem stackoverflow.com/questions/19129091/...
Kyle Clegg

75

Mặc dù câu hỏi này đã cũ, nhưng tôi sẽ nhanh chóng đề cập rằng tôi đã tập hợp một lớp ActionSheetPicker với chức năng tiện lợi, vì vậy bạn có thể tạo một ActionSheet với UIPickerView trong một dòng. Nó dựa trên mã từ câu trả lời cho câu hỏi này.

Chỉnh sửa: Nó hiện cũng hỗ trợ việc sử dụng DatePicker và DistancePicker.


CẬP NHẬT:

Phiên bản này không được dùng nữa: hãy sử dụng ActionSheetPicker-3.0 để thay thế.

hoạt hình


1
Siêu ... sử dụng cái này trong ứng dụng của tôi.
Michael Morrison

Tuyệt vời. Đang sử dụng cái này.
James Skidmore

@Sick làm tôi cần phải thêm tên của bạn trong dự án của tôi nếu tôi sử dụng mã của bạn, nhờ
vinothp

Xin chào, tôi đang sử dụng lớp này trong ứng dụng của mình và nó hoạt động rất tốt. Cảm ơn. Tôi có một câu hỏi. Trong ActionSheetDatePickerchế độ này, bạn có thể thêm nhiều nút vào thanh công cụ trên cùng. Điều này có thể với bình thường ActionSheetStringPickerquá không?
Isuru

Nó có thể thực hiện nhiều lựa chọn?
Kyle Clegg

32

Vâng ! Cuối cùng tôi đã tìm thấy nó.

triển khai mã sau trên sự kiện nhấp vào nút của bạn, để bật lên bảng hành động như được đưa ra trong hình ảnh được đề cập.

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

hi Sagar, nhờ mã, DatePickerDoneClick nút sự kiện, làm thế nào để khai báo nó nhờ
Apache

sagar, làm thế nào để bỏ qua những cửa sổ pop up tờ hành động, và thêm giá trị được lựa chọn vào trường văn bản nhờ
Apache

[aac dimisswithclickedindex] // một cái gì đó giống như phương thức này. (Xem tôi đã đặt một nút done trong bảng hành động và thêm nút mục tiêu done - selector & trong selector đặt mã dimissal.
Sagar R. Kothari

cảm ơn vì đã trả lời sagar, tôi thêm [aac allowWithClickedButtonIndex]; nhưng tôi nhận được cảnh báo: 'UIActionSheet' có thể không phản hồi với '-dismissWithClickedButtonIndex', sau đó tôi tạo phương thức mới cho bộ chọn 'DatePickerDoneClick' như bên dưới - (void) DatePickerDoneClick {NSLog (@ "Đã nhấp xong"); ratings.text = pickerView objectAtIndex: row]} những gì tôi sẽ làm, vì vậy khi tôi nhấp vào nút done UIActionSheet (aac) miễn nhiệm và textfield (ratings.text) được lấp đầy với giá trị được lựa chọn từ bảng chọn nhờ sagar
Apache

1
@Spark là nó có thể đưa ra một số ý tưởng về việc văn bản chọn .. cảm ơn vì bài viết của bạn + 1
vinothp

10

Giải pháp tuyệt vời của Marcio cho câu hỏi này đã giúp ích rất nhiều cho tôi trong việc thêm các lượt xem phụ dưới bất kỳ hình thức nào vào UIActionSheet.

Vì những lý do mà tôi chưa (chưa) hoàn toàn rõ ràng, giới hạn của UIActionSheet chỉ có thể được đặt sau khi nó đã được hiển thị; cả hai giải pháp của sagar và marcio đã giải quyết thành công vấn đề này với thông báo setBounds: CGRectMake (...) được gửi đến bảng hành động sau khi nó được hiển thị.

Tuy nhiên, việc đặt giới hạn UIActionSheet sau khi trang tính đã được hiển thị sẽ tạo ra sự chuyển đổi nhanh chóng khi ActionSheet xuất hiện, nơi nó "bật" vào chế độ xem và sau đó chỉ cuộn trong hơn 40 pixel cuối cùng hoặc lâu hơn.

Khi định kích thước một UIPickerView sau khi thêm các lần xem phụ, tôi khuyên bạn nên gói thông báo setBounds được gửi đến actionSheet bên trong một khối hoạt ảnh. Điều này sẽ làm cho lối vào của actionSheet hiển thị mượt mà hơn.

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

6
Đây là một mẹo tuyệt vời. Dưới ios 4 trở lên, phong cách hoạt hình này "không được khuyến khích" mặc dù theo tài liệu. Trong iOS 4 trở lên, hãy thử cái này thay thế: UIView animateWithDuration: 0,3f delay: 0 options: UIViewAnimationOptionCurveEaseInOut animations: ^ {[actionSheet setBounds: CGRectMake (0,0,320,485)];} complete: NULL];
ceperry

9

Đối với những người đang buộc phải tìm hàm DatePickerDoneClick ... đây là mã đơn giản để loại bỏ Trang tính hành động. Rõ ràng aac phải là ivar (cái nằm trong tệp .h cấy ghép của bạn)


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

9

Tôi thực sự không hiểu tại sao UIPickerViewđang đi vào bên trong a UIActionSheet. Đây có vẻ là một giải pháp lộn xộn và khó xử lý, có thể bị phá vỡ trong một bản phát hành iOS trong tương lai. (Tôi đã từng gặp những thứ như thế này trong một ứng dụng trước đây, nơi mà UIPickerViewnó không được trình bày ở lần nhấn đầu tiên và phải được sửa lại - những câu hỏi kỳ lạ với UIActionSheet).

Những gì tôi đã làm chỉ đơn giản là triển khai một UIPickerViewvà sau đó thêm nó dưới dạng một chế độ xem phụ vào chế độ xem của tôi và làm cho nó hoạt hình di chuyển lên như thể nó đang được trình bày giống như một trang hành động.

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

Đây là lời cảm ơn tuyệt vời. Bạn có thấy điều này hoạt động tốt với iOS 7 không?
avance

1
+1 cho chế độ xem bộ chọn đơn giản tuyệt vời hoạt hình trên màn hình. Nhưng bạn có một lỗi trong mã. Nền chế độ xemTapButton sinh ra trên đầu chế độ xem bộ chọn và ở đó để chặn chế độ xem bộ chọn khỏi sự tương tác của người dùng. những gì bạn thực sự muốn làm là tạo chế độ xem này trên không gian màn hình còn lại mà chế độ xem bộ chọn chưa lấp đầy ... (bạn không thể tạo chế độ xem phía sau chế độ xem bộ chọn như ý bạn muốn)
aZtraL-EnForceR

7

Để thêm vào giải pháp tuyệt vời của marcio, dismissActionSheet:có thể được thực hiện như sau.

  1. Thêm một đối tượng ActionSheet vào tệp .h của bạn, tổng hợp nó và tham chiếu nó trong tệp .m của bạn.
  2. Thêm phương pháp này vào mã của bạn.

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

3

Tôi nghĩ đây là cách tốt nhất để làm điều đó.

ActionSheetPicker-3.0

Đó là khá nhiều những gì mọi người đề xuất, nhưng sử dụng các khối, đó là một liên lạc tốt!


Nếu bạn đọc ở trên, bạn sẽ thấy rằng lớp ActionSheetPicker này xuất hiện ngay từ đầu, do chuỗi này. Vì vậy, đó là cách tốt nhất, nhờ vào giải pháp được chấp nhận (¬_¬). stackoverflow.com/questions/1262574/…
OpenUserX03

2
Có vẻ như apple sắp bắt đầu thực thi quy tắc của họ rằng các bảng hành động không được xếp lớp con khi tôi nhận được thông báo lỗi này - "<Error>: CGContextSetFillColorWithColor: không hợp lệ ngữ cảnh 0x0. Đây là một lỗi nghiêm trọng. Ứng dụng này hoặc một thư viện mà nó sử dụng , đang sử dụng ngữ cảnh không hợp lệ và do đó góp phần làm giảm độ ổn định và độ tin cậy tổng thể của hệ thống. Thông báo này là một phép lịch sự: vui lòng khắc phục sự cố này. Nó sẽ trở thành một lỗi nghiêm trọng trong bản cập nhật sắp tới. "
Stuart P.

@StuartP. xem câu trả lời của tôi
Kyle Clegg

2

Kể từ iOS 8, bạn không thể, nó không hoạt động vì Apple đã thay đổi cách triển khai nội bộ của UIActionSheet. Vui lòng tham khảo Tài liệu Apple :

Ghi chú về phân lớp

UIActionSheet không được thiết kế để phân lớp, bạn cũng không nên thêm các dạng xem vào hệ thống phân cấp của nó . Nếu bạn cần trình bày một trang tính có nhiều tùy chỉnh hơn được cung cấp bởi API UIActionSheet, bạn có thể tạo trang tính của riêng mình và trình bày trang tính đó theo phương thức với presentViewController: animation: complete :.


1

Tôi thích cách tiếp cận được thực hiện bởi Wayfarer và flexaddicted, nhưng nhận thấy (như aZtral) rằng nó không hoạt động vì backgroundTapButton là phần tử duy nhất đang phản hồi tương tác của người dùng. Điều này khiến tôi phải đặt cả ba chế độ xem phụ của anh ấy: _picker, _pickerToolbar và backgroundTapButton bên trong một chế độ xem chứa (cửa sổ bật lên), sau đó được bật và tắt màn hình. Tôi cũng cần nút Hủy trên _pickerToolbar. Dưới đây là các phần tử mã liên quan cho chế độ xem cửa sổ bật lên (bạn cần cung cấp nguồn dữ liệu bộ chọn và các phương thức ủy quyền của riêng mình).

#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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.