prefertsBarStyle çağrılmaz


257

Geçersiz kılmak için bu iş parçacığını izledim -preferredStatusBarStyle, ancak çağrılmıyor. Etkinleştirmek için değiştirebileceğim herhangi bir seçenek var mı? (Projemde XIB kullanıyorum.)


Hangi bağlamda çağrılmaz: simülatör? bir cihazda?
bneely

@bneely ikisi de.
trgoofi

Bir iOS 7 cihazı olan iOS 7 simülatörünü mi kullanıyorsunuz ve temel SDK'nız 7,0 mı?
bneely

@bneely iOS SDK 7.0 proje adımın altında gösteriliyor, bu temel SDK'mın 7.0 olduğu anlamına mı geliyor?
trgoofi

Derleme ayarlarında, "Temel SDK" değerin ayarlandığı yerdir. Projeniz 7.0'a ayarlanmış gibi görünüyor.
bneely

Yanıtlar:


117

Olası kök neden

Aynı sorunu yaşadım ve uygulama penceremde kök görünüm denetleyicisini ayarlamadığım için bunun olduğunu anladım.

UIViewControllerBen hayata geçirdiklerini ettiği preferredStatusBarStylebir kullanılmıştır UITabBarControllerekranda görüşleri görünümünü kontrol, hangi.

Kök görünüm denetleyicisini buna işaret edecek şekilde ayarladığımda, UITabBarControllerdurum çubuğu değişiklikleri beklendiği gibi düzgün çalışmaya başladı (ve preferredStatusBarStyleyöntem çağrıldı).

(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ... // other view controller loading/setup code

    self.window.rootViewController = rootTabBarController;
    [self.window makeKeyAndVisible];
    return YES;
}

Alternatif yöntem (iOS 9'da kullanımdan kaldırıldı)

Alternatif olarak, arka plan rengine bağlı olarak, kullanmak yerine, görünüm denetleyicilerinizin her birinde aşağıdaki yöntemlerden birini uygun şekilde çağırabilirsiniz setNeedsStatusBarAppearanceUpdate:

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

veya

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

Ayrıca sette gerekeceğini Not UIViewControllerBasedStatusBarAppearanceiçin NObu yöntemi kullanırsanız plist dosyasında.


2
Kök görünümü denetleyicisini ayarlamamanla seninle aynı sorunum var. Bunu nasıl buldun?
trgoofi

1
Çerçevedeki bir şeyin bildirimi almadığından setNeedsStatusBarAppearanceUpdateşüphelendim - bu değişikliği yaptığımda şüphelerim doğrulandı.
AbdullahC

2
Bir uygulamada bulduğum ilgili bir sorun, childViewControllerForStatusBarStyle ve childViewControllerForStatusBarHidden geçersiz kılınan tam ekran alt görünüm denetleyicisine sahip bir görünüm denetleyicisiydi. Kendi görünüm denetleyicisi hiyerarşiniz varsa, durum çubuğu stilini belirlemek için hangi görünüm denetleyicisinin kullanılması gerektiğini sisteme bildirmek için bu yöntemleri sağlamanız gerekir.
Jon Steinmetz

rootviewcontroller'ı ayarlamak hiçbir şeyi değiştirmez. Jon'un yorumuyla çalışmalısın. Ve setneedsstatusbarappearanceUpdate'i çağırırken dikkatli olun. Çalışmak için ebeveynden çağırmalısınız.
doozMen

1
@ Hippo sen dahisin !! Bunun rootviewcontroller'ı ayarlamadığı için nasıl buldunuz?
ViruMax

1020

UINavigationController kullanan herkes için:

Bu UINavigationController, preferredStatusBarStyleçağrıları alt görünüm denetleyicilerine iletmez . Bunun yerine kendi durumunu yönetir - olması gerektiği gibi, ekranın üst kısmında durum çubuğunun yaşadığı ve bu nedenle bundan sorumlu olması gereken çizimi çizer. Bunun içinpreferredStatusBarStyle VC'lerinizde bir nav denetleyicisi içinde yapmak hiçbir şey yapmaz - bunlar asla çağrılmaz.

Hüner nedir UINavigationControlleriçin dönmeye karar için kullandığı UIStatusBarStyleDefaultya UIStatusBarStyleLightContent. Bunu dayandırıyor UINavigationBar.barStyle. Varsayılan ( UIBarStyleDefault), karanlık ön plan UIStatusBarStyleDefaultdurum çubuğuyla sonuçlanır . Ve UIBarStyleBlackbirUIStatusBarStyleLightContent durum çubuğu .

TL; DR:

UIStatusBarStyleLightContentBir UINavigationControllerkullanım istiyorsanız :

self.navigationController.navigationBar.barStyle = UIBarStyleBlack;

60
Güzel! O Not preferredStatusBarStyleEğer (set gezinti çubuğunu gizlemek durumunda aslında irade çocuk görünümü denetleyicisinde denilen olsun navigationBarHiddeniçin YES) tam uygun olarak,.
Patrick Pijnappel

25
Bu cevap için teşekkürler. BarStyle'ı tüm gezinme çubuklarınız için ayarlamak istiyorsanız, arayın[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack]
Thomas Desert

15
Mükemmel cevap. SO üzerindeki diğer cevapların hiçbiri UINavigationController'ı dikkate almadı. 2 saat başımı klavyeye vurarak.
Ryan Alford

11
Belirten yönelik @Patrick şeref navigationBarHiddenseti için YESaslında olacaktır preferredStatusBarStyledenir ve bu rastlamak ihtimali olanlarla bir uyarı: Bu çalışır navigationBarHidden, ancak birlikte navigationBar.hidden!
jcaron

4
açık olmalıdır, ancak bunun çalışması için Info.plist'te "Denetleyici tabanlı durum çubuğu görünümünü görüntüle" de EVET olarak ayarlamanız gerekir.
Kod Baller

99

Bu yüzden aslında UINavigationController için bir kategori ekledim ama yöntemleri kullandım:

-(UIViewController *)childViewControllerForStatusBarStyle;
-(UIViewController *)childViewControllerForStatusBarHidden;

ve mevcut görünür UIViewController'ı döndürdü. Bu, mevcut görünür görünüm denetleyicisinin kendi tercih ettiği stili / görünürlüğü ayarlamasını sağlar.

İşte bunun için tam bir kod snippet'i:

Swift'te:

extension UINavigationController {

    public override func childViewControllerForStatusBarHidden() -> UIViewController? {
        return self.topViewController
    }

    public override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return self.topViewController
    }
}

