Представлення UIAlertController належним чином на iPad за допомогою iOS 8


194

За допомогою iOS 8.0 Apple представила UIAlertController на заміну UIActionSheet . На жаль, Apple не додала жодної інформації про те, як її представити. Я знайшов запис про це в блозі hayaGeek, однак, схоже, це не працює на iPad. Погляд абсолютно не замінений:

Не вказано: Неправильне зображення

Правильно: введіть тут опис зображення

Я використовую наступний код, щоб показати його в інтерфейсі:

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

Чи є інший спосіб додати його для iPad? Або Apple просто забула 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 видаляються з перемикачів автоматично, тому що натискання за межі Popover являє собою "скасувати", в контексті Popover.
christopherdrum

це дивовижно, моя проблема вирішена! Дуже дякую!
Махір Таїр

109

На iPad сповіщення відображатиметься як переповнений за допомогою нового UIPopoverPresentationController , воно вимагає вказати опорну точку для презентації Popover, використовуючи або sourceView та sourceRect, або barButtonItem

  • barButtonItem
  • sourceView
  • sourceRect

Для визначення точки прив’язки вам потрібно отримати посилання на UIAlertController UIPopoverPresentationController UIAlertController і встановити одне з властивостей таким чином:

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
Це не "одна з трьох" властивостей точки прив'язки; це: "або sourceView і sourceRect, або barButtonItem".
Rolleric

2
+1 для Rolleric. У документації Apple зазначено, що стосується sourceRect: "Використовуйте це властивість спільно з властивістю sourceView, щоб вказати місце прив’язки для перепонувача. Як варіант, ви можете вказати місце прив’язки для перепону, використовуючи властивість barButtonItem." - developer.apple.com/library/prerelease/ios/documentation/UIKit/…
Ben Patch

О, чоловіче. Він просто розбився без жодного повідомлення в журналі. Чому б хоча б не надати попередження про час компіляції (для універсальних додатків)?
Майк Кескінов

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 У вашій програмі представлено UIAlertController (<UIAlertController: 0x17858a00>) стилю UIAlertControllerStyleActionSheet. ModalPresentationStyle UIAlertController з цим стилем є 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")
    }

Я використовую ящик, я намагаюся використовувати дане рішення, але не вдалося.
Рана Алі

У мене немає коду, оскільки я видаляю аркуш дій та використовую попередження. Але в моєму коді лише один рядок був іншим, хай actionSheet = UIAlertController (назва: "", повідомлення: "", preferenceStyle: .actionSheet) Але я пам’ятаю журнали, він вийшов з ладу через шухляду, я думаю, що ящик протистоять відкриванню аркуш дій. тому що він відкривався в лівому куті екрана. випуск був лише на iPad.
Rana Ali Waseem

15

Оновлення 2018 року

Я просто відхилив додаток з цієї причини, і дуже швидке рішення було просто перейти від використання аркуша дій до попередження.

Працював зачаровував і здав тестерам App Store просто чудово.

Можливо, це не є підходящою відповіддю для всіх, але я сподіваюся, що це допоможе комусь із вас швидко вийти з соління.


1
Працював чудово на обох iPad та iPhone - Дякую
Джеремі Ендрюс

Це не найкраще рішення. Іноді хочеться використовувати стиль 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)

Я спробую це, але не в змозі викликати func addActionSheerForiPad в xcode 11.2.1
Рана Алі

@RanaAliWaseem називаєте це всередині класу 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
Це питання стосується UIAlertController, а не UIActivityViewController
Роман Труба

Чи можете ви оновити відповідь на Swift 3 разом з UIActivityViewController?
Діа

7

Швидкий 5

Я використовував стиль "actionheet" для iPhone та "alert" для iPad. 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] безпосередньо. Ви повинні змінити його на UIDevice.current.userInterfaceIdiom ==
.pad

Одним із недоліків такого підходу є те, що попередження не
відпускається

2

Мені просто потрібно було додати наступне:

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

2
Ви можете опустити оператор if і використовувати необов'язкове ланцюжок: alertController.popoverPresentationController? .BarButtonItem = navigationItem.rightBarButtonItem
Дейл

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 = []
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.