it-swarm.com.ru

Руководства по макету безопасной области в файлах xib - iOS 10

Я начал адаптировать свое приложение для iPhone X и обнаружил проблему в Интерфейсном Разработчике ........ Руководства по макету безопасной области должны быть обратно совместимы, согласно официальным видео Apple. Я обнаружил, что он отлично работает в раскадровках.

Но в моих файлах XIB руководства по разметке безопасной области не соблюдаются в iOS 10.

Они отлично работают для новой версии ОС, но устройства iOS 10, похоже, просто принимают безопасное расстояние равным нулю (игнорируя размер строки состояния).

Я пропустил любую необходимую конфигурацию? Это ошибка XCode, и если да, то какие-либо известные обходные пути?

Вот скриншот проблемы в тестовом проекте (слева iOS 10, справа iOS 11):

 safe area alignment on top of the screen

60
Tiago Lira

Есть некоторые проблемы с макетом безопасной области и обратной совместимостью. Смотрите мой комментарий над здесь .

Возможно, вы сможете обойти проблемы с дополнительными ограничениями, такими как приоритет 1000> = 20,0 для superview.top и приоритет 750 == safearea.top. Если вы всегда показываете строку состояния, это должно исправить ситуацию.

Лучшим подходом может быть создание отдельных раскадровок/XIB для версий до iOS 11 и iOS-11 и выше, особенно если вы столкнулись с большим количеством проблем, чем эта. Причина, по которой это предпочтительнее, заключается в том, что до iOS 11 вы должны размещать ограничения для верхних/нижних направляющих, но для iOS 11 вы должны размещать их в безопасных зонах. Руководства по макету ушли. Размещение в направляющих для Pre-iOS 11 стилистически лучше, чем просто смещение минимум на 20 пикселей, даже если результаты будут такими же, как IFF, вы всегда показываете строку состояния.

Если вы воспользуетесь этим подходом, вам нужно будет установить для каждого файла правильную цель развертывания, на которой он будет использоваться (iOS 11 или что-то более раннее), чтобы XCode не выдавал вам предупреждения и позволял вам использовать направляющие или безопасные зоны, в зависимости. В своем коде проверьте iOS 11 во время выполнения, а затем загрузите соответствующую раскадровку/xibs.

Недостатком этого подхода является техническое обслуживание (у вас будет два набора контроллеров представления для поддержки и синхронизации), но если ваше приложение поддерживает только iOS 11+ или Apple исправит создание ограничения на макет обратной совместимости, вы можете получить избавиться от версий до iOS 11.

Кстати, как вы отображаете контроллер, с которым вы это видите? Это просто контроллер корневого представления или вы его представили, или ..? Проблема, которую я заметил, связана с выдвижением контроллеров представления, так что вы можете столкнуться с другим случаем.

67
clarus

В настоящее время обратная совместимость не работает хорошо. 

Мое решение состоит в том, чтобы создать 2 ограничения в построителе интерфейса и удалить одно в зависимости от используемой версии ios:

  • для ios 11: view.top == safe area.top
  • для более ранних версий: view.top == superview.top + 20

Добавьте их обоих как выходы как myConstraintSAFEAREA и myConstraintSUPERVIEW соответственно. Затем:

override func viewDidLoad() {
    if #available(iOS 11.0, *) {
        view.removeConstraint(myConstraintSUPERVIEW)
    } else {
        view.removeConstraint(myConstraintSAFEAREA)
    }
}
13
Martin Massera

Для меня, простое исправление для того, чтобы заставить его работать на обеих версиях было 

    if #available(iOS 11, *) {}
    else {
        self.edgesForExtendedLayout = []
    }

Из документации: «В iOS 10 и более ранних версиях используйте это свойство, чтобы сообщить, какие края вашего контроллера представления расширяются под панелями навигации или другими предоставленными системой представлениями.» . Поэтому установка их в пустой массив гарантирует, что контроллер представления не распространяется под панелями навигации.

Документ доступен здесь

4
Falco Winkler

Я объединил некоторые ответы с этой страницы в эту, которая работает как очарование (только для топ-макета, как и требовалось в вопросе):

  1. Убедитесь, что вы используете безопасную область в раскадровке или в файле XIB.
  2. Ограничьте свои взгляды в безопасных районах
  3. Для каждого view, который имеет constraint, прикрепленный к SafeArea.top
    • Создайте IBOutlet для view
    • Создайте IBOutler для constraint
  4. Внутри ViewController на viewDidLoad:

    if (@available(iOS 11.0, *)) {}
    else {
        // For each view and constraint do:
        [self.view.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor].active = YES;
        self.constraint.active = NO;
    }
    

Правка:

Вот улучшенная версия, которую я использовал в нашей кодовой базе. Просто скопируйте/вставьте приведенный ниже код и подключите каждое представление и ограничения к их IBOutletCollection.

@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *constraintsAttachedToSafeAreaTop;
@property (strong, nonatomic) IBOutletCollection(UIView) NSArray *viewsAttachedToSafeAreaTop;


if (@available(iOS 11.0, *)) {}
else {
    for (UIView *viewAttachedToSafeAreaTop in self.viewsAttachedToSafeAreaTop) {
        [viewAttachedToSafeAreaTop.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor].active = YES;
    }
    for (NSLayoutConstraint *constraintAttachedToSafeAreaTop in self.constraintsAttachedToSafeAreaTop) {
        constraintAttachedToSafeAreaTop.active = NO;
    }
}

Количество каждой коллекции IBOutletCollection должно быть одинаковым. например для каждого просмотра должно быть его связанное ограничение

2
Tumata

Я использовал этот, добавить макет верхней безопасной зоны и подключиться к розетке

@IBOutlet weak var topConstraint : NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()
    if !DeviceType.IS_IPHONE_X {
        if #available(iOS 11, *)  {
        }
        else{
            topConstraint.constant = 20
        }
    }
}
0
little

Я добавил подкласс NSLayoutConstraint, чтобы исправить эту проблему (IBAdjustableConstraint), с переменной @IBInspectable, выглядит так.

class IBAdjustableConstraint: NSLayoutConstraint {

    @IBInspectable var safeAreaAdjustedConstant: CGFloat = 0 {
        didSet {
            if OS.TenOrBelow {
                constant += safeAreaAdjustedConstantLegacy
            }
        }
    }
}

И OS.TenOrBelow

struct OS {
    static let TenOrBelow = UIDevice.current.systemVersion.compare("10.9", options: NSString.CompareOptions.numeric) == ComparisonResult.orderedAscending
}

Просто установите это как подкласс вашего ограничения в IB, и вы сможете вносить изменения, специфичные для iOS11. Надеюсь, это кому-нибудь поможет.

0
Alex Brown

Это также работает: 

override func viewDidLoad() {
    super.viewDidLoad()

    if #available(iOS 11.0, *) {}
    else {
        view.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height - 80).isActive = true
        view.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width - 20).isActive = true
    }
}
0
Menan Vadivel

Я закончил тем, что удалил ограничение для безопасной области, которое было в моем файле xib ........ Вместо этого я сделал выход в рассматриваемый UIView, и из кода я подключил его вот так, в viewDidLayoutSubviews.

let constraint = alert.viewContents.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor, constant: 0)
constraint.priority = 998
constraint.isActive = true

Это связывает небольшое «предупреждение» с верхней частью экрана, но гарантирует, что представление содержимого в предупреждении всегда находится ниже верхней безопасной области (iOS11ish)/topLayoutGuide (iOS10ish)

Простое и одноразовое решение. Если что-то сломается, я вернусь ????.

0
Jonny