iOS 8 iPad에서 UIActivityViewController 충돌


288

현재 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로 변경된 것이 있습니까? 확인했지만 이것에 아무것도 찾지 못했습니다


아래의 답변은 관용구를 테스트합니다. 그렇지 않은 @Galen의 대답을 사용해야합니다.
doozMen

답변:


462

iPad에서 활동보기 컨트롤러는 새로운 UIPopoverPresentationController를 사용하여 팝 오버로 표시됩니다 . 다음 세 가지 특성 중 하나를 사용하여 팝 오버를 표시 할 앵커 포인트를 지정해야합니다.

앵커 포인트를 지정하려면 UIActivityController의 UIPopoverPresentationController에 대한 참조를 가져 와서 속성 중 하나를 다음과 같이 설정해야합니다.

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

4
@Daljeet의 간단한 방법은 팝 오버 지점을 표시하려는 위치에 1x1 투명 뷰를 배치하고 앵커 뷰로 사용하는 것입니다.
메이슨 클라우드

3
이 아이폰 OS 8에서 잘 작동 이상 @Thanks mmccomb, 난 당신의 코드를 적용했지만, 아이폰 OS 7.I에 내 응용 프로그램 충돌이 여기에 유래에 같은 문제를 게시 한 링크는 다음과 같습니다 stackoverflow.com/questions/26034149/...의 도움도 감사합니다
Daljeet

48
@Daljeet UIActivityController에 popoverPresentationController 속성이 없기 때문에 iOS7에서 충돌이 발생합니다. 이 코드를 사용하여 iOS8 및 iOS7에서 작동하게하십시오. if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) { // iOS8 activityViewController.popoverPresentationController.sourceView = _shareItem; }
bluebamboo

4
iOS8에서는 sourceRect가 작동하지 않았습니다. 그 rect로 souceView를 만들어야했고 잘 작동했습니다.
Harris

10
@bluebamboo 답을 수정하여 제안을 추가하지 않겠습니까? 이 의견에서 중요한 정보를 놓치기 쉽습니다.
Ayush Goel

204

같은 문제가 내 프로젝트에 와서 UIActivityViewControlleriPad에서 열어야하는 솔루션을 찾았습니다.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];
}

스위프트 4.2 / 스위프트 5

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
"최신"Swift 구문의 경우 UIPopoverArrowDirectionAny는 UIPopoverArrowDirection.Any 여야하고 UIUserInterfaceIdiomPhone은 UIUserInterfaceIdiom.Phone
EPage_Ed

1
감사합니다. 이것은 EPage_Ed의 의견과 결합하여 XCode 7 및 SWIFT 2에서 작동합니다.
Oliver Zhang

1
UIPopoverController는 iOS 9에서 더 이상 사용되지 않습니다.
cbartel

3
UIPopOverController는 iOS 9에서 더 이상 사용되지 않습니다.
Leena

1
신속한 답변보다 iOS 답변을 탐색하는 것이 더 쉽기 때문에 누구나이 방법으로 답변해야합니다.
MBH

42

UIActivityViewControlleriPhone에서 잘 작동했지만 iPad를 시뮬레이션 할 때 충돌이 발생하는 Swift 2.0에서 최근 에이 정확한 문제 (원래 질문)가 발생 했습니다.

적어도 Swift 2.0에서는 if 문이 필요없는이 답변 스레드에 추가하고 싶습니다. 당신은 popoverPresentationController옵션을 만들 수 있습니다 .

빠른 답변으로 받아 들인 대답은 sourceView, sourceRect 또는 barButtonItem 만 가질 수 있다고 말하고 있지만 UIPopoverPresentationController에 대한 Apple의 문서에 따르면 다음 중 하나가 필요합니다.

  • 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언급 한 두 줄의 코드는 본질적으로 무시됩니다.

iPad에서 작동하도록하려면 두 줄의 코드 만 추가하거나 barButtonItem을 사용하는 경우 한 줄만 추가하면됩니다.


2
이 솔루션을 사용하는 데 다른 솔루션보다 훨씬 청소기 보인다 respondsToSelector또는 UIUserInterfaceIdiom또한 더 나은 언어로 스위프트에 맞게 보인다. 는 있지만 respondsToSelector이 확실히 갈 수있는 방법이 될 것 같다 아이폰 OS의 최신 버전을 사용하는 경우는, iOS7에 필요한처럼 보인다.
Marcus

18

스위프트 코드를 사용하는 동안 많은 사람들이 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에서 0 vc.popoverPresentationController?이 아니므로이 줄 은 iPhone에서 아무 것도 수행하지 않습니다.


방법 것이 튜토리얼의 맥락에서 그 모습 : hackingwithswift.com/read/3/2/...
데이브 Kliman

1
이 튜토리얼에서는 popoverPresentationController를 언급하지 않으므로 iPad iOS 9.x에서 코드가 충돌합니다. 솔루션은 vc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem뷰 컨트롤러를 제시하기 전에 추가하는 것 입니다.
Martin Marconcini

