У моїй заявці потрібно вказати наступні речі в аркуші дій.
- Панель UITool
- Кнопка на панелі UITool
- Управління UIPicker
Я включив зображення, щоб зрозуміти мої вимоги.
Чи можете ви поясніть, як це можна реалізувати?
У моїй заявці потрібно вказати наступні речі в аркуші дій.
Я включив зображення, щоб зрозуміти мої вимоги.
Чи можете ви поясніть, як це можна реалізувати?
Відповіді:
Оновлення для iOS 7
Документи Apple для UIActionSheet :UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy
Я рекомендую не намагатися налаштувати вміст ActionSheet, оскільки це може призвести до серйозних помилок контексту в iOS 7. Я просто провів кілька годин, працюючи над цією проблемою, і врешті вирішив застосувати інший підхід. Я замінив виклик, щоб показати аркуш дій на контролер модального перегляду, що містить простий перегляд таблиці.
Є багато способів досягти цього. Ось один із способів, який я щойно реалізував у поточному проекті. Це приємно, оскільки я можу використовувати його повторно між 5 або 6 різними екранами, де я всіх користувачів вибираю зі списку параметрів.
SimpleTableViewController
.SimpleTableViewControllerDelegate
з необхідним методом itemSelectedatRow:
та слабким властивістю, яке називається делегатом типу id<SimpleTableViewControllerDelegate>
. Ось так ми передамо вибір назад до батьківського контролера.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 .
Ще одне рішення:
не панель інструментів, а сегментоване управління (глаз)
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)];
Незважаючи на те, що це питання давнє, я швидко зазначу, що я зібрав клас ActionSheetPicker з функцією зручності, тож ви можете породжувати Аркуш дій з UIPickerView в одному рядку. Він заснований на коді з відповідей на це питання.
Редагувати: Тепер він також підтримує використання DatePicker та DistancePicker.
ActionSheetDatePicker
режимі на панелі інструментів зверху можна додати кілька кнопок. Це можливо і просто нормально ActionSheetStringPicker
?
Так! Я нарешті знайду це.
застосуйте наступний код у події натискання кнопки, щоб спливати аркуш дій, як вказано на зображенні запитання.
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)];
Відмінне рішення Марсіо в цьому питанні мені дуже допомогло в додаванні підвидів будь-якого виду до таблиці UIAction.
З причин, які мені (поки що) не зовсім зрозумілі, межі таблиці UIAction можна встановити лише після його відображення; і рішення sagar, і marcio успішно вирішують це за допомогою набору setBounds: CGRectMake (...), що надсилається на лист дій після його відображення.
Однак, встановлення меж UIActionSheet після відображення аркуша створює стрибковий перехід, коли з’являється ActionSheet, де він «спливає» у поле зору, а потім прокручується лише протягом останніх 40 пікселів.
Під час розміщення UIPickerView після додавання підпрезентацій я рекомендую перегорнути повідомлення setBounds, надіслане до 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];
Для тих хлопців, які зобов’язані знайти функцію DatePickerDoneClick ... ось простий код для відхилення листів дій. Очевидно, що Aac має бути ivar (тим, що йде у вашому імплементації .h-файлу)
- (void)DatePickerDoneClick:(id)sender{
[aac dismissWithClickedButtonIndex:0 animated:YES];
}
Я не дуже розумію, чому 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;
}];
}
Щоб додати до дивовижного рішення Марсіо, dismissActionSheet:
його можна реалізувати наступним чином.
Додайте цей метод у свій код.
- (void)dismissActionSheet:(id)sender{
[_actionSheet dismissWithClickedButtonIndex:0 animated:YES];
[_myButton setTitle:@"new title"]; //set to selected text if wanted
}
Я думаю, що це найкращий спосіб зробити це.
Це майже все, що всі пропонують, але використовує блоки, що приємне дотик!
Оскільки iOS 8, ви не можете, він не працює, тому що Apple змінила внутрішню реалізацію UIActionSheet
. Будь ласка, зверніться до Документації Apple :
Примітки підкласифікації
UIActionSheet не призначений для підкласів, а також не слід додавати представлення до його ієрархії . Якщо вам потрібно представити аркуш з більшою налаштуваннями, ніж передбачено API UIActionSheet, ви можете створити свій власний та представити його модально разом із presentViewController: animed: завершення :.
Мені сподобався підхід Wayfarer і flexaddicted, але я виявив (як aZtral), що він не працює, оскільки backgroundTapButton був єдиним елементом, який відповідав на взаємодію користувачів. Це призвело до того, що я помістив усі три його підпогляди: _picker, _pickerToolbar та backgroundTapButton всередині перегляду (спливаючого вікна), який потім анімувався на екрані та вимикав його. Також мені потрібна була кнопка Скасувати на панелі _pickerTool. Ось відповідні елементи коду для спливаючого виду (вам потрібно надати власне джерело даних вибору та методи делегування).
#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;
}