iOS 8을 사용하는 iPad에서 UIAlertController를 올바르게 표시


194

iOS 8.0에서 Apple은 UIActionSheet 를 대체하기 위해 UIAlertController 를 도입 했습니다 . 불행히도 Apple은 그것을 제시하는 방법에 대한 정보를 추가하지 않았습니다. hayaGeek의 블로그에서 관련 항목을 찾았 지만 iPad에서는 작동하지 않는 것 같습니다. 보기가 완전히 잘못되었습니다.

잘못 배치됨 : 잘못 배치 된 이미지

옳은: 여기에 이미지 설명을 입력하십시오

다음 코드를 사용하여 인터페이스에 표시합니다.

    let alert = UIAlertController()
    // setting buttons
    self.presentModalViewController(alert, animated: true)

iPad에 추가 할 수있는 다른 방법이 있습니까? 아니면 애플이 아이 패드를 잊었거나 아직 구현하지 않았습니까?

답변:


284

UIAlertController을 사용하여 팝 오버에서을 표시 할 수 있습니다 UIPopoverPresentationController.

Obj-C에서 :

UIViewController *self; // code assumes you're in a view controller
UIButton *button; // the button you want to show the popup sheet from

UIAlertController *alertController;
UIAlertAction *destroyAction;
UIAlertAction *otherAction;

alertController = [UIAlertController alertControllerWithTitle:nil
                                                      message:nil
                           preferredStyle:UIAlertControllerStyleActionSheet];
destroyAction = [UIAlertAction actionWithTitle:@"Remove All Data"
                                         style:UIAlertActionStyleDestructive
                                       handler:^(UIAlertAction *action) {
                                           // do destructive stuff here
                                       }];
otherAction = [UIAlertAction actionWithTitle:@"Blah"
                                       style:UIAlertActionStyleDefault
                                     handler:^(UIAlertAction *action) {
                                         // do something here
                                     }];
// note: you can control the order buttons are shown, unlike UIActionSheet
[alertController addAction:destroyAction];
[alertController addAction:otherAction];
[alertController setModalPresentationStyle:UIModalPresentationPopover];

UIPopoverPresentationController *popPresenter = [alertController 
                                              popoverPresentationController];
popPresenter.sourceView = button;
popPresenter.sourceRect = button.bounds;
[self presentViewController:alertController animated:YES completion:nil];

Swift 4.2 용으로 편집 할 수는 있지만 블로그를 많이 사용할 수는 있지만 검색 시간을 절약 할 수 있습니다.

 if let popoverController = yourAlert.popoverPresentationController {
                popoverController.sourceView = self.view //to set the source of your alert
                popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) // you can set this as per your requirement.
                popoverController.permittedArrowDirections = [] //to hide the arrow of any particular direction
            }

[alertController.view setTintColor : [UIColor blackColor]];를 사용하십시오. 텍스트가 보이지 않으면 UIAlertController는 기본적으로 창의 색조 색상을 사용하는데,이 예에서는 흰색이고 보이지 않을 수 있습니다.
whyoz

2
iPad에 취소 버튼이 표시되지 않음
Bhavin Ramani

14
팝 오버 컨텍스트에서 팝 오버 외부를 누르면 "취소"가 표시되므로 @BhavinRamani 취소 버튼이 팝 오버에서 자동으로 제거됩니다.
christopherdrum

이것은 굉장합니다, 내 문제는 해결되었습니다! 정말 고맙습니다!
Mahir Tayir

109

iPad에서는 새로운 UIPopoverPresentationController를 사용하여 경고가 팝 오버로 표시됩니다 . sourceView 및 sourceRect 또는 barButtonItem을 사용하여 팝 오버를 표시하기위한 앵커 포인트를 지정해야합니다.

  • barButtonItem
  • sourceView
  • sourceRect

앵커 포인트를 지정하려면 UIAlertController의 UIPopoverPresentationController에 대한 참조를 확보하고 다음과 같이 특성 중 하나를 설정해야합니다.

alertController.popoverPresentationController.barButtonItem = button;

샘플 코드 :

UIAlertAction *actionDelete = nil;
UIAlertAction *actionCancel = nil;

// create action sheet
UIAlertController *alertController = [UIAlertController
                                      alertControllerWithTitle:actionTitle message:nil
                                      preferredStyle:UIAlertControllerStyleActionSheet];

// Delete Button
actionDelete = [UIAlertAction
                actionWithTitle:NSLocalizedString(@"IDS_LABEL_DELETE", nil)
                style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {

                    // Delete
                    // [self deleteFileAtCurrentIndexPath];
                }];

