ios 在操作表中添加 UIPickerView 和一个按钮 - 如何?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1262574/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Add UIPickerView & a Button in Action sheet - How?
提问by Sagar R. Kothari
My application requires following things to be added in an action sheet.
我的应用程序需要在操作表中添加以下内容。
- UIToolbar
- Button on UIToolbar
- UIPicker Control
- 界面工具栏
- UIToolbar 上的按钮
- UIPicker 控件
I have included an image to understand my requirements.
我已经包含了一个图像来了解我的要求。
Could you please explain, how this can be implemented?
您能否解释一下,如何实现?
采纳答案by Kyle Clegg
Update for iOS 7
iOS 7 更新
Apple docs for UIActionSheet: UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy
UIActionSheet 的 Apple 文档:UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy
I recommend against trying to customize the contents of an ActionSheet, as it can lead to serious invalid context errors in iOS 7. I just spent a few hours working through this problem and ultimately decided to take a different approach. I replaced the call to show the action sheet with a modal view controller containing a simple tableview.
我建议不要尝试自定义 ActionSheet 的内容,因为它会导致 iOS 7 中严重的无效上下文错误。我只花了几个小时来解决这个问题,最终决定采用不同的方法。我用一个包含简单 tableview 的模式视图控制器替换了显示操作表的调用。
There are many ways to accomplish this. Here's one way that I just implemented in a current project. It's nice because I can reuse it between 5 or 6 different screens where I all users to select from a list of options.
有很多方法可以实现这一点。这是我刚刚在当前项目中实施的一种方法。这很好,因为我可以在 5 或 6 个不同的屏幕之间重复使用它,所有用户都可以从选项列表中进行选择。
- Create a new UITableViewController subclass,
SimpleTableViewController
. - Create a UITableViewController in your storyboard (embedded in a navigation controller) and set its custom class to SimpleTableViewController.
- Give the navigation controller for SimpleTableViewController a Storyboard ID of "SimpleTableVC".
- In SimpleTableViewController.h, create an NSArray property that will represent the data in the table.
- Also in SimpleTableViewController.h, create a protocol
SimpleTableViewControllerDelegate
with a required methoditemSelectedatRow:
, and a weak property called delegate of typeid<SimpleTableViewControllerDelegate>
. This is how we will pass the selection back to the parent controller. - In SimpleTableViewController.m, implement the tableview data source and delegate methods, calling
itemSelectedatRow:
intableView:didSelectRowAtIndexPath:
.
- 创建一个新的 UITableViewController 子类,
SimpleTableViewController
. - 在您的故事板中创建一个 UITableViewController(嵌入在导航控制器中)并将其自定义类设置为 SimpleTableViewController。
- 为 SimpleTableViewController 的导航控制器提供“SimpleTableVC”的 Storyboard ID。
- 在 SimpleTableViewController.h 中,创建一个 NSArray 属性来表示表中的数据。
- 同样在 SimpleTableViewController.h 中,创建一个
SimpleTableViewControllerDelegate
具有所需方法的协议itemSelectedatRow:
,以及一个称为类型委托的弱属性id<SimpleTableViewControllerDelegate>
。这就是我们将选择传递回父控制器的方式。 - 在SimpleTableViewController.m,实现tableview中的数据源和委托方法,要求
itemSelectedatRow:
在tableView:didSelectRowAtIndexPath:
。
This approach has the added benefit of being fairly reusable. To use, import the SimpleTableViewController class in your ViewController.h, conform to the SimpleTableViewDelegate, and implement the itemSelectedAtRow:
method. Then, to open the modal just instantiate a new SimpleTableViewController, set the table data and delegate, and present it.
这种方法具有相当可重用的额外好处。使用时,在你的ViewController.h中导入SimpleTableViewController类,符合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];
I create a simple example and posted it on github.
我创建了一个简单的示例并将其发布在 github 上。
Also see Showing actionsheet causes CGContext invalid context errors.
回答by marcio
One more solution:
另一种解决方案:
no toolbar but a segmented control (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)];
没有工具栏,而是一个分段控件(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)];
回答by TimCinel
Even though this question is old, I'll quickly mention that I've thrown together an ActionSheetPicker classwith a convenience function, so you can spawn an ActionSheet with a UIPickerView in one line. It's based on code from answers to this question.
尽管这个问题很老,但我很快就会提到我已经将一个ActionSheetPicker 类与一个方便的函数放在一起,因此您可以在一行中生成一个带有 UIPickerView 的 ActionSheet。它基于此问题的答案中的代码。
Edit: It now also supports the use of a DatePicker and DistancePicker.
编辑:它现在还支持使用 DatePicker 和 DistancePicker。
UPD:
更新:
This version is deprecated: use ActionSheetPicker-3.0instead.
此版本已弃用:请改用ActionSheetPicker-3.0。
回答by Sagar R. Kothari
Yep ! I finally Find it.
是的 !我终于找到了。
implement following code on your button click event, to pop up action sheet as given in the image of question.
在按钮单击事件上实现以下代码,以弹出问题图像中给出的操作表。
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)];
回答by reed
Marcio's excellent solution to this question was of great help to me in adding subviews of any kind to a UIActionSheet.
Marcio 对这个问题的出色解决方案对我向 UIActionSheet 添加任何类型的子视图有很大帮助。
For reasons that are not (yet) entirely clear to me, the bounds of the UIActionSheet can only be set after it has been displayed; both sagar's and marcio's solutions successfully address this with a setBounds:CGRectMake(...) message being sent to the actionsheet afterit is shown.
由于我(还)不完全清楚的原因,UIActionSheet 的边界只能在显示后设置;既萨加尔的和马尔西奥的解决方案,成功地解决了这一带的setBounds:CGRectMake(...)消息被发送到actionsheet后显示它。
However, setting the UIActionSheet bounds after the sheet has been displayed creates a jumpy transition when the ActionSheet appeaars, where it "pops" into view, and then only scrolls in over the final 40 pixels or so.
但是,在显示工作表后设置 UIActionSheet 边界会在 ActionSheet 出现时产生跳跃的过渡,它“弹出”到视图中,然后只滚动到最后 40 像素左右。
When sizing a UIPickerView after adding subviews, I recommend wrapping the setBounds message sent to the actionSheet inside an animation block. This will make the entrance of the actionSheet appear smoother.
添加子视图后调整 UIPickerView 的大小时,我建议将发送到 actionSheet 的 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];
回答by Accilies
For those guys who are tying to find the DatePickerDoneClick function... here is the simple code to dismiss the Action Sheet. Obviously aac should be an ivar (the one which goes in your implmentation .h file)
对于那些想要找到 DatePickerDoneClick 函数的人......这里是关闭操作表的简单代码。显然 aac 应该是一个 ivar(在你的实现 .h 文件中的那个)
- (void)DatePickerDoneClick:(id)sender{
[aac dismissWithClickedButtonIndex:0 animated:YES];
}
回答by Ethan Mick
I don't really understand why the UIPickerView
is going inside a UIActionSheet
. This seems to be a messy and hacky solution, which can be broken in a future iOS release. (I've had things like this break in an app before, where the UIPickerView
wasn't being presented on the first tap and had to be retapped - weird quirks with the UIActionSheet
).
我真的不明白为什么UIPickerView
要进入UIActionSheet
. 这似乎是一个乱七八糟的解决方案,可能会在未来的 iOS 版本中被打破。(我以前在一个应用程序中遇到过这样的UIPickerView
问题,第一次点击时没有显示,必须重新点击 - 奇怪的怪癖UIActionSheet
)。
What I did is simply implement a UIPickerView
and then added it as a subview to my view, and animate it moving up as though it were being presented like an action sheet.
我所做的只是简单地实现 aUIPickerView
然后将其作为子视图添加到我的视图中,并使其向上移动,就好像它像动作表一样呈现。
/// 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;
}];
}
回答by Kyle Clegg
To add to marcio's awesome solution, dismissActionSheet:
can be implemented as follows.
要添加到 marcio 的超棒解决方案,dismissActionSheet:
可以按如下方式实现。
- Add an ActionSheet object to your .h file, synthesize it and reference it in your .m file.
Add this method to your code.
- (void)dismissActionSheet:(id)sender{ [_actionSheet dismissWithClickedButtonIndex:0 animated:YES]; [_myButton setTitle:@"new title"]; //set to selected text if wanted }
- 将 ActionSheet 对象添加到您的 .h 文件,合成它并在您的 .m 文件中引用它。
将此方法添加到您的代码中。
- (void)dismissActionSheet:(id)sender{ [_actionSheet dismissWithClickedButtonIndex:0 animated:YES]; [_myButton setTitle:@"new title"]; //set to selected text if wanted }
回答by Tony
I think this is best way to do it.
我认为这是最好的方法。
Its pretty much what everyone suggest, but uses blocks, which is a nice touch!
它几乎是每个人的建议,但使用块,这是一个很好的接触!
回答by Mutawe
Since iOS 8, you can't, it doesn't work because Apple changed internal implementation of UIActionSheet
. Please refer to Apple Documentation:
从 iOS 8 开始,你不能,它不起作用,因为 Apple 改变了UIActionSheet
. 请参考苹果文档:
Subclassing Notes
UIActionSheet is not designed to be subclassed, norshould you add views to its hierarchy. If you need to present a sheet with more customization than provided by the UIActionSheet API, you can create your own and present it modally with presentViewController:animated:completion:.
子类化注释
UIActionSheet 不是设计为子类化的,也不应该向其层次结构添加视图。如果您需要呈现比 UIActionSheet API 提供的自定义更多的表单,您可以创建自己的表单并使用presentViewController:animated:completion: 以模态方式呈现它。