Откройте UISplitViewController для Master View, а не подробно
У меня есть интерфейс разделенного просмотра с целевым приложением iPhone 6. При первом запуске приложения оно открывается в подробном представлении; Я хотел бы, чтобы это открылось в Master View. Я пытался:
self.splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryOverlay
Который был предложен в другом месте (предыдущий вопрос StackOverFlow), но, похоже, он ничего не делает и не открывает главное представление при запуске. Я также попытался добавить следующую строку в мой AppDelegate:
splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
Но, несмотря на возврат true или false ( Другой вопрос переполнения предыдущего стека), я не добился успеха.
Я запустил пример приложения Master-Detail в XCode, и оно загружается в представление Master на основе splitViewController: call returning false; однако, я не уверен, как заставить это работать в более сложном расположении.
9 ответов
стриж
UISplitViewController отображает главный вид выше детализации в книжной ориентации не о показе основного вида, а о представлении подробного представления во всю ширину, под основным видом.
UISplitViewController в портретной ориентации на iPhone демонстрирует детализацию VC, а не мастер о принципе механизма коллапса.
Настоящий ответ адресован:
- Мастер → Деталь(Компактная ширина)
- iPhone 4s, 5, 5s, SE, 6, 6s, 7 (любая ориентация)
- Ipod Touch
- любой айфон плюс (портрет)
- бок о бок(все остальные размеры)
- IPad
- любой айфон плюс (пейзаж)
Вы должны установитьpreferredDisplayMode
, Вы бы хотели это.primaryVisible
если бы он существовал! С помощью .allVisible
iOS выбирает Detail
если подходит только 1 вид (компактная ширина); в этом размере код ниже подберет Master
,
Хитрость заключается в том, чтобы изменить как preferredDisplayMode
в .allVisible
и вернуться true
в collapseSecondary:onto
,
class PrimarySplitViewController: UISplitViewController,
UISplitViewControllerDelegate {
override func viewDidLoad() {
self.delegate = self
self.preferredDisplayMode = .allVisible
}
func splitViewController(
_ splitViewController: UISplitViewController,
collapseSecondary secondaryViewController: UIViewController,
onto primaryViewController: UIViewController) -> Bool {
// Return true to prevent UIKit from applying its default behavior
return true
}
}
iOS 14
Мне не перезвонили
splitViewController(_:collapseSecondary:onto:)
и вместо этого использовал следующий новый метод.
func splitViewController(_ svc: UISplitViewController, topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column) -> UISplitViewController.Column {
return .primary
}
Шаг 1 - Откройте MasterViewController
Шаг 2 - убедитесь, что табличное представление имеет протокол UISplitViewControllerDelegate. Например:
class ListVC: UITableViewController,UISplitViewControllerDelegate {}
Шаг 3 - Добавьте его в ViewDidLoad
splitViewController?.delegate = self
Шаг 4 - Затем переопределите этот метод, чтобы сказать, что главный контроллер вида всегда должен сворачиваться в контроллер подробного вида:
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
return true
}
При первом запуске приложения оно открывается в подробном представлении; Я хотел бы, чтобы это открылось в Master View
Предполагая, что вы хотите это только при первом запуске, но не всегда; например, в случае, когда в главном представлении отображается пустой набор данных; тогда решение так же, как показывает шаблон Master-Detail:
func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController:UIViewController, ontoPrimaryViewController primaryViewController:UIViewController) -> Bool {
guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
if topAsDetailController.detailItem == nil {
// Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return true
}
return false
}
iOS 14
Из WWDC 2020 - Build for iPad вы можете добавить определенный контроллер представления для класса компактной ширины (например, iPhone в портретной ориентации , iPad в режиме Slide Over), установив флажок « Использовать отдельный контроллер представления» в инспекторе атрибутов SplitViewController.
Таким образом, вы можете установить любой контроллер представления в качестве исходного контроллера представления, как хотите, установив переход отношений.
iOS 14 - обновления двухколоночного режима
Некоторое время я боролся с этим, прежде чем в конце концов обнаружил, что контроллер Split View был переработан в iOS14, поэтому ни один из приведенных выше ответов больше не актуален.
Я бы рекомендовал начать с этой статьи:https://www.biteinteractive.com/split-view-controllers-done-right-in-ios-14/
Но если вы ищете быстрое решение:
- Вам нужно будет установить отношение «компактный контроллер представления» на вашем контроллере разделения представления. Вы можете сделать это, щелкнув правой кнопкой мыши контроллер разделения представления и перетащив новое отношение на контроллер представления, который вы хотите отобразить в компактном режиме.
- В моем приложении есть TableView, и в компактном режиме я хочу нажать на контроллер подробного представления при касании ячейки. В новом контроллере SplitView iOS 14 это нужно делать вручную. Я сделал это, добавив в свой
didSelectRowAt
функция:
// If we are in compact mode, we need to push the detail view controller
if let splitViewController = splitViewController {
if splitViewController.isCollapsed {
let shipmentDetailViewController = storyboard?.instantiateViewController(identifier: "shipmentDetailViewController") as! ShipmentDetailViewController
shipmentDetailViewController.shipment = selectedShipment
self.navigationController?.pushViewController(shipmentDetailViewController, animated: true)
}
}
Или просто наследовать от UISplitViewController
и используйте этот новый класс в раскадровке (основываясь на ответе SwiftArchitect):
class MasterShowingSplitViewController :UISplitViewController, UISplitViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.preferredDisplayMode = .allVisible
}
func splitViewController(
_ splitViewController: UISplitViewController,
collapseSecondary secondaryViewController: UIViewController,
onto primaryViewController: UIViewController) -> Bool {
// Return true to prevent UIKit from applying its default behavior
return true
}
}
Это старый вопрос, и ни один из ответов не был для Задачи C, и даже когда я портировал ответы Swift, ни один из них не работал для меня. Один был близко, @SwiftArchitect.
Но он рекомендовал установить режим контента на .allVisible
(UISplitViewControllerDisplayModeAllVisible
в Задаче C) - это заставляет главный вид постоянно отображать, разделяя вид на главный с одной стороны, детализируя с другой. Это круто, но ОП попросил специально отобразить главное представление при первом запуске, что мне и нужно было сделать.
Изменение должно было использовать UISplitViewControllerDisplayModePrimaryOverlay
для режима отображения.
Этот ответ для Xcode 9.4.1, цель развертывания 11.4.
Вот MasterViewController.h - вам нужно добавить UISplitViewControllerDelegate в объявлении протоколов:
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import "MasterDetailDemo+CoreDataModel.h"
@class DetailViewController;
@interface MasterViewController : UITableViewController
<UISplitViewControllerDelegate,
NSFetchedResultsControllerDelegate>
@property (strong, nonatomic) DetailViewController *detailViewController;
@property (strong, nonatomic) NSFetchedResultsController<Event *> *fetchedResultsController;
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@end
А затем в вашем MasterViewController.m вам нужно установить делегат контроллера разделенного представления и режим содержимого в ViewDidLoad, а затем вместе с ответом @ SwiftArchitect также добавить метод делегата контроллера разделенного представления:
- (void)viewDidLoad {
[super viewDidLoad];
// needed to "slide out" MasterView on startup on iPad
self.splitViewController.delegate = self;
self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay;
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
}
// split view delegate method
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {
return true;
}
ПРИМЕЧАНИЕ. После некоторого тестирования я обнаружил, что метод делегирования с разделенным представлением и протокол с разделенным представлением не были необходимы. Без этого, похоже, работает точно так же. Возможно, это результат изменений в iOS, так как вопрос был первоначально задан и получен ответ.
Я получил это работает нормально, просто поместив эту строку в мой метод ViewDidLoad:
self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay;
Swift 5, iOS 13
Я нашел другие ответы полезными, но не совсем в том смысле, что они производили то поведение, которое я хотел, на iPad или iPhone, но не на обоих сразу.
Приведенное ниже решение - это то, для чего я использовал:
iPhone: главное представление всегда отображается первым
iPad Portrait: детали появляются всегда, но с наложением мастера; детализация в полноэкранном режиме (а не только справа от мастера)
Пейзаж iPad: мастер всегда слева, детали всегда справа
class RootSplitViewController: UISplitViewController {
override func viewDidLoad() {
if UIDevice.current.userInterfaceIdiom == .pad {
self.preferredDisplayMode = .automatic
}
else {
self.preferredDisplayMode = .allVisible
}
self.delegate = self
}
}
extension RootSplitViewController: UISplitViewControllerDelegate {
func splitViewController(_ splitViewController: UISplitViewController,
collapseSecondary secondaryViewController:UIViewController,
onto primaryViewController:UIViewController)
-> Bool
{
if AppState.instance.currentSelectedEvent == nil {
// Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return true
}
else {
return false
}
}
}