UIStatusBarStyle PreferredStatusBarStyle не працює на iOS 7


110

У моєму додатку iPhone побудований з Xcode 5 для IOS 7 I множин UIViewControllerBasedStatusBarAppearance=YESв info.plist, і в моєму у ViewControllerмене є цей код:

-(UIStatusBarStyle) preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

Але рядок стану все ще чорний на чорному тлі.

Я знаю , що його можна змінити це додаток шириною, встановивши UIViewControllerBasedStatusBarAppearance=NOв info.plist, але я на самом деле потрібно , щоб змінити це на viewControllerна viewControllerоснові під час виконання.


Привіт, у мене таке ж питання, як ти згадував у питанні. Ви отримали рішення? Будь ласка, надайте мені це.
Noundla Sandeep

Відповіді:


281

Я виявив, що якщо ваш ViewController знаходиться в навігаційному контролері, то навігаційний navigationBar.barStyleконтролер визначає статусBarStyle.

Визначення своєї Панель навігації - х barStyleдо UIBarStyleBlackTranslucentдадуть білий текст в рядку статусу (тобто. UIStatusBarStyleLightContent), І UIBarStyleDefaultдасть чорний текст в рядку статусу (тобто. UIStatusBarStyleDefault).

Зауважте, що це застосовується навіть якщо ви повністю змінили колір навігаційного бару через його barTintColor.


це має сенс для мене ... чудово
Нік

14
Я вважаю, що це тому, що UINavigationController's preferredStatusBarStyleне переходить до ViewController, який він розміщує, а натомість просто повертається на основі навігаціїBarStyle.
mxcl

У цьому випадку подання не знаходиться у навігаційному контролері.
Ендрю Сміт

Дуже протипомічно думати, що стиль бару надає перевагу реалізованому методу в контролері перегляду, і лише при поданні модальних поглядів!
Матей

3
UIBarStyleBlackTranslucent застаріло, використовуйте UIBarStyleBlackнатомість
Nhon Nguyen

87

Гаразд, ось трюк. Вам потрібно додати ключ "Переглянути панель стану на основі контролера" та встановити значення "Ні".

Це суперечить тому, що, як видається, має значення цього ключа, але навіть якщо ви встановите це значення No, ви все одно можете змінити зовнішній вигляд рядка стану та відображати його чи ні в будь-якому контролері перегляду. Таким чином, він діє як "Так", але встановіть його на "Ні"!

Тепер я можу отримати смугу стану білою або темною.


6
Для мене це було неправильно. Ключ потрібно було встановити на "Так", як ви очікували. Я на Xcode 5.1 iOS 7.1, тому, можливо, це змінилося.
joel.d

Я також використовую Xcode 5.1 та iOS 7.1, а для мене НІ працює ... STRANGE.
Арджун Мехта

Де я повинен додати цей ключ?
Хаду

У вашому [AppName] -Info.plist файл
Saren Inden

1
Це прекрасно працює, коли клавішу "Переглянути рядок стану на основі контролера" встановлено на "ТАК" з Xcode6.0, iOS 8.0
bpolat

77

Для preferredStatusBarStyle()роботи всередині, UINavigationControllerі UITabBarControllerя додаю наступний код, який отримає бажаний стиль рядка стану від поточного видимого контролера перегляду.

extension UITabBarController {
    public override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
    public override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return visibleViewController
    }
}

Для Swift 3 це не методи, а властивості:

extension UITabBarController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return visibleViewController
    }
}

В Swift 4.2 властивості були перейменовані:

extension UITabBarController {
   open override var childForStatusBarStyle: UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
   open override var childForStatusBarStyle: UIViewController? {
        return visibleViewController
    }
}

Використання

class ViewController: UIViewController {

    // This will be called every time the ViewController appears
    // Works great for pushing & popping
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }

}