Hedef-C'de:

@interface UINavigationController (StatusBarStyle)

@end

@implementation UINavigationController (StatusBarStyle)

-(UIViewController *)childViewControllerForStatusBarStyle {
    return self.topViewController;
}

-(UIViewController *)childViewControllerForStatusBarHidden {
    return self.topViewController;
}

@end

Ve iyi bir ölçü için, bir UIViewController'da nasıl uygulandığı aşağıda açıklanmıştır:

Swift'te

override public func preferredStatusBarStyle() -> UIStatusBarStyle {
    return .LightContent
}

override func prefersStatusBarHidden() -> Bool {
    return false
}

Hedef-C'de

-(UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent; // your own style
}

- (BOOL)prefersStatusBarHidden {
    return NO; // your own visibility code
}

Son olarak, emin olun uygulama Plist gelmez DEĞİL NO "Görünüm denetketiyicili durum çubuğu görünümü" set var. Ya bu satırı silin ya da EVET olarak ayarlayın (ki şimdi iOS 7 için varsayılan olduğuna inanıyorum?)


return self.topViewController;Benim için çalışıyor gibi görünüyor , ama return self.visibleViewController;- değil
k06a

visibleViewController şu anda sunulan kalıcı denetleyiciyi kapattığınızda geri dönebilir. Hangi bummer. TopViewController kullanın.
Ben Sinclair

1
@ d.lebedev tamam, ama bu sorunların hiçbirinin burada geçerli olduğunu düşünmüyorum. superBu yöntemi çağırmanız gerekmez ve aslında bu tür tüm denetleyicilerin davranışlarını değiştirmek istersiniz
ed '

1
bu benim için iOS 9.3'te çalışmıyor. Sanırım, sorun bu: Kakao sınıflarının birçoğu kategoriler kullanılarak uygulandığından bu sorun özellikle önemlidir. Geçersiz kılmaya çalıştığınız çerçeve tanımlı bir yöntemin kendisi bir kategoride uygulanmış olabilir ve bu nedenle hangi uygulama önceliğe sahip değildir.
vikingosegundo

2
Bu yanlış ve iOS 13.4'te kırılıyor. Çünkü Swift'te objektif C sınıflarını genişletmek Objective C kategorileri aracılığıyla uygulanır. Objective C kategorileri üzerinden geçersiz kılma yöntemleri önerilmez ve kırılması muhtemeldir. Bkz. Stackoverflow.com/a/38274660/2438634
Marc Etcheverry

79

Hala bununla mücadele eden herkes için, hızlı bir şekilde bu basit uzantı sizin için sorunu çözmelidir.

extension UINavigationController {
    override open var childForStatusBarStyle: UIViewController? {
        return self.topViewController
    }
}

10
Efendim bir madalyayı hak ediyorsun.
nikans

2
Çok teşekkür ederim dostum. Ben başarı ile visibleViewController yerine iade edildi.
Fábio Salata

1
Bu altın. Bir sekme çubuğuna gömülü bir gezinme denetleyicim var ve bunu bir dosyaya attım ve şimdi durum çubuğu görünümünü istediğim yerde değiştirebilirim.
Vahid Amiri

2
Bu yanlış ve iOS 13.4'te kırılıyor. Çünkü Swift'te objektif C sınıflarını genişletmek Objective C kategorileri aracılığıyla uygulanır. Objective C kategorileri üzerinden geçersiz kılma yöntemleri önerilmez ve kırılması muhtemeldir. Bkz. Stackoverflow.com/a/38274660/2438634
Marc Etcheverry

