UIStatusBarStyle PreferredStatusBarStyle tidak berfungsi di iOS 7


110

Dalam aplikasi iPhone dibangun dengan Xcode 5 untuk iOS 7 I set UIViewControllerBasedStatusBarAppearance=YESdi info.plist, dan di saya ViewControllersaya memiliki kode ini:

-(UIStatusBarStyle) preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

Namun bilah status masih hitam dengan latar belakang hitam.

Aku tahu yang mungkin untuk mengubah ini aplikasi-lebar dengan menetapkan UIViewControllerBasedStatusBarAppearance=NOdalam info.plist, tapi saya benar-benar perlu untuk mengubah ini pada viewControllerdengan viewControllerdasar saat runtime.


Hai, saya memiliki masalah yang sama seperti yang Anda sebutkan dalam pertanyaan. Apakah Anda mendapatkan solusinya? Tolong berikan saya itu.
Noundla Sandeep

Jawaban:


281

Saya menemukan bahwa jika ViewController Anda berada di dalam navigationController maka navigationController akan navigationBar.barStylemenentukan statusBarStyle.

Menyetel bilah navigasi Anda barStyleke UIBarStyleBlackTranslucentakan memberikan teks bilah status putih (mis. UIStatusBarStyleLightContent), Dan UIBarStyleDefaultakan memberi teks bilah status hitam (mis. UIStatusBarStyleDefault).

Perhatikan bahwa ini berlaku bahkan jika Anda benar-benar mengubah warna navigationBar melalui nya barTintColor.


ini masuk akal bagi saya ... bagus
Nick

14
Saya percaya itu karena UINavigationController's preferredStatusBarStyletidak menelepon melalui ke ViewController itu host, dan bukan hanya mengembalikan berdasarkan nya navigationBarStyle.
mxcl

Dalam hal ini tampilan tidak berada di dalam pengontrol navigasi.
Andrew Smith

Sangat berlawanan dengan intuisi untuk berpikir bahwa gaya batang lebih disukai daripada metode yang diimplementasikan dalam pengontrol tampilan, dan hanya saat menyajikan tampilan modal!
Matej

3
UIBarStyleBlackTranslucent tidak digunakan lagi, gunakan UIBarStyleBlacksaja
Nhon Nguyen

87

Oke, inilah triknya. Anda harus menambahkan kunci "Lihat bilah status berbasis pengontrol" dan setel nilainya ke Tidak.

Ini berlawanan dengan arti kunci ini, tetapi meskipun Anda menyetel nilainya ke No, Anda masih dapat mengubah tampilan bilah status, dan apakah itu muncul atau tidak di pengontrol tampilan mana pun. Jadi ini bertindak seperti "Ya" tetapi setel ke "Tidak"!

Sekarang saya bisa mendapatkan bilah status putih atau gelap.


6
Bagi saya ini salah. Kunci harus disetel ke "Ya", seperti yang Anda harapkan. Saya menggunakan Xcode 5.1 iOS 7.1, jadi mungkin sudah berubah.
joel.d

Saya menggunakan Xcode 5.1 dan iOS 7.1 juga dan TIDAK berhasil untuk saya ... ANEH.
Arjun Mehta

Di mana saya harus menambahkan kunci ini?
Hadu

Dalam file [AppName] -Info.plist Anda
Saren Inden

1
Ini berfungsi dengan baik ketika tombol "Lihat bilah status berbasis pengontrol" disetel ke "YA" dengan Xcode6.0, iOS 8.0
bpolat

77

Untuk preferredStatusBarStyle()bekerja di dalam UINavigationControllerdan UITabBarControllersaya menambahkan kode berikut, yang akan mendapatkan gaya bilah status yang disukai dari pengontrol tampilan yang saat ini terlihat.

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

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

Untuk Swift 3 itu bukan metode tetapi properti:

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

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

Properti Swift 4.2 telah diganti namanya:

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

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

Pemakaian

class ViewController: UIViewController {

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

}

