Przewodniki po układzie strefy bezpiecznej w plikach xib-iOS 10


Zacząłem dostosowywać moją aplikację do iPhone'a X i znalazłem problem w Interface Builder.
Zgodnie z oficjalnymi filmami Apple wytyczne dotyczące układu bezpiecznych stref powinny być wstecznie kompatybilne. Uważam, że działa to świetnie w scenorysach.
Ale w moich plikach XIB przewodniki dotyczące układu bezpiecznej strefy nie są przestrzegane w systemie iOS 10.
Działają dobrze w nowszej wersji systemu operacyjnego, ale urządzenia iOS 10 wydają się po prostu przyjmować bezpieczną odległość strefy jako zero (ignorując rozmiar paska stanu).
Czy brakuje mi jakiejś wymaganej konfiguracji? Czy to błąd Xcode, a jeśli tak, czy są jakieś znane obejścia?
Oto zrzut ekranu przedstawiający problem w projekcie testowym (lewy iOS 10, prawy iOS 11):
https://i.stack.imgur.com/zcOJx.png
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Istnieją pewne problemy z układem bezpiecznych stref i wsteczną kompatybilnością. Zobacz mój komentarz

tutaj
https://coderoad.ru/46184197/
.
Możesz obejść te problemy z dodatkowymi ograniczeniami, takimi jak priorytet 1000> = 20.0 do superview.top i priorytet 750 == safearea.top. Jeśli zawsze wyświetlasz pasek stanu, powinno to naprawić wszystko.
Lepszym podejściem może być posiadanie oddzielnych scenorysów/xibs dla systemów wcześniejszych niż iOS 11 i iOS-11 i nowszych, zwłaszcza jeśli napotkasz więcej problemów. Powodem, dla którego jest to preferowane, jest to, że przed iOS 11 powinieneś umieścić ograniczenia na górnych/dolnych prowadnicach układu, ale w przypadku iOS 11 powinieneś umieścić je w bezpiecznych obszarach. Nie ma żadnych znaczników. Przewodniki po układach dla wersji wcześniejszych niż iOS 11 są stylistycznie lepsze niż tylko przesunięte o co najmniej 20 pikseli, nawet jeśli wyniki są takie same IFF, zawsze wyświetla się pasek stanu.
Jeśli podejmiesz takie podejście, musisz ustawić każdy plik na właściwy cel wdrożenia, w którym będzie używany (iOS 11 lub starszy), aby Xcode nie dawał ostrzeżeń i umożliwiał korzystanie z przewodników układu lub bezpiecznych obszarów, w zależności od tego. W swoim kodzie sprawdź, czy w czasie wykonywania jest iOS 11, a następnie pobierz odpowiedni scenorys/xibs.
Wadą tego podejścia jest konserwacja (będziesz mieć dwa zestawy kontrolerów widoku do utrzymania i synchronizacji), ale gdy Twoja aplikacja obsługuje tylko iOS 11+ lub Apple naprawi generowanie ograniczeń przewodnika układu zgodności wstecznej, powinieneś być w stanie się pozbyć wersji starszych niż iOS 11. ...
Swoją drogą, jak pokażesz kontroler, z którym to widzisz? Czy to tylko główny kontroler widoku, czy przedstawiłeś go, czy ...? Problem, który zauważyłem, jest związany z przekazywaniem kontrolerów widoku, więc możesz napotkać inny przypadek.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Kompatybilność wsteczna nie działa obecnie zbyt dobrze.
Moim rozwiązaniem jest utworzenie 2 ograniczeń w kreatorze interfejsów i usunięcie jednego z nich w zależności od używanej wersji ios:
  • dla iOS 11:
    view.top == safe area.top
  • dla wcześniejszych wersji:
    view.top == superview.top + 20