1
@MarcEtcheverry bu özel örnek yanlış değildi. Mesele şu ki, UINavigationController gibi diğer nesnelerin / protokollerin alt sınıfları dinamik dağıtımda çakışmak için bunları önceden uygulamamışlardır. Gerçek alt sınıflar içinde herhangi bir varsayılan veya uygulama yoktu, bu yüzden bu, gereksiz bir bağımlılık (dönem) oluşturmadan bunu bir uygulamada uygulamanın en temiz yoluydu. Ne yazık ki, 13.4 bu davranışı değiştirmiş görünüyor. Ben yıllardır var olmayan bir kontrol veya uygulama var perde arkasında tahmin .........
TheCodingArt

20

Benim app her üç kullandı: UINavigationController, UISplitViewController, UITabBarController, böylece bunların hepsi durum çubuğunun üzerine kontrol altına almak gibi görünüyor ve neden olacaktır preferedStatusBarStyleçocukları için çağrılacak değil. Bu davranışı geçersiz kılmak için, yanıtların geri kalanı gibi bir uzantı oluşturabilirsiniz. İşte Swift 4'te her üçü için bir uzantı. Apple bu tür şeyler hakkında daha açık olsaydı.

extension UINavigationController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return self.topViewController
    }

    open override var childViewControllerForStatusBarHidden: UIViewController? {
        return self.topViewController
    }
}

extension UITabBarController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return self.childViewControllers.first
    }

    open override var childViewControllerForStatusBarHidden: UIViewController? {
        return self.childViewControllers.first
    }
}

extension UISplitViewController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return self.childViewControllers.first
    }

    open override var childViewControllerForStatusBarHidden: UIViewController? {
        return self.childViewControllers.first
    }
}

Düzenleme: Swift 4.2 API değişiklikleri için güncelleme

extension UINavigationController {
    open override var childForStatusBarStyle: UIViewController? {
        return self.topViewController
    }

    open override var childForStatusBarHidden: UIViewController? {
        return self.topViewController
    }
}

extension UITabBarController {
    open override var childForStatusBarStyle: UIViewController? {
        return self.children.first
    }

    open override var childForStatusBarHidden: UIViewController? {
        return self.children.first
    }
}

extension UISplitViewController {
    open override var childForStatusBarStyle: UIViewController? {
        return self.children.first
    }

    open override var childForStatusBarHidden: UIViewController? {
        return self.children.first
    }
}

1
Bu işe yarayan tek çözümdür. SO'daki tüm yanıtlar, NavigationControllers ile hiçbir uygulama için çalışmayan standart çözümü gösterir. Teşekkür ederim!!!
Houman

Geçersiz kılma için uzantıları kullanmak yanlıştır. Bu güvenli değil. Birden çok daha basit çözüm var. Bunun yerine bir alt sınıf kullanın.
Sulthan

2
Bu yanlış ve iOS 13.4'te kırılıyor. Çünkü Swift'te objektif C sınıflarını genişletmek Objective C kategorileri aracılığıyla uygulanır. Objective C kategorileri üzerinden geçersiz kılma yöntemleri önerilmez ve kırılması muhtemeldir. Bkz. Stackoverflow.com/a/38274660/2438634
Marc Etcheverry

1
@MarcEtcheverry bu özel örnek yanlış değildi. Mesele şu ki, UINavigationController gibi diğer nesnelerin / protokollerin alt sınıfları dinamik dağıtımda çakışmak için bunları önceden uygulamamışlardır. Gerçek alt sınıflar içinde herhangi bir varsayılan veya uygulama yoktu, bu yüzden bu, gereksiz bir bağımlılık (dönem) oluşturmadan bunu bir uygulamada uygulamanın en temiz yoluydu. Ne yazık ki, 13.4 bu davranışı değiştirmiş görünüyor. Ben yıllardır var olmayan bir kontrol veya uygulama var perde arkasında tahmin .........
TheCodingArt

15

Durum çubuğu rengini beyaz olarak değiştirmek için Tyson'ın yanıtı doğrudurUINavigationController .

Herkes kodunu yazarak aynı sonucu elde etmek istiyorsa, AppDelegateaşağıdaki kodu kullanın ve AppDelegate's didFinishLaunchingWithOptionsyöntemi içine yazın .

Ve ayarlamak unutmayın UIViewControllerBasedStatusBarAppearanceiçin YESbaşka değişiklik yansıtmaz, .plist dosyada.

kod

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     // status bar appearance code
     [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

     return YES;
}

14

Bir UINavigationController üzerinde preferredStatusBarStyleçağrılmaz çünkü topViewControllertercih edilir self. Yani, preferredStatusBarStylebir UINavigationController çağırmak için, değiştirmeniz gerekir childViewControllerForStatusBarStyle.

Öneri

Sınıfınızdaki UINavigationController'ınızı geçersiz kılın:

class MyRootNavigationController: UINavigationController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    override var childViewControllerForStatusBarStyle: UIViewController? {
        return nil
    }
}

Tavsiye edilmeyen alternatif

Tüm UINavigationController için bunu yapmak için bir uzantıda geçersiz kılabilirsiniz (uyarı: UIDocumentPickerViewController, UIImagePickerController, vb. Etkiler), ancak muhtemelen Swift belgelerine göre yapmamalısınız :

extension UINavigationController {
    open override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return nil
    }
}

11

Serenn'in cevabına ek olarak, modalPresentationStyle(örneğin .overCurrentContext) bir görünüm kontrolörü sunuyorsanız , bunu yeni sunulan görünüm kontrol cihazında da çağırmalısınız:

presentedViewController.modalPresentationCapturesStatusBarAppearance = true

preferredStatusBarStyleSunulan görünüm denetleyicisinde de geçersiz kılmayı unutmayın .


9

Hippo'nun cevabına ek olarak: bir UINavigationController kullanıyorsanız, bir kategori eklemek muhtemelen daha iyidir:

//  UINavigationController+StatusBarStyle.h:

@interface UINavigationController (StatusBarStyle)

@end



//  UINavigationController+StatusBarStyle.m:

@implementation UINavigationController (StatusBarStyle)

- (UIStatusBarStyle)preferredStatusBarStyle
{
    //also you may add any fancy condition-based code here
    return UIStatusBarStyleLightContent;
}

@end

Bu çözüm, yakında kullanımdan kaldırılacak davranışa geçmekten daha iyidir.


Bunu yapma, şimdilik çalışıyor ama gelecekteki davranışları kırabilir. Sadece navBar stilini değiştirin - cevabımı görün stackoverflow.com/a/19513714/505457
Tyson

2
Kategori değil alt sınıf kullanmalısınız.
shuiyouren

2Tyson: Neden gelecekteki davranışları kıracak? preferSBtusBarStyle: Durum Çubuğu stilini ayarlamak için Apple'ın tercih ettiği yöntemdir.
Artem Abramov

2shuiyouren: Sadece bir kategori kullanabilir ve istediğim her yere dahil edebilirsem neden alt sınıflama ile karmaşıklığı arttırmalıyım? Her neyse, bu bir mimari meselesi, uygulama değil.
Artem Abramov

2
@ArtemAbramov Çünkü UINavigationController zaten uygular preferredStatusBarStyleve UINavigationController'a özgü mantık yapar. Şu anda bu mantık dayanmaktadır, navigationBar.barStyleancak ek kontroller ekleniyor görebilirsiniz (örneğin UISearchDisplayControllernavbar modunu gizlemek için hareket). Varsayılan mantığı geçersiz kılarak, tüm bu işlevleri kaybedersiniz ve kendinizi gelecekte can sıkıcı 'wtf' anlarına açık bırakırsınız. Dahili gezinme denetleyicisi davranışını desteklemeye devam ederken, bunu yapmanın doğru yolu için yukarıdaki cevabıma bakın.
Tyson

9

Swift 4.2 ve üstü

Seçilen yanıtta belirtildiği gibi , temel neden pencere kök görünümü denetleyici nesnesini kontrol etmektir.

Akış yapınızın olası vakaları

  • Özel UIViewController nesnesi pencere kök görünümü denetleyicisidir

    Pencere kök görünümü denetleyiciniz bir UIViewController nesnesidir ve ayrıca uygulama akışınıza bağlı olarak gezinti denetleyicisi veya tabController ekler veya kaldırır.

    Bu tür akış genellikle, uygulamanızda sekmeler olmadan gezinme yığınında ön giriş akışı ve sekmelerle giriş sonrası akış varsa ve muhtemelen her sekmede gezinme denetleyicisi bulunursa kullanılır.

  • TabBarController nesnesi pencere kök görünümü denetleyicisidir

    Bu, pencere kök görünümü denetleyicisinin tabBarController olduğu akıştır, muhtemelen her sekme daha fazla gezinme denetleyicisini tutar.

  • NavigationController nesnesi pencere kökü görüntüleme denetleyicisidir

    Bu, pencere kökü görüntüleme denetleyicisinin navigationController olduğu akıştır.

    Varolan bir gezinme denetleyicisine sekme çubuğu denetleyicisi veya yeni gezinme denetleyicisi ekleme olanağı olup olmadığından emin değilim. Ancak böyle bir durum varsa, durum çubuğu stil kontrolünü bir sonraki kaba aktarmamız gerekir. Bu yüzden bulmak için UINavigationController uzantısına aynı denetimi ekledimchildForStatusBarStyle

Aşağıdaki uzantıları kullanın, yukarıdaki senaryoların tümünü işler -

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

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

extension AppRootViewController {
    open override var preferredStatusBarStyle: UIStatusBarStyle {
        return children.first { $0.childForStatusBarStyle != nil }?.childForStatusBarStyle?.preferredStatusBarStyle ?? .default
    }
}
  • Varsayılan olarak doğru olarak UIViewControllerBasedStatusBarAppearanceanahtar girmenize gerek yokturinfo.plist

