Pasek stanu i pasek nawigacji pojawiają się nad granicami mojego widoku w iOS 7

435

Niedawno pobrałem Xcode 5 DP, aby przetestować moje aplikacje w iOS 7. Pierwszą rzeczą, którą zauważyłem i potwierdziłem, jest to, że granice mojego widoku nie zawsze są zmieniane, aby uwzględnić pasek stanu i pasek nawigacji.

W viewDidLayoutSubviewsdrukuję granice widoku:

{{0, 0}, {320, 568}}

Powoduje to, że moja treść pojawia się poniżej paska nawigacyjnego i paska stanu.

Wiem, że mógłbym samodzielnie wyliczyć wysokość, uzyskując wysokość ekranu głównego, odejmując wysokość paska stanu i wysokość paska nawigacji, ale wydaje się to niepotrzebną dodatkową pracą.

Jak mogę rozwiązać ten problem?

Aktualizacja:

Znalazłem rozwiązanie tego konkretnego problemu. Ustaw półprzezroczystą właściwość paska nawigacji na NIE:

self.navigationController.navigationBar.translucent = NO;

Naprawi to kadrowanie widoku pod paskiem nawigacyjnym i paskiem stanu.

Jednak nie znalazłem rozwiązania dla przypadku, gdy chcesz, aby pasek nawigacji był półprzezroczysty. Na przykład, oglądając zdjęcie na pełnym ekranie, chciałbym, aby pasek nawigacji był przezroczysty, a widok, który ma być w nim obramowany. To działa, ale kiedy przełączam wyświetlanie / ukrywanie paska nawigacji, zauważyłem nawet dziwniejsze wyniki. Pierwszy widok podrzędny (UIScrollView) zmienia swoje granice i pochodzenie za każdym razem.

beebcon
źródło
Dostaję również ten sam problem w xcode 5 DP
Gopesh Gupta
Daj mi znać, jeśli znajdziesz jakieś rozwiązanie
Gopesh Gupta,
1
Spójrz na pasku nawigacyjnym na właściwość koloru odcienia, powinieneś być w stanie zmienić ten niebieski kolor na cokolwiek chcesz.
beebcon,
9
Nienawidzę czasem aktualizacji systemu iOS, ponieważ Apple nigdy nie dawało ci okazji do zachowania zgodności aplikacji z poprzednimi wersjami.
Bagusflyer
3
Jeśli problem jest związany z widokiem przechodzącym pod paskiem stanu po ukryciu górnego paska kontrolera nawigacji, odniosłbym się do odpowiedzi @Stunner stackoverflow.com/a/18976660/235206 jako rozwiązania
MiKL

Odpowiedzi:

495

Można to osiągnąć, wdrażając nową właściwość o nazwie edgesForExtendedLayoutw iOS7 SDK. Dodaj następujący kod, aby to osiągnąć,

if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
        self.edgesForExtendedLayout = UIRectEdgeNone;

Musisz dodać powyższe w swojej -(void)viewDidLoadmetodzie.

iOS 7 wprowadza kilka zmian w sposobie układania i dostosowywania wyglądu interfejsu użytkownika . Zmiany w układzie kontrolera widoku, kolorze odcienia i czcionce wpływają na cały UIKit obiekty w Twojej aplikacji. Ponadto udoskonalenia interfejsów API rozpoznawania gestów zapewniają lepszą kontrolę nad interakcjami gestów.

Korzystanie z kontrolerów widoku

W iOS 7 kontrolery widoku używają układu pełnoekranowego. Jednocześnie iOS 7 zapewnia bardziej szczegółową kontrolę nad sposobem wyświetlania widoków przez kontroler widoku. W szczególności udoskonalono koncepcję układu pełnoekranowego, aby umożliwić kontrolerowi widoku określenie układu każdej krawędzi jego widoku.

Właściwość wantsFullScreenLayoutkontrolera widoku jest przestarzała w iOS 7. Jeśli obecnie określasz wantsFullScreenLayout = NO, kontroler widoku może wyświetlać swoją zawartość w nieoczekiwanym miejscu na ekranie, gdy działa w systemie iOS 7.

