私は現在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で何か変わったことはありますか?私はチェックしたが、私はこれには何も見つからなかった
IPadでは、アクティビティビューコントローラは新しい UIPopoverPresentationController を使用してポップオーバーとして表示されます。以下の3つのうちの1つ
アンカーポイントを指定するには、UIActivityControllerのUIPopoverPresentationControllerへの参照を取得し、次のいずれかのプロパティを設定する必要があります。
if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) {
// iOS8
activityViewController.popoverPresentationController.sourceView =
parentView;
}
同じ問題が私のプロジェクトに来て、私は 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)
}
私は最近Swift 2.0でこの正確な問題(元の質問)に遭遇していました。そこではUIActivityViewController
はiPhoneのためにうまく働きましたが、iPadをシミュレートするときにクラッシュを引き起こしました。
少なくともSwift 2.0では、ifステートメントは必要ありません。 popoverPresentationController
をオプションにすることができます。
余談ですが、受け入れられた答えは、sourceViewだけ、sourceRectだけ、またはbarButtonItemだけでもよいと言っているようですが、 UIPopoverPresentationController に関するAppleの資料によると、次のいずれかが必要です。以下:
私が取り組んでいた特定の例は以下の通りです。ここでは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
をサポートしていない場合、それを言及している2行のコードは本質的に無視されます。
Kinda iPad用に機能させるために必要な作業は、2行のコードを追加するだけです。barButtonItemを使用している場合は1行だけです。
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ではオプションの展開はゼロになるため、iPhoneではvc.popoverPresentationController?
行は何もしません。
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);
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)
これをiPad用に修正するSwiftでは、私が見つけたこのようにすることが最善の方法です。
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)
}
スイフト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)
}
迅速:
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)
}
UIActivityViewController
をクリックしたときにUIBarButtonItem
を表示した場合は、次のコードを使用してください。
activityViewController.popoverPresentationController?.barButtonItem = sender
それ以外の場合で、別のコントロール(UIButton
など)を使用する場合は、次のコードを使用してください。
activityViewController.popoverPresentationController?.sourceView = sender
activityViewController.popoverPresentationController?.sourceRect = sender.bounds
ドキュメントからUIPopoverPresentationController
へ:
var barButtonItem: UIBarButtonItem? { get set }
このプロパティに値を割り当てて、ポップオーバーを指定したバーボタン項目に固定します。提示されると、ポップオーバーの矢印は指定された項目を指します。あるいは、sourceViewおよびsourceRectプロパティを使用してポップオーバーのアンカー位置を指定することもできます。
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];
}
}
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)
私は次のコードを試してみました、そしてそれは働きます:
まずView Controllerにバーボタン項目を配置してから、IBOutletを作成します。
@property(weak,nonatomic)IBOutlet UIBarButtonItem *barButtonItem;
.mファイルの次の行にyourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;
Swift 4では、以下のコードがiphoneとipadで動作しています。該当する文書
特定のデバイスイディオムに適した方法でView Controllerを表示して閉じることは、あなたの責任です。 iPadでは、PopoverでView Controllerを表示する必要があります。他のデバイスでは、モーダルで表示する必要があります。
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)
私はこの解決策を見つけました最初に、ポップオーバーを提示しているあなたのView Controllerは<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;
}