6
Це, безумовно, найкраща відповідь (Для додатків, які використовують UINavigationController або UITabBarController
Kesava

1
яке використання для цього?
AnBisw

@Annjawn ці методи використовують UIKit. Вам не потрібно нічого робити, крім того, щоб додати його до свого проекту.
Даніель Вуд

@DanielWood так, я зрозумів це і зовсім забув, що я використав це саме те саме в одному з моїх попередніх проектів, хоча трохи інакше.
AnBisw

Це справді найкраща відповідь
Musa almatri

33

Я, можливо, до цього приїжджаю трохи пізно, але, мабуть, хтось інший шукає робоче і перевірене рішення для широкого застосування.

@mxcl вірно описує, чому це відбувається. Для того, щоб виправити це, ми просто створимо розширення (або категорію в obj-c), яке перекриває переважний методSatusBarStyle () UINavigationController. Ось приклад у Swift:

extension UINavigationController {
    public override func preferredStatusBarStyle() -> UIStatusBarStyle {
        if let rootViewController = self.viewControllers.first {
            return rootViewController.preferredStatusBarStyle()
        }
        return super.preferredStatusBarStyle()
    }
}

Цей код просто витягує перший контролер подання (контролер кореневого виду) і розгортає його (у obj-c просто переконайтеся, що він не нульовий). Якщо видалення вдалося (не нульове), ми захопимо rootViewControllers preferenceStatusBarStyle. Інакше ми просто повернемо дефолт.

Сподіваюся, це допоможе кожному, хто може це потребувати.


2
У Swift 2.0 ви повинні видалити "як? UIViewController" заяви про стан.
Томас Кальмон

Блискуче, я зробив одну модифікацію на додаток до видалення оператора "як", я змінив його з "першого" на "останнього" таким чином, незалежно від того, який контролер перегляду бачить користувач у верхній частині стека, матиме можливість контролювати колір рядка стану. Чудова робота, дякую за обмін!
Unome

1
Якщо у вашому контролері навігації немає контролерів перегляду, це може спричинити нескінченний цикл. return self.preferredStatusBarStyle()зателефонував би до цього саме такого методу.
ведмідьмору

1
У моєму випадку замість використання rootViewController я використовував topViewController, оскільки під час стека стиль може змінюватися.
Рік Сантос

2
@Unome visibleViewControllerбуло б ще краще
Cœur

21

Щоб отримати детальнішу інформацію про прийняту відповідь, введіть такий рядок у didFinishLaunchingWithOptions:спосіб делегата додатка :

[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;

Потім у своєму Info.plist додайте View controller-based status bar appearanceта встановіть його NO.

Я вважаю, що так слід робити, НЕ від навігаційного контролера, якщо ви хочете однаковий колір рядка стану для всього додатка. Можливо, у вас є екрани, які не обов’язково вбудовані в UINavigationController, або інший UINavigationControllerпідклас десь інше та інші речі.

РЕДАКТУВАННЯ . Ви також можете це зробити, не вводячи жодного коду: https://stackoverflow.com/a/18732865/855680


1
Зауважте, що цей спосіб застарілий з IOS 9.0
Мохамед Салах

10

У viewDidLoad просто напишіть це

[self setNeedsStatusBarAppearanceUpdate];

просто зроби це, і воно спрацює

Ви можете, будь ласка, спробуйте це

Set UIViewControllerBasedStatusBarAppearance to NO.
Call [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

Ще одне, що я бачив у вашому запитанні, що ви написали такий метод

 -(void)UIStatusBarStyle PreferredStatusBarStyle ()
        {
            return UIStatusBarStyle.LightContent;
        }

але воно має бути таким

-(UIStatusBarStyle)preferredStatusBarStyle{ 
    return UIStatusBarStyleLightContent; 
} 

Це викликає виклик кращого методуStatusBarStyle, але все ж рядок стану є чорним.
Ендрю Сміт

будь ласка, дивіться мою оновлену відповідь. Повідомте мене швидко, чи працює це чи ні
Користувач 1531343

У моєму первісному запитанні прямо написано, що мені потрібно переглядати, переглядаючи панель стану.
Ендрю Сміт

Ви можете, будь ласка, перевірити свій код із посиланням на моє оновлене питання?
Користувач 1531343

1
[self setNeedsStatusBarAppearanceUpdate];такий чудовий метод, дякую!
Supertecnoboff

6

Ось як я це вирішив. Зазвичай навігаційний контролер або tabBarController визначають зовнішній вигляд рядка стану (прихований, колір тощо).

Таким чином я закінчив підкласифікацію навігаційного контролера і переосмислив перевагуStatusBarStyle. якщо поточний видимий ViewContorller реалізує StatusBarStyleHandler, я прошу, щоб значення використовувалося як стиль, якщо це не так, я просто повертаю значення за замовчуванням.

Спосіб запуску оновлення зовнішнього вигляду рядка стану - це виклик, setNeedsStatusBarAppearanceUpdateякий запускається preferredStatusBarStyleзнову та оновлення інтерфейсу користувача відповідно до методу повернення

public protocol StatusBarStyleHandler {
    var preferredStatusBarStyle: UIStatusBarStyle { get }
}

public class CustomNavigationCotnroller: UINavigationController {

    public override var preferredStatusBarStyle: UIStatusBarStyle {
        if let statusBarHandler = visibleViewController as? StatusBarStyleHandler {
            return statusBarHandler.preferredStatusBarStyle
        }

        return .default
    }
}

Потім використання

public class SomeController: UIViewController, StatusBarStyleHandler {

    private var statusBarToggle = true

    // just a sample for toggling the status bar style each time method is called
    private func toggleStatusBarColor() {
        statusBarToggle = !statusBarToggle
        setNeedsStatusBarAppearanceUpdate()
    }

    public override var preferredStatusBarStyle: UIStatusBarStyle {
        return statusBarToggle ? .lightContent : .default
    }
}

Ця публікація буде значно покращена, якби ви могли пояснити, чому і як це вирішує проблему.

Замість підкласифікації UINavigationController ви можете просто створити розширення для UINavigationController і досягти того ж результату, не потребуючи підкласу.
квітня

4

1) Один параметр для всього проекту:

Якщо це можливо, вийміть UIViewControllerBasedStatusBarAppearanceпару ключових значень із списку info.plist або встановіть, NOне виймаючи його. Якщо це недоступно у вашому інформаційному списку, нічого не робіть. Типово - NOце властивість.

Додайте код нижче до свого AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}

2) різні налаштування для різних контролерів перегляду:

Додайте UIViewControllerBasedStatusBarAppearanceпару ключових значень до свого списку info.plist і встановіть йогоYES .

Якщо ваш контролер перегляду не вбудований у контролер навігації. Скажімо, MyViewController. просто додайте код нижче до свого файлу MyViewController.m. Якщо ваш контролер перегляду вбудований в навігаційний контролер, створіть новий сенсорний клас какао та зробіть його підкласом UINavigationController. Скажімо, MyNC. На правій панелі виберіть пункт «Перегляд контролера навігації» на панелі розкадрувань; Утиліти -> Інспектор ідентичності -> Спеціальний клас -> Клас, тип "MyNC". Пов’язавши перегляд аркушів розкадрування з сенсорним класом какао "MyNC", додайте код нижче до свого MyNC.m:

- (BOOL)prefersStatusBarHidden {
    return NO;
}

-(UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}

Здається, в iOS9 UIViewControllerBasedStatusBarAppearance iOS9 за замовчуванням містить значення ТАК, як мені потрібно було додати його вручну в .plist і встановити НІ для нормальної роботи.
Мохд Асим

4

Навіть з усіма відповідями тут я все ще не знайшов для мене точного рішення, але почав з відповіді Даніеля. З чим я закінчився:

override var preferredStatusBarStyle: UIStatusBarStyle {
     return visibleViewController?.preferredStatusBarStyle ?? .lightContent
}

у контролерах навігації (схоже на вкладку, щойно вибранеViewController). І тоді він буде поважати:

override var preferredStatusBarStyle: UIStatusBarStyle {
     return .lightContent
}

У кожному контролері перегляду, якщо ви не встановите інше. Мені не потрібно дзвонити setNeedsStatusBarAppearanceUpdate()куди завгодно, він просто оновлюється, коли ви приїжджаєте до кожного контролера перегляду.


2
Я закінчився майже однаковим рішенням, бо боровся з цим годинами.
Скотт Юнгвірт

