İOS 8 iPad'lerde UIActivityViewController kilitleniyor


288

Şu anda Xcode 6 (Beta 6) ile uygulamamı test ediyorum. UIActivityViewController, iPhone cihazları ve simülatörleri ile iyi çalışır, ancak iPad simülatörleri ve cihazları (iOS 8) ile aşağıdaki günlükleri kilitler

Terminating app due to uncaught exception 'NSGenericException', 
reason: 'UIPopoverPresentationController 
(<_UIAlertControllerActionSheetRegularPresentationController: 0x7fc7a874bd90>) 
should have a non-nil sourceView or barButtonItem set before the presentation occurs.

Hem iOS 7 hem de iOS 8 için iPhone ve iPad için aşağıdaki kodu kullanıyorum

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];

Bir diğer uygulamamda da benzer bir kilitlenme görüyorum. Bana rehberlik edebilir misiniz? 8'de UIActivityViewController ile bir şey değişti mi? Kontrol ettim ama bu konuda hiçbir şey bulamadım


Aşağıdaki cevaplar deyimi test eder. @ Galen'in cevap vermediğini kullanmalısınız.
doozMen

Yanıtlar:


462

İPad'de aktivite görünümü denetleyicisi yeni kullanılarak popover olarak gösterilecektir UIPopoverPresentationController , bu üç aşağıdaki özelliklerden birini kullanarak popover sunumu için bir çapa noktası belirtmek gerekir:

Bağlantı noktasını belirlemek için UIActivityController'ın UIPopoverPresentationController'ına bir başvuru almanız ve özelliklerden birini aşağıdaki gibi ayarlamanız gerekir:

if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) { 
// iOS8
 activityViewController.popoverPresentationController.sourceView =
parentView;
 }

4
@Daljeet, popover noktasının görünmesini istediğiniz yere 1x1 şeffaf bir görünüm yerleştirmek ve bunu çapa görünümü olarak kullanmaktır.
Mason Cloud

3
O iOS 8 cezası çalışır yukarıda @Thanks mmccomb i kodunuzu uyguladık, ancak iOS 7.i benim app çöker burada stackoverflow bir aynı sorun attılar link: stackoverflow.com/questions/26034149/... Yardım takdir
Daljeet

48
@Daljeet UIActivityController'ın burada bir özellik popoverPresentationController özelliği olmadığından iOS7'de çökecektir. İOS8 ve iOS7'de çalışması için bu kodu kullanın: if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) { // iOS8 activityViewController.popoverPresentationController.sourceView = _shareItem; }
bluebamboo

4
iOS8'de sourceRect benim için çalışmadı. Bu rect ile bir souceView oluşturmak zorunda kaldı ve bu amele para cezası.
Harris

10
@bluebamboo Neden önerinizi cevaba düzenleme olarak eklemiyorsunuz? Bu yorumlarda önemli bilgilerinizi kaçırmak oldukça kolaydır.
Ayush Goel

204

Aynı sorun benim projeme geliyor sonra UIActivityViewControlleriPad açmak için kullanmak zorunda çözüm bulunduUIPopoverController

İşte iPhone ve iPad'de kullanmak için bir kod:

//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];
}

Hızlı 4.2 / hızlı 5 için

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)
}

5
"Daha yeni" Swift sözdizimi için UIPopoverArrowDirectionAny, UIPopoverArrowDirection.Any ve UIUserInterfaceIdiomPhone, UIUserInterfaceIdiom.Phone
EPage_Ed 22:15

1
Çok teşekkürler, bu, EPage_Ed'in yorumlarıyla birlikte, XCode 7 ve SWIFT 2 üzerinde çalışıyor.
Oliver Zhang

1
UIPopoverController iOS 9 ile kullanımdan kaldırıldı
cbartel

3
UIPopOverController iOS 9'da kullanımdan kaldırıldı
Leena

1
Herkes bu şekilde cevap vermelidir, çünkü ios cevapları için hızlıca gitmekten daha kolaydır.
MBH

42

Geçenlerde UIActivityViewControlleriPhone'da iyi çalıştığı ancak iPad'leri simüle ederken çökmelere neden olan Swift 2.0'da bu tam sorunla (orijinal soru) karşılaşıyordum .

