我目前正在使用Xcode 6(Beta 6)测试我的应用。 UIActivityViewController适用于iPhone设备和模拟器,但与iPad模拟器和设备(iOS 8)崩溃并带有以下日志
Terminating app due to uncaught exception 'NSGenericException',
reason: 'UIPopoverPresentationController
(<_UIAlertControllerActionSheetRegularPresentationController: 0x7fc7a874bd90>)
should have a non-nil sourceView or barButtonItem set before the presentation occurs.
我正在为iOS 7和iOS 8使用以下iPhone和iPad代码
NSData *myData = [NSData dataWithContentsOfFile:_filename];
NSArray *activityItems = [NSArray arrayWithObjects:myData, nil];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:nil applicationActivities:nil];
activityViewController.excludedActivityTypes = @[UIActivityTypeCopyToPasteboard];
[self presentViewController:activityViewController animated:YES completion:nil];
我的其他应用程序也遇到了类似的崩溃。你能指导我吗? iOS 8中的UIActivityViewController有什么变化吗?我查了但是我没有找到任何关于此的内容
答案 0 :(得分:452)
在iPad上,活动视图控制器将使用新的UIPopoverPresentationController显示为弹出窗口,它要求您使用以下三个属性之一为弹出窗口的显示指定锚点:
为了指定锚点,您需要获取对UIActivityController的UIPopoverPresentationController的引用,并设置其中一个属性,如下所示:
if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) {
// iOS8
activityViewController.popoverPresentationController.sourceView =
parentView;
}
答案 1 :(得分:178)
同样的问题来到我的项目然后我找到了在 iPad 中打开UIActivityViewController的解决方案我们必须使用 UIPopoverController
以下是在iPhone和iPad中使用它的代码
//to attach the image and text with sharing
UIImage *image=[UIImage imageNamed:@"giraffe.png"];
NSString *str=@"Image form My app";
NSArray *postItems=@[str,image];
UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:postItems applicationActivities:nil];
//if iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self presentViewController:controller animated:YES completion:nil];
}
//if iPad
else {
// Change Rect to position Popover
UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:controller];
[popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0)inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
对于swift 4.2
func openShareDilog() {
let text = "share text will goes here"
// set up activity view controller
let textToShare = [text]
let activityViewController = UIActivityViewController(activityItems: textToShare, applicationActivities: nil)
activityViewController.excludedActivityTypes = [.airDrop]
if let popoverController = activityViewController.popoverPresentationController {
popoverController.sourceRect = CGRect(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height / 2, width: 0, height: 0)
popoverController.sourceView = self.view
popoverController.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
}
self.present(activityViewController, animated: true, completion: nil)
}
答案 2 :(得分:36)
我最近在Swift 2.0中遇到了这个问题(原始问题),其中UIActivityViewController
适用于iPhone,但在模拟iPad时会导致崩溃。
我只想在这里添加这个答案的帖子,至少在Swift 2.0中,你不需要if语句。您可以选择popoverPresentationController
。
快速地说,接受的答案似乎是说你可以只有一个sourceView,只是一个sourceRect,或者只是一个barButtonItem,但根据Apple's documentation for UIPopoverPresentationController你需要以下其中一个:
我正在处理的特定示例如下所示,我正在创建一个函数,该函数接收UIView
(对于sourceView和sourceRect)和String
(UIActivityViewController的唯一activityItem)。
func presentActivityViewController(sourceView: UIView, activityItem: String ) {
let activityViewController = UIActivityViewController(activityItems: [activityItem], applicationActivities: [])
activityViewController.popoverPresentationController?.sourceView = sourceView
activityViewController.popoverPresentationController?.sourceRect = sourceView.bounds
self.presentViewController(activityViewController, animated: true, completion: nil)
}
此代码适用于iPhone和iPad(我认为甚至是tvOS) - 如果设备不支持popoverPresentationController
,提及它的两行代码基本上都会被忽略。
有点好,你需要做的就是让它适用于iPad只需添加两行代码,或者如果你使用的是barButtonItem就只需要一行代码!
答案 3 :(得分:16)
我看到很多人在使用Swift代码时硬编码iPhone / iPad等。
这不是必需的,您必须使用语言功能。以下代码假定您将使用UIBarButtonItem并将在两者 iPhone和iPad上运行。
@IBAction func share(sender: AnyObject) {
let vc = UIActivityViewController(activityItems: ["hello"], applicationActivities: nil)
vc.popoverPresentationController?.barButtonItem = sender as? UIBarButtonItem
self.presentViewController(vc, animated: true, completion: nil)
}
注意没有If语句或任何其他疯狂的事情。 iPhone上的可选展开将为零,因此行vc.popoverPresentationController?
将无法在iPhone上执行任何操作。
答案 4 :(得分:10)
使用Xamarin.iOS的解决方案。
在我的示例中,我正在进行屏幕捕获,生成图像,并允许用户共享图像。 iPad上的弹出窗口位于屏幕中间。
var activityItems = new NSObject[] { image };
var excludedActivityTypes = new NSString[] {
UIActivityType.PostToWeibo,
UIActivityType.CopyToPasteboard,
UIActivityType.AddToReadingList,
UIActivityType.AssignToContact,
UIActivityType.Print,
};
var activityViewController = new UIActivityViewController(activityItems, null);
//set subject line if email is used
var subject = new NSString("subject");
activityViewController.SetValueForKey(NSObject.FromObject("Goal Length"), subject);
activityViewController.ExcludedActivityTypes = excludedActivityTypes;
//configure for iPad, note if you do not your app will not pass app store review
if(null != activityViewController.PopoverPresentationController)
{
activityViewController.PopoverPresentationController.SourceView = this.View;
var frame = UIScreen.MainScreen.Bounds;
frame.Height /= 2;
activityViewController.PopoverPresentationController.SourceRect = frame;
}
this.PresentViewController(activityViewController, true, null);
答案 5 :(得分:7)
Swift,iOS 9/10(在UIPopoverController弃用之后)
let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
if activityViewController.respondsToSelector(Selector("popoverPresentationController")) {
activityViewController.popoverPresentationController?.sourceView = self.view
}
}
self.presentViewController(activityViewController, animated: true, completion: nil)
答案 6 :(得分:5)
在Swift中为iPad修复此问题,最好的办法就是这样做,我找到了。
let things = ["Things to share"]
let avc = UIActivityViewController(activityItems:things, applicationActivities:nil)
avc.setValue("Subject title", forKey: "subject")
avc.completionWithItemsHandler = {
(s: String!, ok: Bool, items: [AnyObject]!, err:NSError!) -> Void in
}
self.presentViewController(avc, animated:true, completion:nil)
if let pop = avc.popoverPresentationController {
let v = sender as! UIView // sender would be the button view tapped, but could be any view
pop.sourceView = v
pop.sourceRect = v.bounds
}
答案 7 :(得分:4)
修复 Swift 2.0
if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone {
self.presentViewController(activityVC, animated: true, completion: nil)
}
else {
let popup: UIPopoverController = UIPopoverController(contentViewController: activityVC)
popup.presentPopoverFromRect(CGRectMake(self.view.frame.size.width / 2, self.view.frame.size.height / 4, 0, 0), inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
答案 8 :(得分:4)
斯威夫特3:
class func openShareActions(image: UIImage, vc: UIViewController) {
let activityVC = UIActivityViewController(activityItems: [image], applicationActivities: nil)
if UIDevice.current.userInterfaceIdiom == .pad {
if activityVC.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
activityVC.popoverPresentationController?.sourceView = vc.view
}
}
vc.present(activityVC, animated: true, completion: nil)
}
答案 9 :(得分:3)
夫特:
let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)
//if iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone) {
self.presentViewController(activityViewController, animated: true, completion: nil)
} else { //if iPad
// Change Rect to position Popover
var popoverCntlr = UIPopoverController(contentViewController: activityViewController)
popoverCntlr.presentPopoverFromRect(CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0), inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
答案 10 :(得分:2)
如果您在单击UIActivityViewController
时显示UIBarButtonItem
,请使用以下代码:
activityViewController.popoverPresentationController?.barButtonItem = sender
否则,如果您使用其他控件,例如UIButton
,请使用以下代码:
activityViewController.popoverPresentationController?.sourceView = sender
activityViewController.popoverPresentationController?.sourceRect = sender.bounds
从文档到UIPopoverPresentationController
:
var barButtonItem: UIBarButtonItem? { get set }
为此属性分配一个值,以将弹出框锚定到指定的条形按钮项。出现时,弹出框的箭头指向指定的项目。另外,您可以使用sourceView和sourceRect属性指定弹出框的锚点位置。
答案 11 :(得分:1)
SwiftUI 版本
func presentActivityView(items: [Any]){
let activityController = UIActivityViewController(activityItems: items, applicationActivities: nil)
if UIDevice.current.userInterfaceIdiom == .pad{
activityController.popoverPresentationController?.sourceView = UIApplication.shared.windows.first
activityController.popoverPresentationController?.sourceRect = CGRect(x: ScreenSize.width / 3, y: ScreenSize.height / 1.5, width: 400, height: 400)
}
UIApplication.shared.windows.first?.rootViewController?.present(activityController, animated: true, completion: nil)
}
答案 12 :(得分:1)
swift = ios7 / ios8
let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)
//if iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone) {
// go on..
} else {
//if iPad
if activityViewController.respondsToSelector(Selector("popoverPresentationController")) {
// on iOS8
activityViewController.popoverPresentationController!.barButtonItem = self.shareButtonItem;
}
}
self.presentViewController(activityViewController, animated: true, completion: nil)
答案 13 :(得分:1)
Hardik Thakkar用 Swift 5 , XCode 11 回答。
a = [[0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4],
[5, 5, 5, 5, 5, 5]]
b = [[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]]
答案 14 :(得分:1)
Objective-C解决方案,并使用UIPopoverPresentationController
UIActivityViewController *controller = /*Init your Controller*/;
//if iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self presentViewController:controller animated:YES completion:nil];
}
//if iPad
else {
UIPopoverPresentationController* popOver = controller.popoverPresentationController
if(popOver){
popOver.sourceView = controller.view;
popOver.sourceRect = CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0);
[self presentViewController:controller animated:YES completion:nil];
}
}
答案 15 :(得分:0)
我找到了这个解决方案
首先,呈现弹出窗口的视图控制器应该实现<UIPopoverPresentationControllerDelegate>
协议。
接下来,您需要设置popoverPresentationController
代表。
添加以下功能:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Assuming you've hooked this all up in a Storyboard with a popover presentation style
if ([segue.identifier isEqualToString:@"showPopover"]) {
UINavigationController *destNav = segue.destinationViewController;
PopoverContentsViewController *vc = destNav.viewControllers.firstObject;
// This is the important part
UIPopoverPresentationController *popPC = destNav.popoverPresentationController;
popPC.delegate = self;
}
}
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController: (UIPresentationController *)controller {
return UIModalPresentationNone;
}
答案 16 :(得分:0)
我正在使用Swift 5。 在iPad上的应用程序中单击“共享按钮”时,我也遇到了崩溃的问题。找到了这个解决方案。 步骤1:将“视图”对象(在对象库中搜索“ UIView”)添加到Main.storyboard。 步骤2:在ViewController.swift中创建一个@IBOutlet并分配任何名称(例如:view1)
第3步:将上述名称(例如:view1)添加为sourceView。这是我的“共享按钮”操作。
@IBAction func Share(_ sender: Any) {
let activityVC = UIActivityViewController(activityItems: ["www.google.com"], applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = view1
self.present(activityVC, animated: true, completion: nil)
}
我是新手,很快就坚持了一周。希望这会帮助某人。所以分享这个解决方案。
答案 17 :(得分:0)
最好的解决这个问题
let urlstring = "https://apps.apple.com/ae/app/"
let text = "some text for your app"
let url = NSURL(string: urlstring)
let textToShare = [url!,text] as [Any]
let activityViewController = UIActivityViewController(activityItems: textToShare as [Any], applicationActivities: nil)
activityViewController.excludedActivityTypes = [ UIActivity.ActivityType.airDrop, UIActivity.ActivityType.postToFacebook ,UIActivity.ActivityType.postToFlickr,UIActivity.ActivityType.postToTwitter,UIActivity.ActivityType.postToVimeo,UIActivity.ActivityType.mail,UIActivity.ActivityType.addToReadingList]
activityViewController.popoverPresentationController?.sourceView = self.view
activityViewController.popoverPresentationController?.sourceRect = view.bounds
activityViewController.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.down
UIApplication.shared.windows.first?.rootViewController?.present(activityViewController, animated: true, completion: nil)
答案 18 :(得分:0)
在iphone和ipad中运行的以下代码迅速地4。 根据文档
您有责任按照给定的设备习惯用适当的方式展示和关闭视图控制器。 在iPad上,您必须在弹出窗口中显示视图控制器。在其他设备上,必须以模态显示它。
let activityViewController = UIActivityViewController(activityItems: activityitems, applicationActivities: nil)
if UIDevice.current.userInterfaceIdiom == .pad {
if activityViewController.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
activityViewController.popoverPresentationController?.sourceView = self.view
}
}
self.present(activityViewController, animated: true, completion: nil)
答案 19 :(得分:0)
我尝试了下一个代码并且可行:
首先在View Controller中放置一个条形按钮项 然后创建一个IBOutlet:
@property(weak,nonatomic)IBOutlet UIBarButtonItem *barButtonItem;
yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;
答案 20 :(得分:-1)
对于Swift 2.0。我发现如果你试图将popover锚定到iPad上的分享按钮,这是有效的。这假设您已在工具栏中为共享按钮创建了一个插座。
func share(sender: AnyObject) {
let firstActivityItem = "test"
let activityViewController = UIActivityViewController(activityItems: [firstActivityItem], applicationActivities: nil)
if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone {
self.presentViewController(activityViewController, animated: true, completion: nil)
}
else {
if activityViewController.respondsToSelector("popoverPresentationController") {
activityViewController.popoverPresentationController!.barButtonItem = sender as? UIBarButtonItem
self.presentViewController(activityViewController, animated: true, completion: nil)
}
}
}
答案 21 :(得分:-5)
如果您使用swift开发iPad,请小心,它在调试时可以正常工作,但在发布时会崩溃。为了使其与testFlight和AppStore一起使用,请使用-none
禁用针对swift的优化以进行发布。