У якийсь момент це, здається, було виправлено, просто використання перевагStatusBarStyle в кожному ВК зараз працює для мене добре.
Ендрю Пламмер

4

Рішення для iOS 13

Відповідь, котра має найвищий голос, використовує "застарілий" код 👎

Встановлення barStyleвластивості (iOS 13+) вважається "застарілим налаштуванням". За словами Apple ,

В iOS 13 та новіших версіях налаштуйте панель навігації за допомогою властивостей standardAppearance, compactAppearance та scrollEdgeAppearance. Ви можете продовжувати використовувати ці застарілі аксесуари для налаштування зовнішнього вигляду панелі навігації безпосередньо, але ви повинні оновити зовнішній вигляд для різних конфігурацій панелі.

Щодо вашої спроби - ви були на правильному шляху!

UINavigationControllerє підкласом UIViewController(хто знав 🙃)!

Тому, представляючи контролери перегляду, вбудовані в контролери навігації, ви насправді не представляєте вбудовані контролери перегляду; Ви представляєте контролери навігації! UINavigationController, як підклас UIViewController, успадковує preferredStatusBarStyleі childForStatusBarStyle, який ви можете встановити за бажанням.

Будь-який із наступних методів повинен працювати:

  1. Перевизначення preferredStatusBarStyleв межахUINavigationController

    • preferredStatusBarStyle ( doc ) - бажаний стиль рядка стану для контролера перегляду
    • Підклас або розширення UINavigationController

      class MyNavigationController: UINavigationController {
          override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }

      АБО

      extension UINavigationController {
          open override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }
  2. Перевизначення childForStatusBarStyleв межахUINavigationController

    • childForStatusBarStyle( док ) - Викликається, коли системі потрібен контролер перегляду, який використовується для визначення стилю рядка стану
    • Згідно з документацією Apple,

      "Якщо ваш контролер перегляду контейнерів отримує свій стиль рядка стану від одного з його дочірніх контролерів перегляду, [замініть цю властивість] і поверніть цей дочірній контролер подання. Якщо ви повернете нуль або не замініть цей метод, використовується стиль рядка стану для себе Якщо значення повернення цього методу змінюється, викличте метод setNeedsStatusBarAppearanceUpdate (). "

    • Іншими словами, якщо ви не реалізуєте рішення 3 тут, система повернеться до рішення 2 вище.
    • Підклас або розширення UINavigationController

      class MyNavigationController: UINavigationController {
          override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }

      АБО

      extension UINavigationController {    
          open override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }
    • Ви можете повернути будь-який контролер перегляду, який ви хотіли б вище. Я рекомендую одне з наступних:

      • topViewController(of UINavigationController) ( док ) - Контролер перегляду у верхній частині навігаційного стеку
      • visibleViewController(of UINavigationController) ( doc ) - контролер перегляду, пов'язаний з видимим в даний час поданням в навігаційному інтерфейсі (підказка: сюди можна включити "контролер подання, який був представлений модально над самим контролером навігації")

Примітка: Якщо ви вирішили підклас UINavigationController, не забудьте застосувати цей клас до своїх контролерів nav через контролера ідентичності в IB.

PS Мій код використовує синтаксис Swift 5.1 😎


1
Дуже повна відповідь, дякую! Крім того, з чим я боровся деякий час, в iOS 13 .defaultстиль враховує темний режим, і це не документально підтверджено, тому якщо ви також підтримуєте попередні версії iOS, ви можете додати, if #available(iOS 13, *) { return .darkContent } else { return .default }якщо ви намагаєтеся налаштувати стиль рядка стану вручну відповідно до колір за рядком стану, і цей колір "яскравий".
valcanaia

1
Зауважте, що метод розширення для заміщення var більше не працює в Xcode 11.4 / iOS 13.4
Marc Etcheverry,

Оскільки розширення об'єктивних класів C у Swift реалізується через цілі C категорії. Перевизначення методів через цілі C категорій не рекомендується і, ймовірно, може порушитися. Дивіться stackoverflow.com/a/38274660/2438634
Marc Etcheverry