En azından Swift 2.0'da bir if ifadesine ihtiyacınız olmadığını buradaki cevaplar dizisine eklemek istiyorum. Sadece popoverPresentationControlleristeğe bağlı yapabilirsiniz .

Hızlı bir yana, kabul edilen cevap sadece bir sourceView, sadece bir sourceRect veya sadece bir barButtonItem olabileceğini söylüyor gibi görünüyor, ancak Apple'ın UIPopoverPresentationController belgelerine göre aşağıdakilerden birine ihtiyacınız var:

  • barButtonItem
  • sourceView ve sourceRect

Üzerinde çalıştığım belirli bir örnek aşağıdadır, burada UIView(sourceView ve sourceRect için) ve String(UIActivityViewController'ın tek activityItem) işlevini yerine getiririm.

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)
}

Bu kod iPhone ve iPad'de (ve hatta sanırım tvOS'ta) çalışır - cihaz desteklemiyorsa popoverPresentationController, bahsi geçen iki kod satırı aslında yok sayılır.

İPad'lerin çalışması için yapmanız gereken tek şey sadece iki satır kod eklemek ya da bir barButtonItem kullanıyorsanız sadece bir kod eklemek!


2
Bu çözüm, kullanmak zorunda olan diğer çözümlerden çok daha temiz görünüyor respondsToSelectorya UIUserInterfaceIdiomda Swift'i bir dil olarak çok daha iyi uyuyor gibi görünüyor. Her ne kadar respondsToSelectoriOS7 için gerekli gibi görünse de, iOS'un daha yeni sürümlerini kullanıyorsanız bu kesinlikle gitmenin yolu gibi görünüyor.
Marcus

18

Swift kodunu kullanırken birçok insanın iPhone / iPad vb. Kodlamasını görüyorum.

Bu gerekli değildir, dil özelliklerini kullanmanız gerekir. Aşağıdaki kod, bir UIBarButtonItem kullanacağınızı ve hem iPhone hem de iPad'de çalışacağınızı varsayar .

@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)
 }

Nasıl If ifadeleri veya başka çılgınca bir şey olduğuna dikkat edin. İsteğe bağlı açma işlemi iPhone'da sıfır olacaktır, bu nedenle hat vc.popoverPresentationController?iPhone'larda hiçbir şey yapmaz.


bu öğretici bağlamında nasıl görünecekti: hackingwithswift.com/read/3/2/…
Dave Kliman

1
öğretici popoverPresentationController'dan bahsetmez, bu nedenle kod iPad iOS 9.x'te kilitlenir. Çözüm vc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem, görünüm denetleyicisini sunmadan önce eklemek olacaktır .
Martin Marconcini

merhaba Martin ... Zaten böyle bir çizgi vardı, içinde shareTapped(): vc.popoverPresentationController?.barButtonItem = sender as? UIBarButtonItemher ikisi de hala çöktü. Neyi yanlış yapıyorum? Ben buradayken, pop-up'ı Facebook, twitter gibi farklı paylaşım hizmetleriyle nasıl doldururum?
Dave Kliman

Peki çökme nedir? Kendi sorunuzu göndermek isteyebilirsiniz. Olmadığını kontrol edin sendergerçekten olduğunu UIBarButtonItem. Vc'nin olmadığını kontrol edin nil. Bir ViewController sunup sunmadığınızı kontrol edin. Kullanıcı uygulamayı yüklediyse (otomatik olarak bazılarını hariç tutmaya karar vermediyseniz) hizmetler otomatik olarak doldurulur.
Martin Marconcini

1
@DaveKliman evet, kaldırılan / yeniden adlandırılan IBOutlets ve IBActions söz konusu olduğunda Xcode çok kötü ve başlangıçta çökecek. İOS'ta bunu yapmanın gerçekten farklı bir yolu yok, Xcode ve InterfaceBuilder kullanmanız gerekiyor. "Kod" bir çok şey yapabilirsiniz, ancak bazıları "sürükle ve bırak" gerektirir. Apple, Storyboard'ları ve InterfaceBuilder'ı olabildiğince kullanmanızı istiyor… buna
alışın

10

Xamarin.iOS kullanarak çözüm.

Örneğimde, ekran görüntüsü alıyorum, görüntü üretiyorum ve kullanıcının görüntüyü paylaşmasına izin veriyorum. İPad'deki açılır pencere ekranın ortasına yerleştirilir.

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);