6
Sejauh ini, ini adalah jawaban terbaik (Untuk aplikasi yang menggunakan UINavigationController atau UITabBarController
Kesava

1
apa gunanya ini?
AnBisw

@Annjawn metode ini digunakan oleh UIKit. Anda tidak perlu melakukan apa pun selain menambahkannya ke proyek Anda.
Daniel Wood

@DanielWood ya saya mengetahuinya dan benar-benar lupa bahwa saya menggunakan hal yang sama persis di salah satu proyek saya sebelumnya, meskipun sedikit berbeda.
AnBisw

Ini memang jawaban terbaik
Musa almatri

33

Saya mungkin datang sedikit terlambat, tetapi jika ada orang lain yang mencari solusi luas aplikasi yang berfungsi dan diverifikasi.

@mxcl benar dalam menjelaskan mengapa ini terjadi. Untuk memperbaikinya, kita cukup membuat ekstensi (atau kategori dalam obj-c) yang menimpa metode preferSatusBarStyle () dari UINavigationController. Berikut adalah contoh di Swift:

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

Kode ini hanya mengekstrak pengontrol tampilan pertama (pengontrol tampilan root) dan membukanya (di obj-c cukup periksa bahwa itu bukan nol). Jika pembongkaran berhasil (bukan nihil) maka kita ambil rootViewControllers preferStatusBarStyle. Jika tidak, kami hanya mengembalikan default.

Semoga ini bisa membantu siapa saja yang mungkin membutuhkannya.


2
Di Swift 2.0 Anda harus menghapus "as? UIViewController" dari pernyataan kondisi.
Thomás Calmon

Brilian, saya membuat satu modifikasi selain menghapus pernyataan "sebagai", saya mengubahnya dari "pertama" menjadi "terakhir" dengan cara ini, pengontrol tampilan apa pun yang dilihat oleh pengguna di bagian atas tumpukan akan memiliki kemampuan untuk mengontrol warna bilah status. Kerja yang luar biasa, terima kasih telah berbagi!
Unome

1
Jika pengontrol navigasi Anda tidak memiliki pengontrol tampilan, ini akan menyebabkan loop tak terbatas. return self.preferredStatusBarStyle()akan memanggil kembali ke metode yang sama persis.
bearMountain

1
Dalam kasus saya, alih-alih menggunakan rootViewController, saya menggunakan topViewController karena selama tumpukan gaya dapat berubah.
Ric Santos

2
@Unome visibleViewControllerakan menjadi lebih baik
Cœur

21

Untuk memberikan lebih banyak detail tentang jawaban yang diterima, letakkan baris berikut dalam didFinishLaunchingWithOptions:metode delegasi aplikasi Anda :

[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;

Kemudian, di Info.plist Anda, tambahkan View controller-based status bar appearancedan setel ke NO.

Saya percaya begitulah seharusnya dilakukan, BUKAN dari pengontrol navigasi, jika Anda menginginkan warna bilah status yang sama untuk seluruh aplikasi. Anda mungkin memiliki layar yang belum tentu disematkan di UINavigationController, atau UINavigationControllersubkelas yang berbeda di tempat lain, dan hal-hal lain.

EDIT : Anda juga dapat melakukannya tanpa mengetik kode apa pun: https://stackoverflow.com/a/18732865/855680


1
Perhatikan bahwa cara ini tidak digunakan lagi pada iOS 9.0
Mohamed Salah

10

Di viewDidLoad, tulis saja ini

[self setNeedsStatusBarAppearanceUpdate];

lakukan saja dan itu akan berhasil

bisakah kamu mencoba ini

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

Satu hal lagi yang saya lihat dalam pertanyaan Anda bahwa Anda telah menulis metode seperti ini

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

tapi seharusnya seperti ini

-(UIStatusBarStyle)preferredStatusBarStyle{ 
    return UIStatusBarStyleLightContent; 
} 

Hal ini menyebabkan metode PreferensiStatusBarStyle dipanggil, tetapi bilah status tetap hitam.
Andrew Smith

silakan lihat jawaban saya yang diperbarui .. beri tahu saya dengan cepat apakah itu berfungsi atau tidak
Pengguna 1531343

Pertanyaan awal saya secara eksplisit mengatakan bahwa saya perlu melakukan kontrol tampilan dengan tampilan dari bilah status.
Andrew Smith

bisakah kamu memeriksa kode kamu dengan mengacu pada pertanyaan terbaru saya?
Pengguna 1531343

1
[self setNeedsStatusBarAppearanceUpdate];metode yang sangat bagus, terima kasih!
Supertecnoboff

6

Inilah cara saya menyelesaikannya. Biasanya navigationController atau tabBarController yang menentukan kemunculan status bar (tersembunyi, warna, dll).

Jadi saya akhirnya membuat subclass pengontrol navigasi dan mengesampingkan preferStatusBarStyle. jika ViewContorller saat ini mengimplementasikan StatusBarStyleHandler saya meminta nilai untuk digunakan sebagai gaya, jika tidak, saya hanya mengembalikan nilai default.

Cara Anda memicu pembaruan tampilan bilah status adalah dengan memanggil setNeedsStatusBarAppearanceUpdateyang terpicu preferredStatusBarStylelagi dan memperbarui UI sesuai dengan apa yang dikembalikan metode

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
    }
}

