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? Я проверил но я ничего не нашел на этом

588   15  

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

    Ничего не найдено.