在Swift中使用的UIActivityViewController在iPad上崩溃

21

我正在我的游戏中创建一个分享功能,代码已经编写完毕并且在iPhone上可以顺利运行,但是当我在iPad上测试该功能时,点击分享按钮会导致应用崩溃。 我正在使用以下代码来实现分享按钮:

let textToShare = "Check out this website!"

if let myWebsite = NSURL(string: "http://www.apple.com/") {
   let objectsToShare = [textToShare, myWebsite]
   let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
   self.view?.window?.rootViewController?.presentViewController(activityVC, animated: true, completion: nil)
}

1
不要只说“应用程序崩溃了”。当它崩溃时,它会告诉你重要的信息。它会告诉你哪些重要的信息? - matt
提供有关崩溃的详细信息。 - rmaddy
5个回答

34

在iPad上运行时,UIActivityViewController的popoverPresentationController属性不为空。因此,请尝试以下方法。

if let wPPC = activityVC.popoverPresentationController {
    wPPC.sourceView = some view
    //  or
    wPPC.barButtonItem = some bar button item
}
presentViewController( activityVC, animated: true, completion: nil )

你会如何改变 Pop Over View 的位置? - Loanb222
1
谢谢,".barButtonItem = some bar button item" 真的是一个很好的方法。 - Volodymyr Sichka
3
知道了,这是需要翻译的内容:“FYI, you don't need the if let here. Optional chaining will work. activityVC.popoverPresentationController?.barButtonItem = whatever”。我的翻译如下:“你不需要在这里使用 if let,可选链就可以工作。activityVC.popoverPresentationController?.barButtonItem = whatever”。 - Daniel T.

4

在 @Satachito 的回答基础上:作为 sourceView,您可以在应该指向弹出窗口的位置创建一个(不可见的)CGRect,并将箭头设置在该方向上:

let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)

if UIDevice.current.userInterfaceIdiom == .pad {
    activityVC.popoverPresentationController?.sourceView = UIApplication.shared.windows.first
    activityVC.popoverPresentationController?.sourceRect = CGRect(x: 0, y: 0, width: 300, height: 350)
    activityVC.popoverPresentationController?.permittedArrowDirections = [.left]
}

UIApplication.shared.windows.first?.rootViewController?.present(activityVC, animated: true, completion: nil)

自 iOS 15.0 起,UIApplicationwindows 属性已被废弃,如果使用场景,则不应在 iOS 13.0 之后使用。 - HangarRash
请注意,从iOS 13.2版本开始,除非您希望sourceRect成为sourceView的特定子集,否则无需设置。 - HangarRash

-1

需要将 popoverPresentationControllersourceView 设置为当前视图。

let activityVC = UIActivityViewController(activityItems: [quoteController.attributedString, view.screenShot()], applicationActivities: [])
    
present(activityVC, animated: true)
activityVC.popoverPresentationController?.sourceView = view


1
当尝试此解决方案时,我会收到“无法在范围内找到视图”的错误。 - Janik Spies

-1
iOS 16准备好的示例,基于之前的示例,不使用已弃用的windows
func shareAppIntent() {
    let subject = "Share with Friends"
    let extraText = "https://apps.apple.com/..."
    
    guard let mainWindowScene = UIApplication.shared.connectedScenes
            .compactMap({ $0 as? UIWindowScene })
            .first(where: { $0.activationState == .foregroundActive }),
          let mainWindow = mainWindowScene.windows.first,
          let rootViewController = mainWindow.rootViewController else {
        return
    }
    
    if let url = URL(string: extraText) {
        let activityViewController = UIActivityViewController(activityItems: [subject, url], applicationActivities: nil)
        
        // iPad needs extra context, otherwise it will crash
        if UIDevice.current.userInterfaceIdiom == .pad {
            activityViewController.popoverPresentationController?.sourceView = mainWindow
            activityViewController.popoverPresentationController?.sourceRect = CGRect(x: 0, y: 0, width: 300, height: 350)
            activityViewController.popoverPresentationController?.permittedArrowDirections = [.left]
        }
        
        rootViewController.present(activityViewController, animated: true, completion: nil)
    }
}

1
  1. 这个问题与“windows”被弃用无关。
  2. 这段代码存在一个严重的缺陷。如果在iPad的分屏模式下运行,代码很容易选择错误的场景并在屏幕的错误一半显示活动控制器。
  3. 如果所选的根视图控制器已经呈现了其他视图控制器,这也会失败。
- HangarRash
尽管最初的问题与“Windows”无关,但提供一个最新的工作示例是合适的。至于你抱怨弹出窗口显示在屏幕错误的一半上,当iPad屏幕分割时,它确实像iPhone上的表单一样显示。你对根视图控制器的引用是正确的,尽管这种情况极为罕见(在我广泛的测试中从未发生过)。我已经适当地编辑了答案。 - Taltus1337
但是在iPad上,你的应用程序可以同时运行两个场景并且你的代码可能会在屏幕的错误一半显示控制器。 - HangarRash
根据目前的写法,你的回答不够清晰。请编辑以添加更多细节,帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

-1
在iPad上,SheetVC不存在。因此,您需要为弹出控制器添加一个源视图。
@objc private func shareButtonTapped(_ sender: UIButton) {
        let image = UIImage(named: "image")
        let activityItem: [AnyObject] = [image as AnyObject]
        let activityViewController = UIActivityViewController(
            activityItems: activityItem as [AnyObject],
            applicationActivities: nil
        )
        if let popoverController = activityViewController.popoverPresentationController {
            popoverController.sourceView = sender
            popoverController.sourceRect = sender.bounds
        }
        present(activityViewController, animated: true, completion: nil)
    }

请不要发布重复的答案。SheetVC是什么? - HangarRash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接