Kemudian penggunaan

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
    }
}

Posting ini akan jauh lebih baik jika Anda dapat menjelaskan mengapa dan bagaimana ini memperbaiki masalah.

Alih-alih subclass UINavigationController Anda juga bisa membuat ekstensi untuk UINavigationController dan mencapai hasil yang sama tanpa harus subclass.
wilforeal

4

1) Satu pengaturan untuk seluruh proyek:

Jika tersedia, hapus UIViewControllerBasedStatusBarAppearancepasangan nilai kunci dari info.plist Anda, atau setel NOtanpa menghapusnya. Jika tidak tersedia di info.plist Anda, jangan lakukan apa pun. Default NOuntuk properti ini.

Tambahkan kode di bawah ini ke AppDelegate.m Anda:

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

2) Pengaturan berbeda untuk Pengontrol Tampilan yang berbeda:

Tambahkan UIViewControllerBasedStatusBarAppearancepasangan nilai kunci ke info.plist Anda dan setel ke YES.

Jika Pengontrol Tampilan Anda tidak disematkan ke Pengontrol Navigasi. Katakanlah MyViewController. cukup tambahkan kode di bawah ini ke file MyViewController.m Anda. Jika Pengontrol Tampilan Anda disematkan ke Pengontrol Navigasi, buat Kelas Cocoa Touch baru dan jadikan itu subkelas dari UINavigationController. Katakanlah MyNC. Pilih Tampilan Pengontrol Navigasi di Storyboard Anda, di panel kanan; Utilitas -> Inspektur Identitas -> Kelas Khusus -> Kelas, ketik "MyNC". Setelah menautkan Tampilan Papan Cerita dengan Kelas Cocoa Touch "MyNC" Anda, tambahkan kode di bawah ini ke MyNC.m Anda:

- (BOOL)prefersStatusBarHidden {
    return NO;
}

-(UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}

Tampaknya di iOS9 UIViewControllerBasedStatusBarAppearance secara default berisi nilai YES, karena saya perlu menambahkannya secara manual di .plist dan diatur ke NO agar berfungsi dengan benar.
Mohd Asim

4

Bahkan dengan semua jawaban di sini saya masih belum menemukan solusi yang tepat untuk saya, tetapi dimulai dengan jawaban dari Daniel. Apa yang saya dapatkan adalah:

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

di pengontrol navigasi (mirip untuk tab, hanya selectedViewController). Dan kemudian itu akan menghormati:

override var preferredStatusBarStyle: UIStatusBarStyle {
     return .lightContent
}

Di setiap pengontrol tampilan kecuali Anda menyetelnya sebaliknya. Saya tidak perlu menelepon ke setNeedsStatusBarAppearanceUpdate()mana pun, itu hanya diperbarui ketika Anda tiba di setiap pengontrol tampilan.


2
Saya berakhir dengan solusi yang hampir sama setelah berjuang dengan ini selama berjam-jam.
Scott Jungwirth

Pada titik tertentu ini tampaknya telah diperbaiki, hanya menggunakan preferstatusBarStyle di setiap VC berfungsi dengan baik untuk saya sekarang.
Andrew Plummer