Daha karmaşık akışlar için dikkat edilmesi gereken noktalar

  • Modal olarak yeni akış sunmanız durumunda, mevcut durum çubuğu stil akışından ayrılır. Bu nedenle, bir NewFlowUIViewControllernavigasyon cihazı sunduğunuzu varsayalım ve ardından yeni gezinme veya tabBar denetleyicisi NewFlowUIViewControllerekledikten sonra NewFlowUIViewControllerdaha fazla görünüm denetleyicisinin durum çubuğu stilini yönetmek için de uzantı ekleyin .

  • Eğer set modalPresentationStyle dışındaki fullScreenmodally sunarken, ayarlamanız gerekir modalPresentationCapturesStatusBarAppearancebu sunulan görünüm denetleyicisi durum çubuğu görünümü kontrolünü almalıdır böylece true.


Mükemmel cevap!
Amin Benarieb

3
Bu yanlış ve iOS 13.4'te kırılıyor. Çünkü Swift'te objektif C sınıflarını genişletmek Objective C kategorileri aracılığıyla uygulanır. Objective C kategorileri üzerinden geçersiz kılma yöntemleri önerilmez ve kırılması muhtemeldir. Bkz. Stackoverflow.com/a/38274660/2438634
Marc Etcheverry

@MarcEtcheverry bu özel örnek yanlış değildi. Mesele şu ki, UINavigationController gibi diğer nesnelerin / protokollerin alt sınıfları dinamik dağıtımda çakışmak için bunları önceden uygulamamışlardır. Gerçek alt sınıflar içinde herhangi bir varsayılan veya uygulama yoktu, bu yüzden bu, gereksiz bir bağımlılık (dönem) oluşturmadan bunu bir uygulamada uygulamanın en temiz yoluydu. Ne yazık ki, 13.4 bu davranışı değiştirmiş görünüyor. Ben yıllardır var olmayan bir kontrol veya uygulama var perde arkasında tahmin .........
TheCodingArt

8

iOS 13 Çözümleri

UINavigationController bir alt sınıfıdır UIViewController(kim bilir sub) sınıftır!

Bu nedenle, gezinme denetleyicilerine katıştırılmış görünüm denetleyicilerini sunarken, katıştırılmış görünüm denetleyicilerini gerçekten sunmuyorsunuz; navigasyon denetleyicilerini sunuyorsunuz! UINavigationController, alt sınıfı olarak UIViewController, devralınır preferredStatusBarStylevechildForStatusBarStyle istediğiniz şekilde ayarlayabilirsiniz.

Aşağıdaki yöntemlerden herhangi biri çalışmalıdır:

  1. Karanlık Moddan tamamen çıkın
    • Sizin info.plist şu mülkü ekleyin:
      • Anahtar - UIUserInterfaceStyle (diğer adıyla "Kullanıcı Arayüzü Stili")
      • Değer - Işık
  2. preferredStatusBarStyleIçinde geçersiz kılUINavigationController

    • preferredStatusBarStyle( doc ) - Görünüm denetleyicisi için tercih edilen durum çubuğu stili
    • Alt sınıf veya genişletme UINavigationController

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

      VEYA

      extension UINavigationController {
          open override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }
  3. childForStatusBarStyleIçinde geçersiz kılUINavigationController

    • childForStatusBarStyle( doc ) - Sistemin durum çubuğu stilini belirlemek için görünüm denetleyicisine ihtiyacı olduğunda çağrılır
    • Apple'ın belgelerine göre,

      "Kapsayıcı görünüm denetleyiciniz durum çubuğu stilini alt görünüm denetleyicilerinden birinden alıyorsa, [bu özelliği geçersiz kıl] ve bu alt görünüm denetleyicisini döndürür. Nil döndürürseniz veya bu yöntemi geçersiz kılmazsanız, kendi kendine ilişkin durum çubuğu stili kullanılır Bu yöntemden döndürülen değer değişirse, setNeedsStatusBarAppearanceUpdate () yöntemini çağırın. "

    • Başka bir deyişle, burada çözüm 3'ü uygulamazsanız, sistem yukarıdaki çözüm 2'ye geri döner.
    • Alt sınıf veya genişletme UINavigationController

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

      VEYA

      extension UINavigationController {    
          open override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }
    • Yukarıda istediğiniz herhangi bir görünüm denetleyicisini iade edebilirsiniz. Aşağıdakilerden birini öneririm:

      • topViewController(of UINavigationController) ( doc ) - Gezinme yığınının üst kısmındaki görünüm denetleyicisi
      • visibleViewController(of UINavigationController) ( doc ) - Gezinme arayüzünde o anda görülebilen görünümle ilişkilendirilmiş görünüm denetleyicisi (ipucu: bu, "gezinme denetleyicisinin üzerinde kalıcı olarak sunulan bir görünüm denetleyicisini" içerebilir)