Dodaj je jako dane wyjściowe, takie jak odpowiednio
myConstraintSAFEAREA
i
myConstraintSUPERVIEW
. Następnie:
override func viewDidLoad() {
if #available(iOS 11.0, *) {
view.removeConstraint(myConstraintSUPERVIEW)
} else {
view.removeConstraint(myConstraintSAFEAREA)
}
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Dla mnie prostym rozwiązaniem, aby działał na obu wersjach, było
if #available(iOS 11, *) {}
else {
self.edgesForExtendedLayout = []
}

Z dokumentacji: „W systemie iOS 10 i wcześniejszych użyj tej właściwości, aby określić, które krawędzie kontrolera widoku znajdują się poniżej pasków nawigacyjnych lub innych widoków systemowych”.
W związku z tym ustawienie ich na pustą tablicę zapewnia, że ​​kontroler widoku nie jest
rozszerza się pod paskami nawigacyjnymi.
Dokument dostępny

tutaj
https://developer.apple.com/do ... ayout
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Połączyłem niektóre odpowiedzi z tej strony w tę, która działa jak urok (tylko dla górnego przewodnika po układzie, jak wskazano w pytaniu):
  • Upewnij się, że korzystasz z bezpiecznego rogu w swoim scenariuszu lub pliku XIB
  • Ogranicz swoje widoki do bezpiecznych obszarów
  • Dla każdego
    widoku
    , który ma
    ograniczenie
    dołączone do SafeArea.top [list][*]Utwórz IBOutlet dla
    widoku
  • Utwórz IBOutlera dla
    ograniczenia

[/*]
[*]
Wewnątrz ViewController na
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;
}

[/*]
[/list]
Edytować:
Oto ulepszona wersja, której użyłem w naszej bazie kodu. Po prostu skopiuj/wklej poniższy kod i połącz każdy widok i ograniczenia z ich 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;
}
}
Liczba każdego IBOutletCollection musi być równa, na przykład dla każdego widoku
musi istnieć odpowiednie ograniczenie
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Skończyło się na usunięciu ograniczenia obszaru bezpiecznego, które miałem w pliku xib.
Zamiast tego utworzyłem dane wyjściowe do omawianego UIView i z kodu podłączyłem je w ten sposób w viewDidLayoutSubviews.
let constraint = alert.viewContents.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor, constant: 0)
constraint.priority = 998
constraint.isActive = true

Powoduje to powiązanie małego „alertu” z górną częścią ekranu, ale zapewnia, że ​​widok treści w alercie jest zawsze poniżej górnego bezpiecznego obszaru (iOS11ish)/topLayoutGuide (iOS10ish)
Proste i jednorazowe rozwiązanie. Jeśli coś się zepsuje, wrócę.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Skorzystałem z tej opcji, dodałem górny układ obszaru bezpiecznego i podłączyłem do gniazdka
@IBOutlet weak var topConstraint : NSLayoutConstraint!override func viewDidLoad() {
super.viewDidLoad()
if !DeviceType.IS_IPHONE_X {
if #available(iOS 11, *) {
}
else{
topConstraint.constant = 20
}
}
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

To też działa:
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
}
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Znalazłem najprostsze rozwiązanie - po prostu wyłącz
bezpieczny obszar
i użyj
topLayoutGuide
i
bottomLayoutGuide
+ dodaj poprawki dla iPhone'a X. Może to nie jest ładne rozwiązanie , ale wymaga jak najmniejszego wysiłku
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Dodałem podklasę NSLayoutConstraint, aby naprawić ten problem (
IBAdjustableConstraint
), przy czym zmienna
@IBInspectable
wygląda tak.
class IBAdjustableConstraint: NSLayoutConstraint { @IBInspectable var safeAreaAdjustedConstant: CGFloat = 0 {
didSet {
if OS.TenOrBelow {
constant += safeAreaAdjustedConstantLegacy
}
}
}
}

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

Po prostu ustaw podklasę ograniczenia IB i możesz wprowadzić określone zmiany w & < iOS11. Mam nadzieję, że to komuś pomoże.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się