我正在努力寻找UIActionSheet问题的优雅解决方案。
我使用UIActionSheets:
UIActionSheet * myChoices = [[UIActionSheet alloc]
initWithTitle:nil
delegate:self
cancelButtonTitle:@"cancel"
destructiveButtonTitle:@"erase"
otherButtonTitles: @"aaa", @"bbb", @"ccc", @"ddd", nil];
问题是,为了发现用户选择的选项,我必须使用:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
switch ([actionSheet tag]) {
case 0: ...
case 1: ...
case 2: ...
case 3: ...
}
}
基于索引的这种情况很可怕,因为如果我改变了aaa,bbb,ccc等的顺序,在动作表上我必须改变大小写顺序。这个指数并不是一个可靠的解决方案。
我试图想象一种方法来做到这一点,并成为独立于索引但没有得到任何满意的解决方案。使用buttonTitleAtIndex也不够好,因为我的应用程序是本地化的,我必须为每个条目测试n个标题。有什么建议吗?
答案 0 :(得分:5)
由于我创建了基于块的UIAlertView
和UIActionSheet
版本,我个人再也不会使用基于代理的Apple版本了。
您可以在我的GitHub存储库中下载我的OHActionSheet
和OHAlertView
类。
因为它们基于 completionBlock 模式,所以它们更具可读性(所有代码都在同一个地方,没有多个UIActionSheets
的常见代理,...),并且功能更强大(因为块也会根据需要捕获它们的上下文。)
NSArray* otherButtons = @[ @"aaa", @"bbb", @"ccc", @"ddd" ];
[OHActionSheet showSheetInView:self.view
title:nil
cancelButtonTitle:@"cancel"
destructiveButtonTitle:@"erase"
otherButtonTitles:otherButtons
completion:^(OHActionSheet* sheet, NSInteger buttonIndex)
{
if (buttonIndex == sheet.cancelButtonIndex) {
// cancel
} else if (buttonIndex == sheet.destructiveButtonIndex) {
// erase
} else {
NSUInteger idx = buttonIndex - sheet.firstOtherButtonIndex;
// Some magic here: thanks to the blocks capturing capability,
// the "otherButtons" array is accessible in the completion block!
NSString* buttonName = otherButtons[idx];
// Do whatever you want with idx and buttonName
}
}];
switch/case
请注意,在完成处理程序中if/else
测试的otherButtons部分,您可以使用idx
测试switch/case
,或使用我的 {{ 3}}类别,这将允许您编写switch/case
- 类似于NSStrings
的代码,因此您可以在OHActionSheet
的完成处理程序中拥有这样的代码:
NSUInteger idx = buttonIndex - sheet.firstOtherButtonIndex;
NSString* buttonName = otherButtons[idx];
[buttonName switchCase:
@"aaa", ^{ /* Some code here to execute for the "aaa" button */ },
@"bbb", ^{ /* Some code here to execute for the "bbb" button */ },
@"ccc", ^{ /* Some code here to execute for the "ccc" button */ },
..., nil
];
编辑:既然最新的LLVM编译器支持新的“Object Literals”语法,您可以使用NSDictionary的紧凑语法执行与ObjcSwitch
相同的操作:
((dispatch_block_t)@{
@"aaa": ^{ /* Some code here to execute for the "aaa" button */ },
@"bbb": ^{ /* Some code here to execute for the "bbb" button */ },
@"ccc": ^{ /* Some code here to execute for the "ccc" button */ },
}[buttonName] ?:^{
/* Some code here to execute for defaults if no case found above */
})();
答案 1 :(得分:3)
我更喜欢通过使用值数组来帮助(尽管没有完全解决)这个问题。它使您至少拥有统一的数据源。因此,通过在viewDidLoad或其他任何内容中为您的值创建数组,并在创建操作表时,可以将其更改为:
//where myValuesArray is an array of strings you declared in viewDidLoad
//myValuesArray = [NSArray arrayWithObjects:@"aaa", @"bbb", @"ccc", @"ddd", nil];
UIActionSheet * myChoices = [[UIActionSheet alloc]
initWithTitle:nil
delegate:self
cancelButtonTitle:@"cancel"
destructiveButtonTitle:@"erase"
otherButtonTitles:nil];
for(NSString *title in myValuesArray)
{
[myChoices addButtonWithTitle:@"LMNOP"];
}
然后在clickedButtonAtIndex中,您正在检查完全相同的数组的索引,我假设是您的选择。使用此功能,您还可以在需要进行更改时更新阵列。我希望这会有所帮助。
答案 2 :(得分:0)
很抱歉为这么老的问题添加了一个迟到的答案,但谷歌搜索“UIActionSheet块”在这里引导所以我想我会与你分享我写的这个简单的块实现。
https://github.com/freak4pc/UIActionSheet-Blocks
干杯!
答案 3 :(得分:0)
老问题,但是对于iOS 8,新的UIAlertController
类允许您使用块创建UIAlertAction
:
let alertController = UIAlertController(title: "Pancakes", message: "Do you like them with:", preferredStyle: .ActionSheet)
alertController.addAction(UIAlertAction(title: "Maple Syrup", style: .Default, handler: { (alert) -> Void in
println("Picked syrup")
}))
alertController.addAction(UIAlertAction(title: "Jam", style: .Default, handler: { (alert) -> Void in
println("Jam? eh?")
}))
alertController.addAction(UIAlertAction(title: "I HATE PANCAKES", style: .Destructive, handler: { (alert) -> Void in
println("You monster.")
}))