Not: Alt sınıfa karar verirseniz UINavigationController, IB'deki kimlik denetçisi aracılığıyla bu sınıfı nav denetleyicilerinize uygulamayı unutmayın.

PS Kodum Swift 5.1 sözdizimini kullanıyor 😎


Ekran döndürüldükten sonra durum çubuğum kararıyor. Neden olduğu hakkında bir fikrin var mı? Bu yalnızca iPad Pro simülatöründe olur.
Pedro Paulo Amorim

@PedroPauloAmorim, daha fazla bilgi verebilir misiniz? Üstten görünüm denetleyicisi nasıl sunulur (kalıcı, tam ekran, gösteri)? Bir gezinti denetleyicisinin içine yuvalanmış mı? Metin siyah mı yoksa arka plan mı? Ne yapmaya çalışıyorsun?
Andrew Kirna

Uygulamamın tümünde ışık durumu çubuğunu ayarladım. İki rotasyonda ışık alır, üçüncüsünde kararır ve asla ışığa dönmez, hatta onu yeniden çizmeye zorlar. İPad Pro simülatöründe oluyor. Görünümler tam ekran olarak sunuluyor ve bir gezinti denetleyicisinin içinde yuvalanmıyorlar. Yalnızca metin kararır.
Pedro Paulo Amorim

Işık durum çubuğunu ilk etapta nasıl ayarlıyorsunuz?
Andrew Kirna

3
Uzantı üzerinden geçersiz kılma işleminiz gerçek bir geçersiz kılma değil. Bu, dilin güvenli olmayan bir şekilde yanlış kullanılması. Bu çok kolay kırılabilir.
Sulthan

7

@ serenn'in yukarıdaki cevabı hala UINavigationControllers için harika bir cevap. Ancak, hızlı 3 için childViewController işlevleri olarak değiştirildi vars. Dolayısıyla UINavigationControlleruzantı kodu şöyle olmalıdır:

override open var childViewControllerForStatusBarStyle: UIViewController? {
  return topViewController
}

override open var childViewControllerForStatusBarHidden: UIViewController? {
  return topViewController
}

Ve sonra durum denetleyicisi stilini dikte etmesi gereken görünüm denetleyicisinde:

override var preferredStatusBarStyle: UIStatusBarStyle {
   return .lightContent
}

2
Bu yanlış ve iOS 13.4'te kırılıyor. Çünkü Swift'te objektif C sınıflarını genişletmek Objective C kategorileri aracılığıyla uygulanır. Objective C kategorileri üzerinden geçersiz kılma yöntemleri önerilmez ve kırılması muhtemeldir. Bkz. Stackoverflow.com/a/38274660/2438634
Marc Etcheverry

@MarcEtcheverry bu özel örnek yanlış değildi. Mesele şu ki, UINavigationController gibi diğer nesnelerin / protokollerin alt sınıfları dinamik dağıtımda çakışmak için bunları önceden uygulamamışlardır. Gerçek alt sınıflar içinde herhangi bir varsayılan veya uygulama yoktu, bu yüzden bu, gereksiz bir bağımlılık (dönem) oluşturmadan bunu bir uygulamada uygulamanın en temiz yoluydu. Ne yazık ki, 13.4 bu davranışı değiştirmiş görünüyor. Ben yıllardır var olmayan bir kontrol veya uygulama var perde arkasında tahmin .........
TheCodingArt

6

ViewController cihazınız UINavigationController altındaysa.

UINavigationController alt sınıfı ve ekleme

override var preferredStatusBarStyle: UIStatusBarStyle {
    return topViewController?.preferredStatusBarStyle ?? .default
}

ViewController preferredStatusBarStyleçağrılacaktır.



4

İOS 7'de UIStatusBarStyle

İOS 7'deki durum çubuğu şeffaftır, arkasındaki görünüm gösterilir.

Durum çubuğunun stili, içeriğinin görünümüne atıfta bulunur. İOS 7'de durum çubuğu içeriği karanlık ( UIStatusBarStyleDefault) veya açık ( UIStatusBarStyleLightContent). Hem UIStatusBarStyleBlackTranslucentve UIStatusBarStyleBlackOpaqueiOS 7.0 kaldırılıyor. UIStatusBarStyleLightContentBunun yerine kullanın .

Nasıl değiştirilir UIStatusBarStyle

Durum çubuğunun altında bir gezinme çubuğu varsa, durum çubuğu stili gezinme çubuğu stiline uyacak şekilde ayarlanır ( UINavigationBar.barStyle):

Özellikle, gezinme çubuğu stili UIBarStyleDefault ise, durum çubuğu stili UIStatusBarStyleDefault; gezinme çubuğu stili ise UIBarStyleBlack, durum çubuğu stiliUIStatusBarStyleLightContent .

Durum çubuğunun altında gezinme çubuğu yoksa, durum çubuğu stili uygulama çalışırken ayrı bir görünüm denetleyicisi tarafından kontrol edilebilir ve değiştirilebilir.

- [UIViewController preferredStatusBarStyle]iOS 7'de eklenen yeni bir yöntemdir. Tercih edilen durum çubuğu stilini döndürmek için geçersiz kılınabilir:

- (UIStatusBarStyle)preferredStatusBarStyle
  {
      return UIStatusBarStyleLightContent;
  }

Durum çubuğu stilinin kendinden ziyade bir alt görünüm denetleyicisi tarafından denetlenmesi gerekiyorsa, geçersiz kılma -[UIViewController childViewControllerForStatusBarStyle] o çocuk görüntüleme denetleyicisini döndürmek için .

Bu davranışı devre dışı bırakmak ve -[UIApplication statusBarStyle]yöntemi kullanarak durum çubuğu stilini ayarlamak isterseniz , UIViewControllerBasedStatusBarAppearanceanahtarı bir uygulamanın Info.plistdosyasına ekleyin ve ona NO değeri verin.


3

Birisi bir Gezinti Denetleyicisi kullanıyorsa ve tüm gezinme denetleyicilerinin siyah stile sahip olmasını istiyorsa, Swift 3'te UINavigationController'a böyle bir uzantı yazabilirsiniz ve tüm gezinme denetleyicilerine uygulanır ( zaman).

extension UINavigationController {

    override open func viewDidLoad() {
        super.viewDidLoad()

        self.navigationBar.barStyle = UIBarStyle.black
    }

}

1
Peki ya ben gezinme çubuğu gizlenirse?
Slavcho

1
Çünkü navigasyonun gizlenmesini ve durum çubuğunun görünür olmasını istiyorum.
Slavcho

1

Swift'te her türlü UIViewController için:

Senin içinde AppDelegatesette:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    window!.rootViewController = myRootController
    return true
}

myRootControllerherhangi bir tür olabilir UIViewController, örneğin UITabBarControllerveya UINavigationController.

Ardından, bu kök denetleyiciyi şu şekilde geçersiz kılın:

class RootController: UIViewController {
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }
}

Kök denetleyici durum çubuğu görünümünden yalnızca sorumlu olduğu için bu, uygulamanızdaki durum çubuğunun görünümünü değiştirir.

Bu işi yapmak için özelliği varsayılan View controller-based status bar appearanceolarak EVET olarak ayarlamayı unutmayın Info.plist.


@ Swift3'te nasıl oluyor?
uçak

1

Swift 3 iOS 10 Çözümü:

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
 }

1

Cevapların çoğu, childViewControllerForStatusBarStyleyöntemin iyi uygulanmasını içermez UINavigationController. Deneyimlerime göre, navigasyon denetleyicisi üzerinden şeffaf görünüm denetleyicisinin sunulduğu durumları ele almalısınız. Bu durumlarda kontrolü modal kontrolörünüze ( visibleViewController) geçirmelisiniz , ancak kaybolduğunda değil.

override var childViewControllerForStatusBarStyle: UIViewController? {
  var childViewController = visibleViewController
  if let controller = childViewController, controller.isBeingDismissed {
    childViewController = topViewController
  }
  return childViewController?.childViewControllerForStatusBarStyle ?? childViewController
}

1

Benim durumumda, yanlışlıkla Görünüm / Gezinti Denetleyicisini sundum UIModalPresentationStyle.overFullScreen, bu preferredStatusBarStyleda çağrılmamasına neden oluyor . Geri döndükten sonra UIModalPresentationStyle.fullScreenher şey işe yarıyor.


1

İOS 13.4'te olduğu preferredStatusBarStylegibiUINavigationControllerİOS kategorideki çağrılmayacak, alt sınıf kullanmaya gerek kalmadan swizzling tek seçenek gibi görünüyor.

Misal:

Kategori başlığı:

@interface UINavigationController (StatusBarStyle)
+ (void)setUseLightStatusBarStyle;
@end

Uygulama:

#import "UINavigationController+StatusBarStyle.h"
#import <objc/runtime.h>

@implementation UINavigationController (StatusBarStyle)

void (^swizzle)(Class, SEL, SEL) = ^(Class c, SEL orig, SEL new){
    Method origMethod = class_getInstanceMethod(c, orig);
    Method newMethod = class_getInstanceMethod(c, new);
    if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
        class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    else
        method_exchangeImplementations(origMethod, newMethod);
};

+ (void)setUseLightStatusBarStyle {
    swizzle(self.class, @selector(preferredStatusBarStyle), @selector(_light_preferredStatusBarStyle));
}

- (UIStatusBarStyle)_light_preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}    
@end

AppDelegate.h dosyasında kullanım:

#import "UINavigationController+StatusBarStyle.h"

[UINavigationController setUseLightStatusBarStyle];

0

İşte bunu çözme yöntemim.

AGViewControllerAppearance adlı bir protokol tanımlayın .

AGViewControllerAppearance.h

#import <Foundation/Foundation.h>

@protocol AGViewControllerAppearance <NSObject>

@optional

- (BOOL)showsStatusBar;
- (BOOL)animatesStatusBarVisibility;
- (UIStatusBarStyle)preferredStatusBarStyle;
- (UIStatusBarAnimation)prefferedStatusBarAnimation;