Незважаючи на те, що переосмислення UINavigationController безумовно працює, це схоже на помилку на стороні Apple, що він не робить дочірнього ForStatusBarStyle, за замовчуванням повертаючи його topViewController. Наприклад, UITabBarController робить це для своїх вкладок. Для мене немає причин, чому UINavigationController, будучи суто контролером контейнерів для розміщення "справжніх" контролерів перегляду, а не для представлення власного інтерфейсу, повинен "з'їдати" ці стилі смуги стану. Створить радари для Apple.
Ігор Василев

1

Якщо ви хочете приховати статусBar під час splashScreen, але хочете змінити стиль на світлий вміст (StatusBarInitiallyHidden у Plist має бути НІ, щоб приховати статусBar на сплеску), ви можете додати це до методу didFinishLaunchingWithOptions appDelegate для зміни на lightContent.

[[UIApplication sharedApplication]setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent];

1

швидкий приклад

в AppDelegate.swift

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent;

    return true
}

у встановленому списку info.plist Перегляд зовнішнього вигляду на основі контролера: НІ


1

Якщо ви використовуєте NavigationController, ви можете підклас, NavigationControllerщоб він звертався до контролера дочірнього перегляду

// MyCustomNavigationController

- (NSUInteger)supportedInterfaceOrientations {
    UIViewController *viewControllerToAsk = [self findChildVC];
    return [viewControllerToAsk supportedInterfaceOrientations];
}

- (BOOL)shouldAutorotate {
    UIViewController *viewControllerToAsk = [self findChildVC];
    return [viewControllerToAsk shouldAutorotate];
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    UIViewController *viewControllerToAsk = [self findChildVC];
    return [viewControllerToAsk preferredStatusBarStyle];
}

- (UIViewController *)findChildVC {
    return self.viewControllers.firstObject;
}

1

Швидкий 4.2

extension UITabBarController {
    open override var childForStatusBarStyle: UIViewController? {
        return selectedViewController
    }
}

extension UINavigationController {
    open override var childForStatusBarStyle: UIViewController? {
        return visibleViewController
    }
}

Зауважте, що метод розширення для заміщення var більше не працює в Xcode 11.4 / iOS 13.4
Marc Etcheverry,

@MarcEtcheverry так, чому ти спростував відповідь? здається дивним.
В’ячеслав

Оскільки розширення об'єктивних класів C у Swift реалізується через цілі C категорії. Перевизначення методів через цілі C категорій не рекомендується і, ймовірно, може порушитися. Дивіться stackoverflow.com/a/38274660/2438634
Marc Etcheverry

@MarcEtcheverry 'не рекомендується'! = 'Ніколи не використовуй!'. для липня 2018 року відповідь була правильною. Навіть ця відповідь не є актуальною, це не є підставою для заборони її. Я не бачу майбутнього
В’ячеслав

0

Ви можете встановити стиль рядка стану. Він буде нагадувати рядок стану, як IOS 6 і нижче.
Вставте ці способи у контролер перегляду

-(UIStatusBarStyle)preferredStatusBarStyle{
    return UIStatusBarStyleBlackOpaque;
}

і виклик цього методу з виду зробив завантаження, як це

if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f)
    {
       [self setNeedsStatusBarAppearanceUpdate];
    }

Ви маєте на увазі [self setStatusBarNeedsUpdate]у другому блоці? (Або щонайменше щось інше).
mxcl

0

Я просто хочу додати примітку до конкретного випадку, з яким я стикався. У мене було ще одне вікно інтерфейсу користувача у моєму додатку для відображення чату, яке постійно плаває по моєму додатку. Це не призвело до того, що жодне з вищезазначених рішень не спрацювало, і я не дуже впевнений, чому! Все, що я помітив, це те, що мій ViewController у новому вікні UIW був причиною цього! І якщо я хотів змінити стиль рядка стану, я повинен це зробити в цьому контролері перегляду нового вікна UIW.

Ця примітка може допомогти іншим, хто має подібну структуру! Таким чином, ви можете застосувати рішення, згадані вище, у ViewController нового вікна UIW.

Знову це конкретний випадок.

Дякую


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.