4

Solusi iOS 13

Jawaban dengan suara terbanyak menggunakan kode "warisan" 👎

Menyetel barStyleproperti sekarang (iOS 13+) dianggap sebagai "penyesuaian lama". Menurut Apple ,

Di iOS 13 dan lebih baru, sesuaikan bilah navigasi Anda menggunakan properti standardAppearance, compactAppearance, dan scrollEdgeAppearance. Anda dapat terus menggunakan pengakses lama ini untuk menyesuaikan tampilan bilah navigasi Anda secara langsung, tetapi Anda harus memperbarui sendiri tampilan untuk konfigurasi bilah yang berbeda.

Mengenai usaha Anda - Anda berada di jalur yang benar!

UINavigationControlleradalah subclass dari UIViewController(siapa tahu 🙃)!

Oleh karena itu, saat menampilkan pengontrol tampilan yang disematkan di pengontrol navigasi, Anda tidak benar-benar menampilkan pengontrol tampilan yang disematkan; Anda sedang menampilkan pengontrol navigasi! UINavigationController, sebagai subkelas UIViewController, mewarisi preferredStatusBarStyledan childForStatusBarStyle, yang dapat Anda setel sesuai keinginan.

Salah satu metode berikut harus bekerja:

  1. Timpa preferredStatusBarStyledalamUINavigationController

    • preferredStatusBarStyle( doc ) - Gaya bilah status yang disukai untuk pengontrol tampilan
    • Subkelas atau perluasan UINavigationController

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

      ATAU

      extension UINavigationController {
          open override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }
  2. Timpa childForStatusBarStyledalamUINavigationController

    • childForStatusBarStyle( doc ) - Dipanggil saat sistem memerlukan pengontrol tampilan yang akan digunakan untuk menentukan gaya bilah status
    • Menurut dokumentasi Apple,

      "Jika pengontrol tampilan penampung Anda memperoleh gaya bilah status dari salah satu pengontrol tampilan turunannya, [timpa properti ini] dan kembalikan pengontrol tampilan anak tersebut. Jika Anda mengembalikan nol atau tidak mengganti metode ini, gaya bilah status untuk diri sendiri akan digunakan . Jika nilai kembalian dari metode ini berubah, panggil metode setNeedsStatusBarAppearanceUpdate (). "

    • Dengan kata lain, jika Anda tidak menerapkan solusi 3 di sini, sistem akan kembali ke solusi 2 di atas.
    • Subkelas atau perluasan UINavigationController

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

      ATAU

      extension UINavigationController {    
          open override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }
    • Anda dapat mengembalikan pengontrol tampilan apa pun yang Anda inginkan di atas. Saya merekomendasikan salah satu dari yang berikut:

      • topViewController(of UINavigationController) ( doc ) - Pengontrol tampilan di bagian atas tumpukan navigasi
      • visibleViewController(dari UINavigationController) ( doc ) - Pengontrol tampilan yang terkait dengan tampilan yang saat ini terlihat di antarmuka navigasi (petunjuk: ini dapat mencakup "pengontrol tampilan yang disajikan secara sederhana di atas pengontrol navigasi itu sendiri")

Catatan: Jika Anda memutuskan untuk membuat subkelas UINavigationController, ingatlah untuk menerapkan kelas tersebut ke pengontrol nav Anda melalui pemeriksa identitas di IB.

PS Kode saya menggunakan sintaks Swift 5.1 😎


1
Jawaban sangat lengkap terima kasih! Juga, sesuatu yang saya perjuangkan untuk sementara waktu, di iOS 13 .defaultgayanya mempertimbangkan mode gelap dan itu tidak didokumentasikan, jadi jika Anda juga mendukung versi iOS sebelumnya, Anda dapat menambahkan if #available(iOS 13, *) { return .darkContent } else { return .default }jika Anda mencoba mengatur gaya bilah status secara manual sesuai dengan warna di belakang bilah status dan warna itu "cerah".
valcanaia

1
Perhatikan bahwa metode ekstensi melakukan override var tidak berfungsi lagi di Xcode 11.4 / iOS 13.4
Marc Etcheverry