// Cancel Button
actionCancel = [UIAlertAction
                actionWithTitle:NSLocalizedString(@"IDS_LABEL_CANCEL", nil)
                style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
                    // cancel
                    // Cancel code
                }];

// Add Cancel action
[alertController addAction:actionCancel];
[alertController addAction:actionDelete];

// show action sheet
alertController.popoverPresentationController.barButtonItem = button;
alertController.popoverPresentationController.sourceView = self.view;

[self presentViewController:alertController animated:YES
                 completion:nil];

28
"3 가지 중 하나"앵커 포인트 속성이 아닙니다. "sourceView 및 sourceRect 또는 barButtonItem"입니다.
Rolleric

2
롤러 식 +1 Apple의 설명서에는 sourceRect에 관한 내용이 나와 있습니다. "이 속성을 sourceView 속성과 함께 사용하여 팝 오버의 앵커 위치를 지정하십시오. 또는 barButtonItem 속성을 사용하여 팝 오버의 앵커 위치를 지정할 수 있습니다." - developer.apple.com/library/prerelease/ios/documentation/UIKit/...
벤 패치

오. 로그 메시지없이 충돌했습니다. 최소한 컴파일 타임 경고를 제공하지 않는 이유는 무엇입니까 (범용 앱의 경우)?
Mike Keskinov

85

Swift 2에서는 iPhone 및 iPad에 올바르게 표시하기 위해 다음과 같은 작업을 수행하려고합니다.

func confirmAndDelete(sender: AnyObject) {
    guard let button = sender as? UIView else {
        return
    }

    let alert = UIAlertController(title: NSLocalizedString("Delete Contact?", comment: ""), message: NSLocalizedString("This action will delete all downloaded audio files.", comment: ""), preferredStyle: .ActionSheet)
    alert.modalPresentationStyle = .Popover

    let action = UIAlertAction(title: NSLocalizedString("Delete", comment: ""), style: .Destructive) { action in
        EarPlaySDK.deleteAllResources()
    }
    let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel) { action in

    }
    alert.addAction(cancel)
    alert.addAction(action)

    if let presenter = alert.popoverPresentationController {
        presenter.sourceView = button
        presenter.sourceRect = button.bounds
    }
    presentViewController(alert, animated: true, completion: nil)
}

발표자를 설정하지 않으면 iPad에서 -[UIPopoverPresentationController presentationTransitionWillBegin]다음 메시지와 함께 예외가 발생 합니다.

치명적인 예외 : NSGenericException 응용 프로그램에서 UIAlertControllerStyleActionSheet 스타일의 UIAlertController (<UIAlertController : 0x17858a00>)를 제시했습니다. 이 스타일을 가진 UIAlertController의 modalPresentationStyle은 UIModalPresentationPopover입니다. 경보 컨트롤러의 popoverPresentationController를 통해이 팝 오버에 대한 위치 정보를 제공해야합니다. sourceView 및 sourceRect 또는 barButtonItem을 제공해야합니다. 경보 제어기를 제시 할 때이 정보를 알 수없는 경우 UIPopoverPresentationControllerDelegate 메소드 -prepareForPopoverPresentation에서 제공 할 수 있습니다.


26

Swift 3.0 이상 업데이트

    let actionSheetController: UIAlertController = UIAlertController(title: "SomeTitle", message: nil, preferredStyle: .actionSheet)

    let editAction: UIAlertAction = UIAlertAction(title: "Edit Details", style: .default) { action -> Void in

        print("Edit Details")
    }

    let deleteAction: UIAlertAction = UIAlertAction(title: "Delete Item", style: .default) { action -> Void in

        print("Delete Item")
    }

    let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in }

    actionSheetController.addAction(editAction)
    actionSheetController.addAction(deleteAction)
    actionSheetController.addAction(cancelAction)

//        present(actionSheetController, animated: true, completion: nil)   // doesn't work for iPad

    actionSheetController.popoverPresentationController?.sourceView = yourSourceViewName // works for both iPhone & iPad

    present(actionSheetController, animated: true) {
        print("option menu presented")
    }

서랍을 사용하고 있는데 주어진 솔루션을 사용하려고했지만 실패했습니다.
라나 알리 Waseem

작업 시트를 제거하고 경고를 사용하기 때문에 코드가 없습니다. 그러나 내 코드에서는 한 줄만 다릅니다 let actionSheet = UIAlertController (title : "",, message : "", preferredStyle : .actionSheet) 하지만 로그를 기억하지만 서랍으로 인해 충돌이 발생했습니다. 서랍으로 인해 서랍이 열리지 않습니다. 액션 시트. 화면 왼쪽 구석에 열리고 있었기 때문에 문제는 iPad에서만 발생했습니다.
라나 알리 Waseem