Aby dostosować sposób, w jaki kontroler widoku określa swoje widoki, UIViewController udostępnia następujące właściwości:

  • EdgeForExtendedLayout

edgesForExtendedLayoutWłaściwość wykorzystuje UIRectEdgetyp, który określa każdego prostokąta czterech krawędziach, oprócz określenia równych i wszystko. Służy edgesForExtendedLayoutdo określania, które krawędzie widoku powinny zostać przedłużone, niezależnie od półprzezroczystości paska. Domyślnie wartość tej właściwości toUIRectEdgeAll .

  • ExtendedLayoutIncludesOpaqueBars

Jeśli projekt używa nieprzezroczystych pasków, popraw edgesForExtendedLayouttakże, ustawiając extendedLayoutIncludesOpaqueBarswłaściwość na NIE . (Wartość domyślna extendedLayoutIncludesOpaqueBarsto NIE .)

  • automatycznieAdjustsScrollViewInsets

Jeśli nie chcesz zawartość wstawki przewijania widoku, który ma być automatycznie regulowana, zestaw automaticallyAdjustsScrollViewInsetsdo NO . (Wartość domyślna automaticallyAdjustsScrollViewInsetsto TAK .)

  • topLayoutGuide, bottomLayoutGuide

Właściwości topLayoutGuidei bottomLayoutGuidewskazują położenie górnej lub dolnej krawędzi paska w widoku kontrolera widoku. Jeśli paski powinny nakładać się na górę lub dół widoku, można użyć Konstruktora interfejsów, aby ustawić widok względem paska, tworząc ograniczenia do dolnej topLayoutGuidelub górnej krawędzi bottomLayoutGuide. (Jeśli żaden pasek nie powinien zachodzić na widok, dolna część topLayoutGuidejest taka sama jak góra widoku i góra bottomLayoutGuide jest taka sama jak dolna część widoku.) Obie właściwości są tworzone leniwie na żądanie.

Proszę odnieść się, Apple Doc

Nandha
źródło
2
Nie będzie się kompilować pod iOS6. Myślę, że powinien być napisany jako performselector ...
Shmidt
8
Tak, dlatego zawarłem selektor z warunkiem if, jeśli ([self responssToSelector: @selector (edgeForExtendedLayout)])
Nandha
19
To nie zadziałałoby, jeśli nie mam paska nawigacji. W takim przypadku mój widok rozciąga się za pasek stanu.
Van Du Tran,
4
Mam taki sam problem jak @VanDuTran. EdgeForExtendedLayout nie pomaga, jeśli pasek nawigacyjny jest ukryty.
fishinear
6
to działa, ale ... nie ma już efektu półprzezroczystego ... jak możemy również zachować efekt półprzezroczysty ...
Dipu Rajak
110

Nie musisz obliczyć, jak daleko chcesz wszystko przesunąć w dół, jest do tego wbudowana właściwość. W Konstruktorze interfejsów podświetl kontroler widoku, a następnie przejdź do inspektora atrybutów. Tutaj zobaczysz kilka pól wyboru obok słów „Rozszerz krawędzie”. Jak widać, na pierwszym zrzucie ekranu domyślnym wyborem jest wyświetlanie treści pod górnymi i dolnymi słupkami, ale nie pod nieprzezroczystymi słupkami, dlatego ustawienie stylu paska na półprzezroczyste działało dla Ciebie.

Jak można zobaczyć na pierwszym zrzucie ekranu, pod paskiem nawigacji ukryte są dwa elementy interfejsu użytkownika. (Włączyłem w tym celu szkielety w IB). Te elementy, UIButton i UISegmentedControl, mają zarówno początek „y” zerowy, jak i kontroler widoku, który pozwala na zawartość poniżej górnego paska.

wprowadź opis zdjęcia tutaj

