Добавить UIPickerView и кнопку в листе действий - как? - PullRequest
120 голосов
/ 12 августа 2009

Мое приложение требует добавления следующих вещей в лист действий.

  • UIToolbar
  • Кнопка на UIToolbar
  • UIPicker Control

Я включил изображение, чтобы понять мои требования.

alt text

Не могли бы вы объяснить, как это можно реализовать?

Ответы [ 11 ]

111 голосов
/ 15 января 2010

Еще одно решение:

  • нет панели инструментов, но сегментированный элемент управления (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)];
    
75 голосов
/ 07 января 2011

Несмотря на то, что этот вопрос старый, я быстро упомяну, что я собрал класс ActionSheetPicker с удобной функцией, поэтому вы можете создать ActionSheet с UIPickerView в одной строке. Он основан на коде из ответов на этот вопрос.

Редактировать: теперь также поддерживается использование DatePicker и DistancePicker.


UPD:

Эта версия устарела: вместо нее используйте ActionSheetPicker-3.0 .

animation

32 голосов
/ 12 августа 2009

Да! Я наконец-то нашел его.

внедрите следующий код в событие нажатия кнопки, чтобы открыть лист действий, как показано на изображении вопроса.

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)];
25 голосов
/ 02 октября 2013

Обновление для iOS 7

Документы Apple для UIActionSheet : UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy

Я рекомендую не пытаться настроить содержимое ActionSheet, так как это может привести к серьезным ошибкам недопустимого контекста в iOS 7. Я просто потратил несколько часов на решение этой проблемы и в итоге решил использовать другой подход. Я заменил вызов, чтобы показать лист действий модальным контроллером представления, содержащим простое представление таблицы.

Есть много способов сделать это. Вот один из способов, который я только что реализовал в текущем проекте. Это хорошо, потому что я могу повторно использовать его на 5 или 6 разных экранах, где я могу выбрать всех пользователей из списка опций.

  1. Создать новый подкласс UITableViewController, SimpleTableViewController.
  2. Создайте UITableViewController в вашей раскадровке (встроенный в контроллер навигации) и установите для его пользовательского класса значение SimpleTableViewController.
  3. Присвойте контроллеру навигации для SimpleTableViewController идентификатор раскадровки "SimpleTableVC".
  4. В SimpleTableViewController.h создайте свойство NSArray, которое будет представлять данные в таблице.
  5. Также в SimpleTableViewController.h создайте протокол SimpleTableViewControllerDelegate с обязательным методом itemSelectedatRow: и слабым свойством под названием делегат типа id<SimpleTableViewControllerDelegate>. Вот как мы передадим выбор обратно в родительский контроллер.
  6. В SimpleTableViewController.m реализуйте источник данных tableview и делегируйте методы, вызывая itemSelectedatRow: в tableView:didSelectRowAtIndexPath:.

Этот подход имеет дополнительное преимущество, так как его можно использовать многократно. Чтобы использовать, импортируйте класс SimpleTableViewController в ваш ViewController.h, соответствует SimpleTableViewDelegate и реализуйте метод itemSelectedAtRow:. Затем, чтобы открыть модальное окно, просто создайте новый SimpleTableViewController, установите данные таблицы и делегата и представьте его.

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

Я создаю простой пример и разместил его на github .

Также см. Отображение таблицы действий вызывает ошибки недопустимого контекста CGContext .

10 голосов
/ 28 марта 2010

Отличное решение Марсио в этом вопросе мне очень помогло в добавлении любых подпредставлений в UIActionSheet.

По причинам, которые (пока) не совсем ясны для меня, границы UIActionSheet могут быть установлены только после его отображения; Решения Sagar и Marcio успешно решают эту проблему с помощью сообщения setBounds: CGRectMake (...), отправляемого на лист действий , после оно отображается.

Однако установка границ UIActionSheet после отображения листа создает скачкообразный переход, когда появляется ActionSheet, когда он «всплывает» в поле зрения, а затем прокручивает только последние 40 пикселей или около того.

При определении размера UIPickerView после добавления подпредставлений я рекомендую поместить сообщение setBounds, отправленное в actionSheet, в блок анимации. Это сделает вход ActionSheet более плавным.

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]; 
9 голосов
/ 30 мая 2013

Я не очень понимаю, почему UIPickerView входит внутрь UIActionSheet. Это кажется грязным и хакерским решением, которое может быть взломано в будущем выпуске iOS. (У меня были такие вещи, как этот перерыв в приложении, где UIPickerView не был представлен при первом нажатии и должен был быть повторно использован - странные причуды с UIActionSheet).

Я просто реализовал UIPickerView, а затем добавил его в качестве подпредставления к моему представлению и анимировал его, двигаясь вверх, как если бы он был представлен как лист действий.

/// 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;
    }];
}
9 голосов
/ 13 сентября 2010

Для тех парней, которые пытаются найти функцию DatePickerDoneClick ... вот простой код для отклонения листа действий. Очевидно, что aac должен быть иваром (который входит в ваш файл имплементации .h)


- (void)DatePickerDoneClick:(id)sender{
    [aac dismissWithClickedButtonIndex:0 animated:YES];
}
7 голосов
/ 05 сентября 2012

Чтобы добавить к удивительному решению Марсио, dismissActionSheet: может быть реализовано следующим образом.

  1. Добавьте объект ActionSheet в ваш файл .h, синтезируйте его и сделайте ссылку на него в вашем файле .m.
  2. Добавьте этот метод к своему коду.

    - (void)dismissActionSheet:(id)sender{
      [_actionSheet dismissWithClickedButtonIndex:0 animated:YES];
      [_myButton setTitle:@"new title"]; //set to selected text if wanted
    }
    
3 голосов
/ 02 февраля 2013

Я думаю, что это лучший способ сделать это.

ActionSheetPicker-3,0

Это почти то, что все предлагают, но использует блоки, что приятно!

2 голосов
/ 17 августа 2014

Начиная с iOS 8, вы не можете, это не работает, потому что Apple изменила внутреннюю реализацию UIActionSheet. Пожалуйста, обратитесь к Документация Apple :

Примечания по подклассам

UIActionSheet не предназначен для использования в подклассах, или если вы добавите представления в его иерархию . Если вам нужно представить лист с большей настройкой, чем предусмотрено API UIActionSheet, вы можете создать свой собственный и представить его модально с presentViewController: animated: complete:.

...