Uiactivityviewcontroller сбой на iOS 8 iPads
в настоящее время я тестирую свое приложение с помощью 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.
Я использую следующий код для iPhone и iPad как для iOS 7, так и для iOS 8
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];
Я получаю аналогичный сбой в одном из моих других приложений, а также. Не могли бы вы проводить меня ? что-нибудь изменилось с UIActivityViewController в iOS 8? Я проверил но я ничего не нашел на этом
15 ответов:
на iPad контроллер вида активности будет отображаться как поповер с помощью нового UIPopoverPresentationController, требуется указать точку привязки для представления popover с помощью одного из трех следующих свойств:
чтобы указать точку привязки, вам нужно будет получить ссылка на UIPopoverPresentationController UIActivityController и установить одно из свойств следующим образом:
if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) { // iOS8 activityViewController.popoverPresentationController.sourceView = parentView; }
та же проблема пришла в мой проект, тогда я нашел решение, чтобы открыть UIActivityViewController в iPad мы должны использовать 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]; }быстро
let imageURL: URL = URL(string: product.images[0].fullImageUrlString)! let objectsToShare: [AnyObject] = [imageURL as AnyObject] let activityViewController = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil) activityViewController.popoverPresentationController?.sourceView = self.view activityViewController.excludedActivityTypes = [.airDrop] self.present(activityViewController, animated: true, completion: nil)
недавно я столкнулся с этой точной проблемой (исходный вопрос) в Swift 2.0, где
UIActivityViewControllerработал нормально для iPhones, но вызывал сбои при моделировании iPads.Я просто хочу добавить к этому потоку ответов здесь, что, по крайней мере, в Swift 2.0, вам не нужен оператор if. Вы можете просто сделать
popoverPresentationControllerнеобязательно.как быстро в сторону, принятый ответ, похоже, говорит о том, что у вас может быть только sourceView, просто sourceRect или просто a barButtonItem, но согласно документация Apple для UIPopoverPresentationController вам нужно одно из следующих действий:
- barButtonItem
- sourceView и sourceRect
конкретный пример, над которым я работал ниже, где я создаю функцию, которая принимает
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, две строки кода, которые упоминают его, по существу игнорируются.приятно, что все, что вам нужно сделать, чтобы заставить его работать для iPads, это просто добавить две строки кода или только один, если вы используете barButtonItem!
Я вижу много людей, жестко кодирующих iPhone / iPad и т. д. при использовании Swift-кода.
это не нужно, вы должны использовать языковые функции. Следующий код предполагает, что вы будете использовать 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?ничего не будет делать на айфонах.
решение с использованием Xamarin.усвн.
в моем примере я делаю снимок экрана, создавая изображение и позволяя пользователю делиться изображением. Всплывающее окно на 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);
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)
в 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 }
исправить на 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) }
Swift 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) }
Swift:
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) }
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)
Я нашел это решение Во-первых, ваш контроллер представления, который представляет popover, должен реализовать
<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; }
я попробовал следующий код и он работает:
сначала поместите элемент кнопки панели в контроллер вида затем создайте IBOutlet:
@property(weak,nonatomic)IBOutlet UIBarButtonItem *barButtonItem;следующий .файл м:
yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;
Для Swift 2.0. Я обнаружил, что это работает, если вы пытаетесь привязать popover к кнопке share на 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) } } }
будьте осторожны, если вы разрабатываете для iPad с помощью swift, он будет работать нормально в отладке, но выйдет из строя в выпуске. Чтобы заставить его работать с testFlight и AppStore, отключите оптимизацию для swift с помощью
-noneдля выхода.
Comments