15

2018 업데이트

이 이유로 인해 앱이 거부되었으며 매우 빠른 해결 방법은 단순히 작업 시트 사용에서 경고로 변경하는 것이 었습니다.

매력을 일으켜 App Store 테스터를 통과했습니다.

모든 사람에게 적합한 답변은 아닐 수 있지만 이것이 피클에서 빨리 도움이 되길 바랍니다.


1
감사합니다 - 모두 아이 패드 및 아이폰에서 완벽하게 작동
제레미 앤드류스

최상의 솔루션은 아닙니다. 때로는 현대적인 actionSheet 스타일을 사용하려고합니다.
ShadeToD

9

스위프트 4 이상

확장 프로그램을 만들었습니다

extension UIViewController {
  public func addActionSheetForiPad(actionSheet: UIAlertController) {
    if let popoverPresentationController = actionSheet.popoverPresentationController {
      popoverPresentationController.sourceView = self.view
      popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
      popoverPresentationController.permittedArrowDirections = []
    }
  }
}

사용하는 방법:

let actionSheetVC = UIAlertController(title: "Title", message: nil, preferredStyle: .actionSheet)
addActionSheetForIpad(actionSheet: actionSheetVC)
present(actionSheetVC, animated: true, completion: nil)

나는 엑스 코드 11.2.1에 addActionSheerForiPad FUNC 호출 할 수 그것을 시도하지만
라나 알리 Waseem

@ RaanaAliWaseem UIViewController 클래스 내에서 이것을 호출하고 있습니까?
ShadeToD

예. UIViewController 클래스에서 호출합니다. 그러나 기본 클래스와 UIViewController에서 상속 된 기본 클래스로 상속됩니다.
라나 알리 와심

8

빠른 해결책은 다음과 같습니다.

NSString *text = self.contentTextView.text;
NSArray *items = @[text];

UIActivityViewController *activity = [[UIActivityViewController alloc]
                                      initWithActivityItems:items
                                      applicationActivities:nil];

activity.excludedActivityTypes = @[UIActivityTypePostToWeibo];

if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
    //activity.popoverPresentationController.sourceView = shareButtonBarItem;

    activity.popoverPresentationController.barButtonItem = shareButtonBarItem;

    [self presentViewController:activity animated:YES completion:nil];

}
[self presentViewController:activity animated:YES completion:nil];

3
이 질문은 UIActivityViewController가 아니라 UIAlertController에 관한 것입니다
Roman

UIActivityViewController와 함께 Swift 3에 대한 답변을 업데이트 할 수 있습니까?
Dia

7

스위프트 5

iPhone에는 "actionsheet"스타일을, iPad에는 "alert"스타일을 사용했습니다. 화면 중앙에 iPad가 표시됩니다. sourceView를 지정하거나 어디서나 뷰를 고정 할 필요가 없습니다.

var alertStyle = UIAlertController.Style.actionSheet
if (UIDevice.current.userInterfaceIdiom == .pad) {
  alertStyle = UIAlertController.Style.alert
}

let alertController = UIAlertController(title: "Your title", message: nil, preferredStyle: alertStyle)

편집 : ShareToD의 제안에 따라 더 이상 사용되지 않는 "UI_USER_INTERFACE_IDIOM () == UIUserInterfaceIdiom.pad"확인 업데이트


2
iOS 13에서 'UI_USER_INTERFACE_IDIOM ()'은 iOS 13.0에서 더 이상 사용되지 않습니다.-[UIDevice userInterfaceIdiom]을 직접 사용하십시오. 11시 13 분에 UIDevice.current.userInterfaceIdiom == .pad
ShadeToD

이 방법의 한 가지 단점은 경계 바깥 쪽을 클릭 할 때 경고를 해제 할 수 없다는 것입니다.
mliu

2

나를 위해 다음을 추가해야했습니다.

if let popoverController = alertController.popoverPresentationController {
    popoverController.barButtonItem = navigationItem.rightBarButtonItem
}

2
if 문을 생략하고 선택적 체인을 사용할 수 있습니다. alertController.popoverPresentationController? .barButtonItem = navigationItem.rightBarButtonItem
Dale

2

조치 시트를 제시하기 전에 다음 코드를 추가하십시오.

if let popoverController = optionMenu.popoverPresentationController {
    popoverController.sourceView = self.view
    popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
    popoverController.permittedArrowDirections = []
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.