Thanks you so much :) Bir Bağımlılık Hizmeti kullanarak Xamarin Forms ile çalışır
Ricardo Romo

7

Swift, iOS 9/10 (UIPopoverController kullanımdan kaldırıldıktan sonra)

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)

3
Swift 3 bunu desteklemiyor
Maksim Kniazev

5

Swift'te bunu iPad için düzeltmenin en iyi yolu bulduğum gibi yapmaktır.

    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
    }

@ Galen cevabı kullan.
İOS8

5

Bir kodu UIActivityViewControllertıkladığınızda gösterdiğinizde UIBarButtonItemaşağıdaki kodu kullanın:

activityViewController.popoverPresentationController?.barButtonItem = sender

Aksi takdirde, örneğin a gibi başka bir denetim UIButtonkullanırsanız, aşağıdaki kodu kullanın:

activityViewController.popoverPresentationController?.sourceView = sender
activityViewController.popoverPresentationController?.sourceRect = sender.bounds

Belgelerden UIPopoverPresentationController:

var barButtonItem: UIBarButtonItem? { get set }

Popover'ı belirtilen çubuk düğmesi öğesine bağlamak için bu özelliğe bir değer atayın. Sunuldığında, popover'ın oku belirtilen öğeyi gösterir. Alternatif olarak, sourceView ve sourceRect özelliklerini kullanarak popover için bağlantı konumunu belirleyebilirsiniz.


4

Swift 2.0 için düzeltme

    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)
    }

2
UIPopoverController kullanımdan kaldırıldı.
LevinsonTechnologies

1
Teşekkür ederim!! Bana çok yardımcı oldu.
Oscar

4

Hızlı 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)
}

3

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)

    }

2

Objective-C ve kullanımı ile çözüm 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];
        }
    }

1

Sonraki kodu denedim ve çalışıyor:

önce Görünüm Denetleyicinize bir çubuk düğmesi öğesi koyun, ardından bir IBOutlet oluşturun:

@property(weak,nonatomic)IBOutlet UIBarButtonItem *barButtonItem;

sonraki .m dosyasında: yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;


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)

0

Bu çözümü buldum İlk olarak, popover'ı sunan görünüm denetleyiciniz <UIPopoverPresentationControllerDelegate>protokolü uygulamalıdır .

Ardından, popoverPresentationController'nin temsilcisini ayarlamanız gerekir .

Bu işlevleri ekleyin:

- (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;
}

0

İphone ve ipad çalışma kodu aşağıdaki hızlı 4. Belgelere göre

Verilen aygıt deyimine uygun araçları kullanarak görünüm denetleyicisini sunmak ve kapatmak sizin sorumluluğunuzdadır. İPad'de, görünüm denetleyicisini bir popover'da sunmalısınız. Diğer cihazlarda, modal olarak sunmalısınız.

 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)

0

Swift 5 kullanıyorum. İPad'deki uygulamamda "Paylaş düğmesini" tıkladığımda aynı sorunla karşılaştım. Bu çözümü buldum. adım 1: Main.storyboard'a "view" nesnesini ekleyin (nesne kütüphanesinde "UIView" kelimesini arayın). Adım 2: ViewController.swift içinde bir @IBOutlet oluşturun ve herhangi bir ad atayın (örneğin: view1)

3. adım: sourceView olarak yukarıdaki adı (ör: view1) ekleyin. bu benim "Paylaş düğmesi" eylemim.

@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)


}

Hızlı bir şekilde yeniyim ve bir hafta boyunca takılıp kaldım. umarım bu birisine yardım eder. yani bu çözümü paylaşmak.


Teşekkürler bu çalıştı!
Jnguyen22

-1

Swift 2.0 için. Popover'ı iPad'deki bir paylaşım düğmesine tutturmaya çalışıyorsanız bunun işe yaradığını gördüm. Bu, araç çubuğunuzdaki paylaş düğmesi için bir çıkış oluşturduğunuzu varsayar.

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)
        }

    }
}

-5

Hızlı kullanarak iPad için geliştiriyorsanız dikkatli olun, hata ayıklamada iyi çalışır, ancak sürümde kilitlenir. TestFlight ve AppStore ile çalışmasını sağlamak için, hızlı kullanım -noneiçin optimizasyonun sürüm için devre dışı bırakılmasını sağlayın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.