苹果在WWDC 2014 session video的a look inside presentation controllers一讲中,展示了如何使用UIAlertController,看起来挺简单,但在实际用的时候,问题不少,原因是苹果并没有详细对其进行说明,因此不得不探索一番。
对于Alert样式的UIAlertController,没有什么问题(在不同设备上及在处理屏幕旋转问题上,都没问题)。但,ActionSheet样式的UIAlertController却出现了一些问题(在iPhone、iPod touch上没问题,但在iPad上有问题),使用起来有些不太容易,这里会对在iPad上如何使用ActionSheet样式的UIAlertController进行较为详细的说明。
按照session video中提供的示例代码,写出一个示例工程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
@interface
ViewController
(
)
@property
(
nonatomic
,
strong
)
UIAlertController
*alert
;
@property
(
nonatomic
,
strong
)
UIAlertController
*actionSheet
;
@property
(
nonatomic
,
weak
)
IBOutlet
UIButton
*showAlertBtn
;
@property
(
nonatomic
,
weak
)
IBOutlet
UIButton
*showActionSheetBtn
;
@end
@implementation
ViewController
-
(
void
)
viewDidLoad
{
[
super
viewDidLoad
]
;
self
.
alert
=
[
UIAlertController
alertControllerWithTitle
:
@"标题"
message
:
@"消息"
preferredStyle
:UIAlertControllerStyleAlert
]
;
UIAlertAction
*act1
=
[
UIAlertAction
actionWithTitle
:
@"取消"
style
:UIAlertActionStyleCancel
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
UIAlertAction
*act2
=
[
UIAlertAction
actionWithTitle
:
@"确定"
style
:UIAlertActionStyleDefault
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
UIAlertAction
*act3
=
[
UIAlertAction
actionWithTitle
:
@"销毁"
style
:UIAlertActionStyleDestructive
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
[
self
.
alert
addAction
:act1
]
;
[
self
.
alert
addAction
:act2
]
;
[
self
.
alert
addAction
:act3
]
;
self
.
actionSheet
=
[
UIAlertController
alertControllerWithTitle
:
@"标题"
message
:
@"消息"
preferredStyle
:UIAlertControllerStyleActionSheet
]
;
// 在action sheet中,UIAlertActionStyleCancel不起作用
UIAlertAction
*act4
=
[
UIAlertAction
actionWithTitle
:
@"取消"
style
:UIAlertActionStyleDefault
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
UIAlertAction
*act5
=
[
UIAlertAction
actionWithTitle
:
@"确定"
style
:UIAlertActionStyleDefault
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
UIAlertAction
*act6
=
[
UIAlertAction
actionWithTitle
:
@"销毁"
style
:UIAlertActionStyleDestructive
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
[
self
.
actionSheet
addAction
:act4
]
;
[
self
.
actionSheet
addAction
:act5
]
;
[
self
.
actionSheet
addAction
:act6
]
;
}
-
(
IBAction
)
showAlert
:
(
id
)
sender
{
[
self
presentViewController
:self
.
alert
animated
:YES
completion
:
^
{
}
]
;
}
-
(
IBAction
)
showActionSheet
:
(
id
)
sender
{
[
self
presentViewController
:self
.
actionSheet
animated
:YES
completion
:
^
{
}
]
;
}
@end
|
在iPad模拟器中运行,“妖精”就出现了。
按照惯例,应该显示在中心位置才对啊!但它偏偏显示为这个样子。
点上一点,它自动就消失了!看来,苹果已经实现了消失功能,并不需要自己来写。这个同样适用于alert样式。
此处发现一个现象:点击其它区域,它也会消失,这不是popover的特性么!有图有真像。
想了想,苹果的这一讲,从头到尾,说的是presentation controller,会不会与presentation controller有关呢?再者,苹果有提供UIPresentationController类的子类:UIPopoverPresentationController。试试就知道!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
@interface
ViewController
(
)
<UIPopoverPresentationControllerDelegate>
@property
(
nonatomic
,
strong
)
UIAlertController
*alert
;
@property
(
nonatomic
,
strong
)
UIAlertController
*actionSheet
;
@property
(
nonatomic
,
weak
)
IBOutlet
UIButton
*showAlertBtn
;
@property
(
nonatomic
,
weak
)
IBOutlet
UIButton
*showActionSheetBtn
;
@end
@implementation
ViewController
-
(
void
)
viewDidLoad
{
[
super
viewDidLoad
]
;
self
.
alert
=
[
UIAlertController
alertControllerWithTitle
:
@"标题"
message
:
@"消息"
preferredStyle
:UIAlertControllerStyleAlert
]
;
UIAlertAction
*act1
=
[
UIAlertAction
actionWithTitle
:
@"取消"
style
:UIAlertActionStyleCancel
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
UIAlertAction
*act2
=
[
UIAlertAction
actionWithTitle
:
@"确定"
style
:UIAlertActionStyleDefault
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
UIAlertAction
*act3
=
[
UIAlertAction
actionWithTitle
:
@"销毁"
style
:UIAlertActionStyleDestructive
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
[
self
.
alert
addAction
:act1
]
;
[
self
.
alert
addAction
:act2
]
;
[
self
.
alert
addAction
:act3
]
;
self
.
actionSheet
=
[
UIAlertController
alertControllerWithTitle
:
@"标题"
message
:
@"消息"
preferredStyle
:UIAlertControllerStyleActionSheet
]
;
// 在action sheet中,UIAlertActionStyleCancel不起作用
UIAlertAction
*act4
=
[
UIAlertAction
actionWithTitle
:
@"取消"
style
:UIAlertActionStyleDefault
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
UIAlertAction
*act5
=
[
UIAlertAction
actionWithTitle
:
@"确定"
style
:UIAlertActionStyleDefault
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
UIAlertAction
*act6
=
[
UIAlertAction
actionWithTitle
:
@"销毁"
style
:UIAlertActionStyleDestructive
handler
:
^
(
UIAlertAction
*action
)
{
}
]
;
[
self
.
actionSheet
addAction
:act4
]
;
[
self
.
actionSheet
addAction
:act5
]
;
[
self
.
actionSheet
addAction
:act6
]
;
}
-
(
IBAction
)
showAlert
:
(
id
)
sender
{
[
self
presentViewController
:self
.
alert
animated
:YES
completion
:
^
{
}
]
;
}
-
(
IBAction
)
showActionSheet
:
(
id
)
sender
{
UIPopoverPresentationController
*ppc
=
self
.
actionSheet
.
popoverPresentationController
;
ppc
.
delegate
=
self
;
ppc
.
sourceView
=
self
.
view
;
// 仔细看苹果文档,sourceRect是要与sourceView结合起来使用的。
ppc
.
sourceRect
=
CGRectMake
(
(
CGRectGetWidth
(
ppc
.
sourceView
.
bounds
)
-
2
)
*
0.5f
,
(
CGRectGetHeight
(
ppc
.
sourceView
.
bounds
)
-
2
)
*
0.5f
,
2
,
2
)
;
// 显示在中心位置
[
self
presentViewController
:self
.
actionSheet
animated
:YES
completion
:
^
{
}
]
;
}
#pragma mark - UIPopoverPresentationControllerDelegate
-
(
void
)
prepareForPopoverPresentation
:
(
UIPopoverPresentationController
*
)
popoverPresentationController
{
NSLog
(
@"%s"
,
__PRETTY_FUNCTION__
)
;
}
// Called on the delegate when the popover controller will dismiss the popover. Return NO to prevent the
// dismissal of the view.
-
(
BOOL
)
popoverPresentationControllerShouldDismissPopover
:
(
UIPopoverPresentationController
*
)
popoverPresentationController
{
NSLog
(
@"%s"
,
__PRETTY_FUNCTION__
)
;
return
NO
;
}
// Called on the delegate when the user has taken action to dismiss the popover. This is not called when the popover is dimissed programatically.
-
(
void
)
popoverPresentationControllerDidDismissPopover
:
(
UIPopoverPresentationController
*
)
popoverPresentationController
{
NSLog
(
@"%s"
,
__PRETTY_FUNCTION__
)
;
}
// -popoverPresentationController:willRepositionPopoverToRect:inView: is called on your delegate when the
// popover may require a different view or rectangle.
-
(
void
)
popoverPresentationController
:
(
UIPopoverPresentationController
*
)
popoverPresentationController
willRepositionPopoverToRect
:
(
inout
CGRect
*
)
rect
inView
:
(
inout
UIView
*
*
)
view
{
NSLog
(
@"%s"
,
__PRETTY_FUNCTION__
)
;
}
@end
|
再次运行起来。
如上图,它显示在了所指定的位置,并且,点击其它区域,它也不会消失,为嘛不会消失?看代理方法。
1
2
3
4
|
-
(
BOOL
)
popoverPresentationControllerShouldDismissPopover
:
(
UIPopoverPresentationController
*
)
popoverPresentationController
{
NSLog
(
@"%s"
,
__PRETTY_FUNCTION__
)
;
return
NO
;
}
|
这个方法返回了NO,所以,点击其它区域,它不会消失。
继续折腾。看看旋转屏幕后,会怎样。
“妖精”溃败后又卷土重来啦!这这这,如何是好啊!兵来将挡,水来土掩呗。
仔细看了一看。
代理方法-popoverPresentationController:willRepositionPopoverToRect:inView:不正是那个需要的东东么!看看这个方法的含义就知道啦。对这个方法的实现进行修改。
1
2
3
4
|
-
(
void
)
popoverPresentationController
:
(
UIPopoverPresentationController
*
)
popoverPresentationController
willRepositionPopoverToRect
:
(
inout
CGRect
*
)
rect
inView
:
(
inout
UIView
*
*
)
view
{
NSLog
(
@"%s"
,
__PRETTY_FUNCTION__
)
;
*rect
=
CGRectMake
(
(
CGRectGetWidth
(
(
*view
)
.
bounds
)
-
2
)
*
0.5f
,
(
CGRectGetHeight
(
(
*view
)
.
bounds
)
-
2
)
*
0.5f
,
2
,
2
)
;
// 显示在中心位置
}
|
按照上面代码的实现,我们还是要让它居中显示。看看样子吧。
这不正是我们想要的结果嘛!!!