안녕하세요 마틴 ... 난 이미이처럼 보이는 라인을했다,에 shareTapped(): vc.popoverPresentationController?.barButtonItem = sender as? UIBarButtonItem모두 여전히 추락했다. 내가 뭘 잘못하고 있죠? 여기에있는 동안 Facebook, Twitter 등의 다른 공유 서비스로 팝 오버를 채우려면 어떻게해야합니까?
Dave Kliman

그리고 충돌은 무엇입니까? 당신은 당신의 자신의 질문을 게시 할 수 있습니다. sender실제로 확인하십시오 UIBarButtonItem. vc가 아닌지 확인하십시오 nil. 충돌 / 코드를 보지 않고 ViewController를 제시 할 수 있는지 확인하십시오. 사용자가 앱을 설치 한 경우 서비스가 자동으로 채워집니다 (명시 적으로 제외하기로 결정한 경우 제외).
Martin Marconcini

1
@DaveKliman 예, Xcode는 제거 / 이름이 바뀐 IBOutlets 및 IBActions와 관련하여 매우 나쁘며 시작시 충돌합니다. iOS에서는 다른 방법이 없으므로 Xcode와 InterfaceBuilder를 사용해야합니다. "코드에서"많은 것을 할 수 있지만 일부는 "끌어다 놓기"가 필요합니다. 애플은 스토리 보드와 InterfaceBuilder를 최대한 많이 사용하길 원한다. 그래서 익숙해
지자

10

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

정말 고마워 :) 의존성 서비스를 사용하여 Xamarin Forms와 함께 작동
Ricardo Romo

7

스위프트, 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)

3
스위프트 3는 이것을 지원하지 않습니다
Maksim Kniazev

5

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
    }

@Galen 답변을 사용하십시오. iOS8 +를 대상으로 할 때 관용구 검사를 할 필요가 없습니다
doozMen

5

UIActivityViewController클릭 할 때 표시 되면 UIBarButtonItem다음 코드를 사용하십시오.

activityViewController.popoverPresentationController?.barButtonItem = sender

그렇지 않으면 다른 컨트롤 (예 : a UIButton)을 사용하는 경우 다음 코드를 사용하십시오.

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

설명서에서 UIPopoverPresentationController:

var barButtonItem: UIBarButtonItem? { get set }

팝 오버를 지정된 막대 단추 항목에 고정하려면이 특성에 값을 지정하십시오. 표시되면 팝 오버의 화살표가 지정된 항목을 가리 킵니다. 또는 sourceView 및 sourceRect 속성을 사용하여 팝 오버의 앵커 위치를 지정할 수 있습니다.


4

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

2
UIPopoverController는 더 이상 사용되지 않습니다.
LevinsonTechnologies

1
감사합니다!! 그것은 많은 도움이되었습니다.
Oscar

4

스위프트 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

빠른:

    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 및 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

다음 코드를 시도했지만 작동합니다.

먼저 View Controller에 막대 버튼 항목을 넣은 다음 IBOutlet을 작성하십시오.

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

.m 파일의 다음 : yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;


1

스위프트 = 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

이 솔루션을 찾았습니다. 먼저 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;
}

0

아이폰과 아이 패드에서 작동하는 신속한 4 다음 코드에서. 문서에 따르면

주어진 장치 관용구에 적절한 수단을 사용하여 뷰 컨트롤러를 제시하고 해제하는 것은 귀하의 책임입니다. iPad에서는보기 컨트롤러를 팝업으로 표시해야합니다. 다른 장치에서는 모달로 제시해야합니다.

 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를 사용하고 있습니다. iPad의 앱에서 "공유 버튼"을 클릭 할 때 동일한 충돌 문제가 발생했습니다. 이 솔루션을 찾았습니다. 1 단계 : "view"오브젝트를 추가하십시오 (오브젝트 라이브러리에서 "UIView"검색). Main.storyboard에. 2 단계 : ViewController.swift에서 @IBOutlet을 생성하고 이름을 지정하십시오 (예 : view1)

3 단계 : 위의 이름 (예 : view1)을 sourceView로 추가하십시오. 이것은 "공유 버튼"작업입니다.

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


}

나는 아주 빨리 새롭고 일주일 동안 붙어있었습니다. 이것이 누군가를 도울 수 있기를 바랍니다. 이 솔루션을 공유하십시오.


고마워요!
Jnguyen22

-1

스위프트 2.0 나는 당신이 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)
        }

    }
}

-5

swift를 사용하여 iPad 용으로 개발하는 경우 디버그에서는 잘 작동하지만 릴리스에서는 충돌이 발생합니다. testFlight 및 AppStore와 함께 작동하려면 -none릴리스 에 신속하게 사용하도록 최적화를 비활성화하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.