@end

UIViewController'da Upgrade adlı bir kategori tanımlayın .

UIViewController + Upgrade.h

#import <UIKit/UIKit.h>

@interface UIViewController (Upgrade)

//
//  Replacements
//

- (void)upgradedViewWillAppear:(BOOL)animated;

@end

UIViewController + Upgrade.m

#import "UIViewController+Upgrade.h"

#import <objc/runtime.h>

#import "AGViewControllerAppearance.h" // This is the appearance protocol

@implementation UIViewController (Upgrade)

+ (void)load
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wselector"
    Method viewWillAppear = class_getInstanceMethod(self, @selector(viewWillAppear:));
#pragma clang diagnostic pop
    Method upgradedViewWillAppear = class_getInstanceMethod(self, @selector(upgradedViewWillAppear:));
    method_exchangeImplementations(viewWillAppear, upgradedViewWillAppear);
}

#pragma mark - Implementation

- (void)upgradedViewWillAppear:(BOOL)animated
{
    //
    //  Call the original message (it may be a little confusing that we're
    //  calling the 'same' method, but we're actually calling the original one :) )
    //

    [self upgradedViewWillAppear:animated];

    //
    //  Implementation
    //

    if ([self conformsToProtocol:@protocol(AGViewControllerAppearance)])
    {
        UIViewController <AGViewControllerAppearance> *viewControllerConformingToAppearance =
        (UIViewController <AGViewControllerAppearance> *)self;

        //
        //  Status bar
        //

        if ([viewControllerConformingToAppearance respondsToSelector:@selector(preferredStatusBarStyle)])
        {
            BOOL shouldAnimate = YES;

            if ([viewControllerConformingToAppearance respondsToSelector:@selector(animatesStatusBarVisibility)])
            {
                shouldAnimate = [viewControllerConformingToAppearance animatesStatusBarVisibility];
            }

            [[UIApplication sharedApplication] setStatusBarStyle:[viewControllerConformingToAppearance preferredStatusBarStyle]
                                                        animated:shouldAnimate];
        }

        if ([viewControllerConformingToAppearance respondsToSelector:@selector(showsStatusBar)])
        {
            UIStatusBarAnimation animation = UIStatusBarAnimationSlide;

            if ([viewControllerConformingToAppearance respondsToSelector:@selector(prefferedStatusBarAnimation)])
            {
                animation = [viewControllerConformingToAppearance prefferedStatusBarAnimation];
            }

            [[UIApplication sharedApplication] setStatusBarHidden:(! [viewControllerConformingToAppearance showsStatusBar])
                                                    withAnimation:animation];
        }
    }
}

@end

Şimdi, görünüm denetleyicinizin AGViewControllerAppearance uygulamasını uyguladığını söylemenin zamanı geldi protokolünü .

Misal:

@interface XYSampleViewController () <AGViewControllerAppearance>

... the rest of the interface

@end

Tabii ki, yöntemlerin (kalanını uygulayabilirsiniz showsStatusBar , animatesStatusBarVisibility , prefferedStatusBarAnimation protokolü ve itibaren) UIViewController + Yükseltme onlar tarafından sağlanan değerlere dayalı uygun özelleştirme yapacağız.


0

Birisi UISearchController ile bu sorunla karşılaşırsa. Sadece yeni bir UISearchController alt sınıfı oluşturun ve ardından bu sınıfa aşağıdaki kodu ekleyin:

override func preferredStatusBarStyle() -> UIStatusBarStyle {
    return .LightContent
}

0

Unutmayın ki self.navigationController.navigationBar.barStyle = UIBarStyleBlack;Çözümü

plist'inize gidip "Denetleyici tabanlı durum çubuğu görünümünü görüntüle" seçeneğini EVET olarak ayarladığınızdan emin olun. HAYIR ise işe yaramaz.


Proje plistinde UIViewControllerBasedStatusBarAppearance öğesini YES olarak ayarlamak benim için tüm farkı yarattı. Bunu unutmuştum.
filo

0

Xcode 11.4'ten bu yana, preferredStatusBarStyle 11.4'ten beri, bir UINavigationController uzantısında özelliğin kılınması, çağrılmayacağından artık çalışmıyor.

Ayar barStyleait navigationBariçin .blackgerçekten işlerin ancak hafif ve karanlık modu için değişik görünüm NavigationBar için subviews eklerseniz bu istenmeyen yan etkileri ekleyecektir. Çünkü barStylesiyah olarak ayarlandığında, userInterfaceStylenavigationBar içine gömülmüş bir görünümün uygulaması, uygulamadan userInterfaceStyle.darkbağımsız olarak her zaman olacaktır userInterfaceStyle.

Ortaya koyduğum uygun çözüm, bir alt sınıf ekleyip oraya UINavigationControllergeçersiz preferredStatusBarStylekılmaktır. Daha sonra tüm görünümleriniz için bu özel UINavigationController'ı kullanırsanız, kayıt tarafında olacaksınız.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.