问题
I set a UITableViewController to be displayed in a popover on iPad :
When I click on a row, I display an alert to warn the user of a potential destructive action. I used the new UIAlertController, and here is what happens:
The popover becomes very small (the size of the alertController view in fact). If I press Cancel, I can see the result :
Here is my code:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var previouslySelectedCell: UITableViewCell?
if checkedIndexPath != nil {
previouslySelectedCell = tableView.cellForRowAtIndexPath(checkedIndexPath)
}
var selectedCell = tableView.cellForRowAtIndexPath(indexPath)
let selectedCurrency = PortfolioCurrencyStore.sharedStore().allCurrencies[indexPath.row]
if selectedCurrency.symbol != GlobalSettings.sharedStore().portfolioCurrency {
// Warning : changing the portfolio currency will reset the portfolio
var resetWarning = UIAlertController(title: NSLocalizedString("Currency Picker VC:AS title", comment: "Changing currency will reset portfolio"), message: nil, preferredStyle: .ActionSheet)
// destructive button
let resetAction = UIAlertAction(title: NSLocalizedString("Currency Picker VC:AS destructive", comment: "Destructive button title"), style: .Destructive, handler: { (action: UIAlertAction!) in
// Remove checkmark from the previously marked cell
previouslySelectedCell?.accessoryType = .None
// Add checkmark to the selected cell
selectedCell?.accessoryType = .Checkmark
self.checkedIndexPath = indexPath
// Animate deselection of cell
self.tableView.deselectRowAtIndexPath(indexPath, animated:true)
// Stock the portfolio currency as NSUserDefaults
GlobalSettings.sharedStore().portfolioCurrency = selectedCurrency.symbol // link between portfolioCurrency as a String and currency.symbol as the property of a Currency instance.
// Delete all items from the StockStore
StockStore.sharedStore().removeAllStocks()
println("StockStore : all entries were deleted")
// Reload tableView
self.tableView.reloadData()
})
// cancel button
let cancelAction = UIAlertAction(title: NSLocalizedString("Currency Picker VC:AS cancel", comment: "Cancel button title"), style: .Cancel, handler:nil)
resetWarning.addAction(resetAction)
resetWarning.addAction(cancelAction)
presentViewController(resetWarning, animated: true, completion: nil)
} else {
// Animate deselection of cell
tableView.deselectRowAtIndexPath(indexPath, animated:true)
}
}
Did I miss something ?
Thanks for your help
回答1:
Found it ! If this AlertController is presented inside a popover, it must provide the location information, either a sourceView and sourceRect, or a barButtonItem.
Like
resetWarning.popoverPresentationController?.sourceView = selectedCell?.contentView
resetWarning.popoverPresentationController?.sourceRect = selectedCell!.contentView.frame
My code had to look like that:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var previouslySelectedCell: UITableViewCell?
if checkedIndexPath != nil {
previouslySelectedCell = tableView.cellForRowAtIndexPath(checkedIndexPath)
}
var selectedCell = tableView.cellForRowAtIndexPath(indexPath)
let selectedCurrency = PortfolioCurrencyStore.sharedStore.allCurrencies[indexPath.row]
if selectedCurrency.symbol != GlobalSettings.sharedStore.portfolioCurrency {
// Warning : changing the portfolio currency will reset the portfolio
var resetWarning = UIAlertController(title: NSLocalizedString("Currency Picker VC:AS title", comment: "Changing currency will reset portfolio"), message: nil, preferredStyle: .ActionSheet)
// destructive button
let resetAction = UIAlertAction(title: NSLocalizedString("Currency Picker VC:AS destructive", comment: "Destructive button title"), style: .Destructive, handler: { (action: UIAlertAction!) in
// Remove checkmark from the previously marked cell
previouslySelectedCell?.accessoryType = .None
// Add checkmark to the selected cell
selectedCell?.accessoryType = .Checkmark
self.checkedIndexPath = indexPath
// Animate deselection of cell
self.tableView.deselectRowAtIndexPath(indexPath, animated:true)
// Stock the portfolio currency as NSUserDefaults
GlobalSettings.sharedStore.portfolioCurrency = selectedCurrency.symbol // link between portfolioCurrency as a String and currency.symbol as the property of a Currency instance.
// Delete all items from the StockStore
StockStore.sharedStore.removeAllStocks()
println("StockStore : all entries were deleted")
// Delete all items from the CurrencyRateStore
CurrencyRateStore.sharedStore.deleteAllRates()
println("CurrencyStore : all entries were deleted")
// Delete all items from the SalesJournal
SalesJournal.sharedStore.removeAllEntries()
println("SalesJournal : all Sales journal entries were deleted")
// Reload tableView
self.tableView.reloadData()
// On Regular sizes, the currency picker is presented inside a popover : reloadData of the List View
NSNotificationCenter.defaultCenter().postNotificationName("CurrencyPickerVC_PortfolioCurrencyDidChangeNotification", object:nil, userInfo:nil)
// Animate deselection of cell
tableView.deselectRowAtIndexPath(indexPath, animated:true)
// Return to root VC
self.navigationController?.popToRootViewControllerAnimated(true)
})
// cancel button
let cancelAction = UIAlertAction(title: NSLocalizedString("Currency Picker VC:AS cancel", comment: "Cancel button title"), style: .Cancel, handler: { (alertAction: UIAlertAction!) -> Void in
// Animate deselection of cell
self.tableView.deselectRowAtIndexPath(indexPath, animated:true)
})
resetWarning.addAction(resetAction)
resetWarning.addAction(cancelAction)
// If this AlertController is presented inside a popover, it must provide the location information, either a sourceView and sourceRect or a barButtonItem.
resetWarning.popoverPresentationController?.sourceView = selectedCell?.contentView
resetWarning.popoverPresentationController?.sourceRect = selectedCell!.contentView.frame
presentViewController(resetWarning, animated: true, completion: nil)
} else {
// Animate deselection of cell
tableView.deselectRowAtIndexPath(indexPath, animated:true)
}
}
Now the image looks like this:
回答2:
I had the same problem and wasn't able to figure out how to prevent the popover from resizing. Using an Alert instead of an Action Sheet will also cause the popover to resize. The workaround I found was to use an Action Sheet as a popover itself by setting the Modal Presentation Style to UIModalPresentationPopover
. I know you're using Swift but my code is Objective-C; hopefully it will be easy for you to translate:
- (UIAlertController *)modalAlertWithTitle:(NSString *)title andMessage:(NSString *)message fromViewController:(UIViewController *)sender {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleActionSheet];
// This will turn the Action Sheet into a popover
[alertController setModalPresentationStyle:UIModalPresentationPopover];
// Set Modal In Popover to YES to make sure your popover isn't dismissed by taps outside the popover controller
[alertController setModalInPopover:YES];
// Get the PopoverPresentationController and set the source View and Rect so the Action Sheet knows where to pop up
UIPopoverPresentationController *popPresenter = [alertController popoverPresentationController];
popPresenter.sourceView = sender.view;
popPresenter.sourceRect = sender.view.bounds;
return alertController;
}
It's very important that you remember to set your cancel button's UIAlertAction style to Default. If you set the style to Cancel it won't appear on the action sheet since this uses a ModalPresentationPopover. Users also won't be able to cancel by tapping outside the Action Sheet since we set ModalInPopover to YES. Setting the cancel button's style to Default will ensure it appears on the sheet.
I just made this as a utility method in my AppDelegate so I could call it from all of my popovers. This works but isn't really an ideal solution because if something causes an Alert to fire while one of your popovers is up, it might get resized. Please let me know if you figure out how to prevent the resizing from occurring at all. Best of luck!
来源:https://stackoverflow.com/questions/25805608/present-a-uialertcontroller-from-within-a-popover-in-ios8