我正在使用iOS 8的新自适应“Present As Popover”功能。我在StoryBoard中连接了一个简单的segue来进行演示。它适用于iPhone 6 Plus,因为它将视图显示为弹出窗口,而iPhone 4s则显示为全屏视图(工作表样式)。
问题是当显示为全屏视图时,我需要在视图中添加“完成”按钮,以便可以调用dismissViewControllerAnimated。当它显示为弹出窗口时,我不想显示“完成”按钮。
我试着查看了presentationController和popoverPresentationController的属性,但是我找不到任何告诉我它是否实际显示为弹出窗口的内容。
NSLog( @"View loaded %lx", (long)self.presentationController.adaptivePresentationStyle ); // UIModalPresentationFullScreen
NSLog( @"View loaded %lx", (long)self.presentationController.presentationStyle ); // UIModalPresentationPopover
NSLog( @"View loaded %lx", (long)self.popoverPresentationController.adaptivePresentationStyle ); // UIModalPresentationFullScreen
NSLog( @"View loaded %lx", (long)self.popoverPresentationController.presentationStyle ); // UIModalPresentationPopover
adaptivePresentationStyle始终返回UIModalPresentationFullScreen,而presentationStyle始终返回UIModalPresentationPopover
在查看UITraitCollection时,我确实找到了一个名为“_UITraitNameInteractionModel”的特征,当它实际显示为Popover时,它只被设置为1。但是,Apple不通过popoverPresentationController的traitCollection直接访问该特征。
答案 0 :(得分:13)
我发现这样做的最好方法(最不臭)是使用UIPopoverPresentationControllerDelegate
。
•确保将呈现的视图控制器设置为用于管理演示文稿的UIPopoverPresentationControllerDelegate
上的UIPopoverPresentationController
。我使用了故事板,因此请在prepareForSegue:
segue.destinationViewController.popoverPresentationController.delegate = presentedVC;
•在呈现的视图控制器中创建一个属性以跟踪此状态:
@property (nonatomic, assign) BOOL amDisplayedInAPopover;
•添加以下委托方法(或添加到现有的委托方法):
- (void)prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController
{
// This method is only called if we are presented in a popover
self.amDisplayedInAPopover = YES;
}
•最后在viewWillAppear:
- viewDidLoad:
中过早,在viewDidLoad:
和viewWillAppear:
之间调用委托准备方法
if (self.amDisplayedInAPopover) {
// Hide the offending buttons in whatever manner you do so
self.navigationItem.leftBarButtonItem = nil;
}
编辑:更简单的方法!
只需设置代理(确保您的presentVC采用UIPopoverPresentationControllerDelegate
):
segue.destinationViewController.popoverPresentationController.delegate = presentedVC;
并提供方法:
- (void)prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController
{
// This method is only called if we are presented in a popover
// Hide the offending buttons in whatever manner you do so
self.navigationItem.leftBarButtonItem = nil;
}
答案 1 :(得分:10)
我检查了视图布局后是否设置了popoverPresentationController的arrowDirection。就我的目的而言,这种方法效果很好,涵盖了较小屏幕设备上的弹出窗口。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if (popoverPresentationController?.arrowDirection != UIPopoverArrowDirection.Unknown) {
// This view controller is running in a popover
NSLog("I'm running in a Popover")
}
}
答案 2 :(得分:3)
我测试了这篇文章中提出的所有解决方案。对不起,在所有情况下都无效。例如,在iPad中,拆分视图显示样式可以在拖动拆分视图行时更改,因此我们需要特定的通知。 经过几个小时的研究,我发现苹果样品中的溶液(swift): https://developer.apple.com/library/ios/samplecode/AdaptivePhotos/Introduction/Intro.html#//apple_ref/doc/uid/TP40014636
这是obj-c中的相同解决方案。
首先在prepareForSegue函数中设置popoverPresentationController委托。它也可以在MyViewController“init”中设置,但不能在“viewDidLoad”中设置(因为在viewDidLoad之前调用第一个willPresentWithAdaptiveStyle)。
MyViewController *controller = [segue destinationViewController];
controller.popoverPresentationController.delegate = (MyViewController *)controller;
现在,每次iOS更改演示风格时,MyViewController对象都会收到此通知,包括首次演示。以下是在navigationController中显示/隐藏“关闭”按钮的示例实现:
- (void)presentationController:(UIPresentationController *)presentationController
willPresentWithAdaptiveStyle:(UIModalPresentationStyle)style
transitionCoordinator:(nullable id<UIViewControllerTransitionCoordinator>)transitionCoordinator {
if (style == UIModalPresentationNone) {
// style set in storyboard not changed (popover), hide close button
self.topViewController.navigationItem.leftBarButtonItem = nil;
} else {
// style changed by iOS (to fullscreen or page sheet), show close button
UIBarButtonItem *closeButton =
[[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(closeAction)];
self.topViewController.navigationItem.leftBarButtonItem = closeButton;
}
}
- (void)closeAction {
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
答案 3 :(得分:2)
管理视图控制器的UIPresentationController
通过将modalPresentationStyle
设置为UIModalPresentationPopover
来呈现它。
根据UIViewController
reference:
presentsViewController
- 显示此视图的视图控制器 控制器。 (只读)
modalPresentationStyle
- UIModalPresentationPopover:在水平常规环境中,在弹出视图中显示内容的演示文稿样式。背景内容变暗并点击 在popover之外导致popover被解雇。如果你不 想要点击以消除弹出窗口,您可以分配一个或多个视图 相关的passthroughViews属性 UIPopoverPresentationController对象,你可以从中获取 popoverPresentationController属性。
我们可以通过检查horizontalSizeClass
如下(我假设您的按钮是UIBarButtonItem
)
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.presentingViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular)
self.navigationItem.leftBarButtonItem = nil; // remove the button
}
最安全的地方是viewWillAppear:
,presentingViewController
可能是nil
。
答案 4 :(得分:2)
怎么样
if (self.modalPresentationStyle == UIModalPresentationPopover)
这对我有用
答案 5 :(得分:2)
实现此功能的官方方法是首先从视图控制器中删除“完成”按钮,然后在适应紧凑时将视图控制器嵌入导航控制器中,将完成按钮添加为导航项:
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.FullScreen
}
func presentationController(controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
let navigationController = UINavigationController(rootViewController: controller.presentedViewController)
let btnDone = UIBarButtonItem(title: "Done", style: .Done, target: self, action: "dismiss")
navigationController.topViewController.navigationItem.rightBarButtonItem = btnDone
return navigationController
}
func dismiss() {
self.dismissViewControllerAnimated(true, completion: nil)
}
答案 6 :(得分:2)
适用于多任务的解决方案
将呈现控制器指定为popover的代理
...
controller.popoverPresentationController.delegate = controller;
[self presentViewController:controller animated:YES completion:nil];
然后,在控制器中,实现委托方法:
- (void)presentationController:(UIPresentationController *)presentationController willPresentWithAdaptiveStyle:(UIModalPresentationStyle)style transitionCoordinator:(id<UIViewControllerTransitionCoordinator>)transitionCoordinator
{
if (style != UIModalPresentationNone)
{
// Exited popover mode
self.navigationItem.leftBarButtonItem = button;
}
}
- (void)prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController
{
// Entered popover mode
self.navigationItem.leftBarButtonItem = nil;
}
答案 7 :(得分:1)
我的棘手解决方案,效果很好。
在import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
PanResponder,
Animated,
Easing,
Dimensions,
Platform,
TouchableOpacity,
} from 'react-native';
let CIRCLE_RADIUS = 36;
let Window = Dimensions.get('window');
export class App extends Component<{}> {
constructor(props){
super(props);
this.dataDrag = [1,2,3,4];
this.pan = this.dataDrag.map( () => new Animated.ValueXY() );
this.state = {
showDraggable : true,
dropZoneValues : null,
};
}
getPanResponder(index) {
return PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove : Animated.event([null,{
dx : this.pan[index].x,
dy : this.pan[index].y
}]),
onPanResponderRelease : (e, gesture) => {
if(this.isDropZone(gesture)){
this.setState({
showDraggable : false
});
}else{
Animated.spring(
this.pan[index],
{toValue:{x:0,y:0}}
).start();
}
}
});
}
isDropZone(gesture){
var dz = this.state.dropZoneValues;
return gesture.moveY > dz.y && gesture.moveY < dz.y + dz.height;
}
setDropZoneValues(event){
this.setState({
dropZoneValues : event.nativeEvent.layout
});
}
render(){
return (
<View style={styles.mainContainer}>
<View
onLayout={this.setDropZoneValues.bind(this)}
style={styles.dropZone}>
<Text style={styles.text}>Drop me here!</Text>
</View>
{this.dataDrag.map((d, index) => (
<Animated.View
key={index}
{...this.getPanResponder(index).panHandlers}
style={[styles.draggableContainer, this.pan[index].getLayout(), styles.circle]}>
<Text style={styles.text}>Drag {index}</Text>
</Animated.View>
))}
</View>
);
}
}
let styles = StyleSheet.create({
mainContainer: {
flex : 1
},
dropZone : {
height : 100,
backgroundColor:'#2c3e50'
},
text : {
marginTop : 25,
marginLeft : 5,
marginRight : 5,
textAlign : 'center',
color : '#fff'
},
draggableContainer: {
position : 'absolute',
marginTop : Window.height/2 - CIRCLE_RADIUS,
marginLeft : Window.width/2 - CIRCLE_RADIUS,
},
circle : {
backgroundColor : '#1abc9c',
width : CIRCLE_RADIUS*2,
height : CIRCLE_RADIUS*2,
borderRadius : CIRCLE_RADIUS
},
});
的{{1}}。
PopoverViewController
这个想法很简单,Popover的视图大小永远不会等于设备屏幕大小,除非它不是Popover。