Karena memperluas kelas tujuan C di Swift diimplementasikan melalui kategori Objective C. Mengganti metode melalui kategori Tujuan C tidak direkomendasikan dan kemungkinan besar akan rusak. Lihat stackoverflow.com/a/38274660/2438634
Marc Etcheverry

Meskipun menimpa UINavigationController pasti berfungsi, sepertinya bug di Apple yang tidak melakukan childForStatusBarStyle secara default mengembalikan topViewControllernya. Misalnya UITabBarController melakukan ini untuk tabnya. Bagi saya, tidak ada alasan mengapa UINavigationController, sebagai pengontrol kontainer yang ketat untuk menghosting pengontrol Tampilan "nyata" daripada menampilkan UI-nya sendiri, harus "memakan" gaya bilah status tersebut. Akan membuat radar untuk Apple.
Igor Vasilev

1

Jika seandainya Anda ingin menyembunyikan statusBar selama splashScreen tetapi ingin mengubah gaya menjadi konten ringan (StatusBarInitiallyHidden on Plist harus NO untuk menyembunyikan statusBar pada splash), Anda dapat menambahkan ini ke metode didFinishLaunchingWithOptions appDelegate untuk mengubah ke lightContent.

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

1

contoh cepat

di AppDelegate.swift

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

    return true
}

di set info.plist Lihat tampilan bilah status berbasis pengontrol: NO


1

Jika Anda menggunakan NavigationController, Anda dapat membuat subkelas NavigationControllersehingga berkonsultasi dengan pengontrol tampilan anaknya

// 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

Swift 4.2.0

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

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

Perhatikan bahwa metode ekstensi melakukan override var tidak berfungsi lagi di Xcode 11.4 / iOS 13.4
Marc Etcheverry

@MarcEtcheverry jadi, mengapa Anda tidak menyukai jawabannya? sepertinya aneh.
Vyacheslav

Karena memperluas kelas tujuan C di Swift diimplementasikan melalui kategori Objective C. Mengganti metode melalui kategori Tujuan C tidak direkomendasikan dan kemungkinan besar akan rusak. Lihat stackoverflow.com/a/38274660/2438634
Marc Etcheverry

@MarcEtcheverry 'not recommended'! = 'Never use it!'. untuk jul2018 jawabannya benar. Meskipun jawaban ini tidak up-to-date, ini bukan alasan untuk menurunkannya. Saya tidak bisa melihat masa depan
Vyacheslav

0

Anda dapat mengatur gaya bilah status. Ini akan menyerupai bilah status seperti iOS 6 dan di bawahnya.
Tempel metode ini di pengontrol tampilan Anda

-(UIStatusBarStyle)preferredStatusBarStyle{
    return UIStatusBarStyleBlackOpaque;
}

dan memanggil metode ini dari tampilan tidak memuat seperti ini

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

Apakah yang Anda maksud [self setStatusBarNeedsUpdate]di blok kedua? (Atau setidaknya sesuatu yang lain).
mxcl

0

Saya hanya ingin menambahkan catatan untuk kasus tertentu yang saya hadapi. Saya memiliki UIWindow lain di aplikasi saya untuk menampilkan wajah obrolan yang akan mengambang di seluruh aplikasi saya sepanjang waktu. Melakukan ini menyebabkan tidak ada solusi di atas yang berfungsi, dan saya tidak begitu yakin mengapa! Semua yang saya perhatikan adalah bahwa ViewController saya di UIWindow baru adalah alasannya! Dan jika saya ingin mengubah gaya bilah status, saya harus melakukannya di pengontrol tampilan UIWindow baru itu.

Catatan ini mungkin membantu orang lain yang memiliki struktur serupa! Jadi pada dasarnya Anda dapat menerapkan solusi yang disebutkan di atas di ViewController dari UIWindow baru.

Sekali lagi ini kasus khusus.

Terima kasih


-1

Untuk swift 3, di UIViewController Anda:

override var preferredStatusBarStyle : UIStatusBarStyle { return UIStatusBarStyle.lightContent }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.