Ten drugi zrzut ekranu pokazuje, co się stanie, gdy odznaczysz pole wyboru „Pod górnymi pasami”. Jak widać, widok kontrolerów widoku został odpowiednio przesunięty w dół, aby jego pochodzenie y znajdowało się bezpośrednio pod paskiem nawigacji.

wprowadź opis zdjęcia tutaj

Można to również osiągnąć programowo poprzez użycie -[UIViewController edgesForExtendedLayout]. Oto link do odwołania do klasy EdgeForExtendedLayout i UIRectEdge

[self setEdgesForExtendedLayout:UIRectEdgeNone];
Mick MacCallum
źródło
15
Jak mogę zrobić to samo dla samego widoku w .xib?
bobiki
2
Dodałem jedną etykietę do wyświetlenia i postępowałem zgodnie z twoimi instrukcjami, ale to nie działa dla mnie
RMRAHUL
5
@bobics Odpowiedź na pytanie XIB brzmi: „Nie możesz”. W każdym razie nie przez IB. Złóż radar i mam nadzieję, że Apple w końcu go rozwiąże.
memmons,
Dzięki @ 0x7fffffff, To były tylko informacje, których szukałem i były bardzo pomocne.
Campo
33

Stworzyłem mój widok programowo, co skończyło się dla mnie:

- (void) viewDidLayoutSubviews {
    // only works for iOS 7+
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        CGRect viewBounds = self.view.bounds;
        CGFloat topBarOffset = self.topLayoutGuide.length;

        // snaps the view under the status bar (iOS 6 style)
        viewBounds.origin.y = topBarOffset * -1;

        // shrink the bounds of your view to compensate for the offset
        viewBounds.size.height = viewBounds.size.height + (topBarOffset * -1);
        self.view.bounds = viewBounds;
    }
}

Źródło (w sekcji topLayoutGuide na dole str.39).

Szlagier
źródło
W końcu znalazłem odpowiedź, która faktycznie na to działa. Dobra robota!
StuartM
1
Aby rozwiązać problem polegający na tym, że widok kontrolera widoku pojawia się pod paskiem stanu, gdy pasek nawigacyjny jest ukryty, jest to kod, który przyciąga widok pod paskiem stanu.
MiKL
Uwaga: spowoduje to zepchnięcie dolnej części widoku z ekranu.
memmons,
1
Ponadto, chyba że budujesz tylko dla iOS7, powyższy kod zgłosi błąd - topLayoutGuidedotyczy tylko iOS7.
memmons,
1
Należy również pamiętać, że gdy głównym widokiem jest UITableView, viewDidLayoutSubviews będzie wywoływany przy każdym przewijaniu. Twój UITableView będzie skalowany w dół, aż jego wysokość wyniesie 15 pikseli. Dodaj flagę, aby uruchomić ten kod tylko raz. ;)
Thomas Johannesmeyer
30

Rozwiązanie Swift 3 / Swift 4, które działa również z plikami NIB / XIB w iOS 10+:

override func viewDidLoad() {
    super.viewDidLoad()

    edgesForExtendedLayout = []
}
flo_23
źródło
To mi pomogło ... Tak proste. Dzięki :-)
Hernan Arber
Dziękuję, to jest naprawdę pomocne
Muhammad Ahmed Baig
To najlepsze rozwiązanie dla IMO 10.x Swift 3+
shokaveli
10

Jeśli chcesz, aby widok miał przezroczysty pasek nawigacyjny (co jest całkiem miłe), musisz skonfigurować contentInset lub podobny.

Oto jak to robię:

