Расширение сообщений iOS 10 - неправильный макет при использовании Storyboard Segue

При использовании Segues в приложении расширения сообщений макет портится.
Есть ли способ решить эту проблему, все еще используя storrybord segues?

Скриншоты:
(Примечание: первый и второй View / ViewController идентичны. Тип segue не имеет значения)

Расширенный стиль презентации:

1Exp 2Exp


Компактный стиль презентации:

1Comp 2Comp

Обновление 1:

Верхний и нижний направляющие макета сбрасываются после перехода

  • компактный:
    • top: должно быть: 0, но есть: 20
    • внизу: должно быть: 44, но есть: 0
  • расширен:
    • top: должно быть: 86, но есть: 20
    • внизу: должно быть: 44, но есть: 0


PS Может кто-нибудь создать новый тег "messages-extension"?

3 ответа

Я надеюсь, что это не всегда будет необходимо, но в итоге я использовал комбинацию выхода ограничения, переменной presentationStyle и viewDidLayoutSubviews() для преодоления этой ошибки / недосмотра.

В моем DetailViewController:

@IBOutlet weak var myViewTopConstraint: NSLayoutConstraint!
var presentationStyle: MSMessagesAppPresentationStyle?

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if presentationStyle == .expanded {
        myViewTopConstraint.constant = 86
    } else {
        myViewTopConstraint.constant = 0
    }
}

И в моем MainViewController:

override func willTransition(to presentationStyle: MSMessagesAppPresentationStyle) {
    if let detailController = presentedViewController as? DetailViewController {
        detailController.presentationStyle = presentationStyle
    }
}

И в случае, если это что-то меняет, мой переход представлен модально в виде листа.

В моем приложении viewcontroller в режиме.expand установлен:

view.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor).isActive = true

в режиме.compact установите значение false

view.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor).isActive = false

он должен работать.

Одно возможное решение, к которому я пришел с помощью http://sandmoose.com/post/35714028270/storyboards-with-custom-container-view-controllers

В контроллере вида точки входа поместите вид контейнера, который имеет автоматические ограничения макета, выравнивая верх и низ вида контейнера с верхним и нижним направляющими макета.

Затем в само представление контейнера необходимо встроить любой контроллер представления, к которому вы обращаетесь. Таким образом, контроллеры представления назначения всегда будут жить в пределах представления контейнера. Вид контейнера также будет корректно ограничен верхними и нижними направляющими компоновки контроллера начального вида.

Один из способов добиться этого: реализовать протокол, который будет получать уведомления о переходах - что-то вроде:

protocol SegueDelegate {
  func willSegue(to: UIViewController)

  func didSegue(to: UIViewController)
}

Реализуйте подкласс UIViewController, который имеет ссылку на SegueDelegate, например

class ContainedViewController: UIViewController {
  weak var segueDelegate: SegueDelegate?

  ...

  override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    segueDelegate?.willSegue(to: segue.destination)
  }
}

Пусть ваш начальный контроллер просмотра сообщений реализует протокол.

extension MSMessagesAppViewController: SegueDelegate {

  func didSegue(to destination: UIViewController) {
    guard let destination = destination as? ContainedViewController else {
      return
    }
    // Reference through IBOutlet or something
    containerViewController.embed(destination)
  }
}

Контейнер containerViewController должен реализовывать метод встраивания, который заменяет контроллер отображаемого представления на новый, например

class ContainerViewController: UIViewController {
  ...

  func embed(_ viewController: UIViewController) {
    let source = childViewControllers.first
    if source == viewController {
        return
    }

    source?.willMove(toParentViewController: nil)
    addChildViewController(viewController)
    if let source = source {
        // Do transition here if you want
        viewController.view.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)
        view.addSubview(viewController.view)
        viewController.didMove(toParentViewController: self)

        source.willMove(toParentViewController: nil)
        source.removeFromParentViewController()
    } else {
        viewController.view.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)
        view.addSubview(viewController.view)
        viewController.didMove(toParentViewController: self)
    }

    // Assigned in viewDidLoad of MSMessagesAppViewController or similar
    segueDelegate?.didSegue(to: viewController)
  }

}
Другие вопросы по тегам