// Check if we are running on ios7
if([[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."][0] intValue] >= 7) {
      CGRect statusBarViewRect = [[UIApplication sharedApplication] statusBarFrame];
      float heightPadding = statusBarViewRect.size.height+self.navigationController.navigationBar.frame.size.height;

      myContentView.contentInset = UIEdgeInsetsMake(heightPadding, 0.0, 0.0, 0.0);
}
Magnus
źródło
3
dlaczego nie można go bezpośrednio porównać z 7.0
Leena
1
lol Rozumiem: sprawdzanie konkretnej wersji z niewielkim dodatkiem jest mniej niezawodne. Ale sprawdzasz, czy wartość jest WIĘKSZA lub równa, więc porównanie z 7.0 byłoby tutaj w porządku;)
EeKay
1
@leena - ta funkcja jest dostępna w wersji 7.x i nowszych - więc sprawdzam, czy wersja ma 7 lub nowszą wersję, i pomijam drobne zmiany w czeku.
Magnus
2
Wystąpił problem z wyświetlaniem mojej tabeli wyświetlanej za paskiem Tabbar. Co sprawiło, że ostatni rząd mojego stołu nigdy nie przewijał się powyżej paska kart. Naprawiłem to w ten sposób: myTableView.contentInset = UIEdgeInsetsMake (0, 0,0, TabbarHeight, 0)
James Laurenstin
contentInsetjest własnością UIScrollView. Co jeśli mój główny widok nie jest podklasą UIScrollView. Jak więc rozwiązać problem nakładania się?
Pwner,
9

edgesForExtendedLayoutrobi to na iOS 7. Jednak jeśli zbudujesz aplikację w iOS 7 SDK i wdrożysz ją w iOS 6, pasek nawigacyjny będzie przezroczysty, a widoki będą pod nim. Aby to naprawić zarówno w systemie iOS 7, jak i iOS 6, wykonaj następujące czynności:

self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
    self.edgesForExtendedLayout = UIRectEdgeNone;   // iOS 7 specific
Raj Pawan Gumdal
źródło
9

W pliku plist aplikacji dodaj wiersz, nazwij go „Wyświetl pasek stanu oparty na kontrolerze” i ustaw go na NIE .

Idan
źródło
7

Najprostszą sztuczką jest otwarcie pliku NIB i wykonanie dwóch prostych kroków:

  1. Po prostu przełącz to i ustaw na preferowane:

Wpisz opis zdjęcia tutaj

  1. Wybierz te UIView / UIIMageView / ..., które chcesz przenieść w dół. W moim przypadku nałożono tylko logo i ustawiłem deltę na +15; (LUB -15, jeśli wybrałeś iOS 7 w kroku 1)

Wpisz opis zdjęcia tutaj

A wynik :

Przed Po

Riskov
źródło
6
Działa, ale wygląda to na trudne do utrzymania rozwiązanie. Najlepiej byłoby po prostu rozwiązać problem zamiast go załatać.
NL we wtorek
najlepiej byłoby to zrobić programowo dla wszystkich widoków podrzędnych widoku, ponieważ nie działa, jeśli zostanie zastosowane do widoku głównego
wildmonkey
5

Szybkie rozwiązanie:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.edgesForExtendedLayout = UIRectEdge.None
}
fatihyildizhan
źródło
4
Teraz jest to edgeForExtendedLayout = []
Leon,
1
Ponieważ jest to odpowiedź publiczna, nie powinniśmy zapominać dzwonić:super.viewWillAppear(animated)
prod
4

Chciałbym rozwinąć odpowiedź Stunnera i dodać if oświadczenie, aby sprawdzić, czy jest to iOS-7, ponieważ kiedy testowałem to na iOS 6, moja aplikacja ulegała awarii.

Dodanie polegałoby na dodaniu:

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)

Sugeruję więc dodanie tej metody do MyViewControler.mpliku:

- (void) viewDidLayoutSubviews {
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        CGRect viewBounds = self.view.bounds;
        CGFloat topBarOffset = self.topLayoutGuide.length;
        viewBounds.origin.y = topBarOffset * -1;
        self.view.bounds = viewBounds;
    }
}
werdsackjon
źródło
4

Szybki 3

override func viewWillAppear(_ animated: Bool) {
    self.edgesForExtendedLayout = []
}
Shahrukh
źródło
3

Mam scenariusz, w którym używam BannerViewController napisanego przez Apple do wyświetlania moich reklam oraz ScrollViewController osadzonego w BannerViewController.

Aby zapobiec ukrywaniu zawartości paska nawigacji, musiałem dokonać dwóch zmian.

1) Zmodyfikuj BannerViewController.m

- (void)viewDidLoad
{
   [super viewDidLoad];
   float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
   if (systemVersion >= 7.0) {
      self.edgesForExtendedLayout = UIRectEdgeNone;
   }
}

2) Zmodyfikuj mój ScrollViewContoller

- (void)viewDidLoad
{
    [super viewDidLoad];
    float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (systemVersion >= 7.0) {
        self.edgesForExtendedLayout = UIRectEdgeBottom;
    }
}

Teraz reklamy wyświetlają się poprawnie w dolnej części widoku, zamiast być zakrytymi przez pasek nawigacyjny, a zawartość u góry nie jest odcinana.

Xavier John
źródło
2

wystarczy ustawić następujący kod w widoku pojawi się.

  if ([[[UIDevice currentDevice] systemVersion] floatValue]<= 7) {
self.edgesForExtendedLayout = UIRectEdgeNone;
 }
Amit Shelgaonkar
źródło
To jedyna rzecz, która działała w moich okolicznościach.
goobliata,
2

wprowadzić ograniczenia do górnego układu w ten sposób wprowadź opis zdjęcia tutaj

carmen_munich
źródło
2

Swift 4.2 - Xcode 10.0 - iOS 12.0:

if #available(iOS 11.0, *) {} else {
  self.edgesForExtendedLayout = []
  self.navigationController?.view.backgroundColor = .white
}
juliancadi
źródło
1

Dla mnie najprostszym rozwiązaniem jest dodanie dwóch kluczy do listy

wprowadź opis zdjęcia tutaj

Giuseppe
źródło
+1, miałem „pasek stanu początkowo ukryty” = TAK, ale dodając „Zobacz wygląd paska stanu na podstawie kontrolera” = NIE pozbyłem się paska stanu.
Jonas Byström
1

Dodaj wiersz „Wyświetl pasek stanu na podstawie kontrolera” z rozwijanej listy jako wiersz w info.plist. Coś takiego:

Wpisz opis zdjęcia tutaj

Kursat Turkay
źródło
ciekawe. pomogło w moich projektach cocos2d. gdy przełączam tę opcję, widzę, że górny pasek stanu zniknął lub się pojawił.
Kursat Turkay,
1

Miałem ten sam problem z moją aplikacją na iPady (armv7, armv7s, amr64) tylko przez przedstawienie innego UIViewController i po ich odrzuceniu przechodzi na pasek nawigacji pod paskiem stanu ... Spędzam dużo czasu, aby znaleźć rozwiązanie tego problemu. Używam storyboardu i interfejsu InterfaceBuilder dla UIViewController, co sprawia, że ​​straszne jest ustawienie Prezentacji z FullScreen -> Bieżący kontekst i to rozwiązuje ten problem. Działa w mojej aplikacji tylko dla iPadów => iOS 8.0 (testowanie z iOS 8.1) i dla iPadów z iOS 7.1 nie działa !!patrz zrzut ekranu

Alexej W.
źródło
W moim przypadku mój główny widok nakładał się na pasek kart i nie miałem pojęcia, dlaczego. Okazuje się, że zaznaczono opcję Rozszerz krawędzie> Pod dolnymi pasami. Naprawdę trudno było to zauważyć, ponieważ tło mojej aplikacji było białe i generowało tylko pewien stopień krycia na moim pasku tab. Dzięki!
Jesus Rodriguez
0

Kroki, aby ukryć pasek stanu w iOS 7:

1. Przejdź do pliku info.plist aplikacji.

2.I Ustaw, Wyświetl wygląd paska stanu na podstawie kontrolera: Boolean NO

Mam nadzieję, że rozwiązałem problem paska stanu .....

chandrika
źródło
0

W moim przypadku wystąpiło przerwanie loadView ()
ten kod: self.edgesForExtendedLayout = UIRectEdgeNone

ale po usunięciu loadView () wszystko działało dobrze

DevB2F
źródło