preferStatusBarStyle tidak dipanggil

257

Saya mengikuti utas ini untuk mengganti -preferredStatusBarStyle, tetapi tidak dipanggil. Apakah ada opsi yang dapat saya ubah untuk mengaktifkannya? (Saya menggunakan XIB dalam proyek saya.)

trgoofi
sumber
Itu tidak dipanggil dalam konteks apa: simulator? pada perangkat?
bneely
@ pada dasarnya keduanya.
trgoofi
Anda menggunakan simulator iOS 7, perangkat iOS 7, dan SDK dasar Anda adalah 7.0?
bneely
@bahkan iOS SDK 7.0 ditampilkan di bawah nama proyek saya, apakah itu berarti SDK dasar saya 7.0?
trgoofi
Dalam pengaturan build, "Base SDK" adalah tempat nilainya diatur. Sepertinya proyek Anda disetel ke 7.0.
bneely

Jawaban:

117

Kemungkinan penyebab root

Saya memiliki masalah yang sama, dan menemukan itu terjadi karena saya tidak mengatur pengontrol tampilan root di jendela aplikasi saya.

Di UIViewControllermana saya telah menerapkan preferredStatusBarStyleitu digunakan dalam UITabBarController, yang mengontrol tampilan tampilan di layar.

Ketika saya mengatur pengontrol tampilan root untuk menunjukkan hal ini UITabBarController, perubahan bilah status mulai berfungsi dengan benar, seperti yang diharapkan (dan preferredStatusBarStylemetode dipanggil).

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

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

Metode alternatif (Tidak digunakan di iOS 9)

Atau, Anda dapat memanggil salah satu metode berikut ini, yang sesuai, di setiap pengontrol tampilan Anda, tergantung pada warna latar belakangnya, daripada harus menggunakan setNeedsStatusBarAppearanceUpdate:

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

atau

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

Perhatikan bahwa Anda juga perlu mengatur UIViewControllerBasedStatusBarAppearanceke NOdalam file plist jika Anda menggunakan metode ini.

AbdullahC
sumber
2
Saya memiliki masalah yang sama seperti Anda, tidak mengatur pengontrol tampilan root. Bagaimana kamu menemukan itu?
trgoofi
1
Saya curiga ada sesuatu dalam kerangka kerja yang tidak menerima pemberitahuan setNeedsStatusBarAppearanceUpdate- kecurigaan saya dikonfirmasi ketika saya melakukan perubahan ini.
AbdullahC
2
Masalah terkait yang saya temukan di aplikasi adalah pengontrol tampilan dengan pengontrol tampilan anak layar penuh yang tidak menimpa childViewControllerForStatusBarStyle dan childViewControllerForStatusBarHidden untuk mengembalikan pengontrol tampilan anak itu. Jika Anda memiliki hierarki pengontrol tampilan Anda sendiri, Anda perlu menyediakan metode ini untuk menginformasikan sistem yang pengontrol tampilan harus digunakan untuk menentukan gaya bilah status.
Jon Steinmetz
pengaturan rootviewcontroller tidak mengubah apa pun. Anda harus bekerja dengan komentar Jon. Dan berhati-hatilah saat memanggil setneedsstatusbarappearanceUpdate. Anda harus memanggilnya dari induk untuk bekerja.
doozMen
1
@ Kuda nil, kamu jenius !! Bagaimana Anda mengetahui bahwa itu karena tidak menyetel rootviewcontroller?
ViruMax
1019

Bagi siapa pun yang menggunakan UINavigationController:

The UINavigationControllertidak meneruskan preferredStatusBarStylepanggilan ke pengontrol tampilan anaknya. Alih-alih mengelola negaranya sendiri - sebagaimana mestinya, ia menggambar di bagian atas layar tempat bilah status berada dan karenanya harus bertanggung jawab untuk itu. Karenanya menerapkan preferredStatusBarStyleVC Anda dalam kontroler nav tidak akan melakukan apa pun - mereka tidak akan pernah dipanggil.

Kuncinya adalah apa UINavigationControllergunanya memutuskan apa yang akan kembali UIStatusBarStyleDefaultatau UIStatusBarStyleLightContent. Ini mendasarkan ini pada UINavigationBar.barStyle. Default ( UIBarStyleDefault) menghasilkan UIStatusBarStyleDefaultbilah status latar depan gelap . Dan UIBarStyleBlackakan memberikan UIStatusBarStyleLightContentstatus bar.

TL; DR:

Jika Anda ingin UIStatusBarStyleLightContentpada UINavigationControllerpenggunaan:

self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
Tyson
sumber
59
Bagus! Perhatikan bahwa preferredStatusBarStylesebenarnya akan dipanggil pada pengontrol tampilan anak jika Anda menyembunyikan bilah navigasi (disetel navigationBarHiddenke YES), tepat sesuai kebutuhan.
Patrick Pijnappel
25
Terima kasih atas jawaban ini. Jika Anda ingin mengatur barStyle untuk semua bilah navigasi Anda, hubungi[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack]
Thomas Desert
15
Jawaban sempurna. Tidak ada jawaban lain pada SO yang mempertimbangkan UINavigationController. 2 jam membenturkan kepalaku ke keyboard.
Ryan Alford
10
Kudos to @Patrick untuk menunjukkan bahwa navigationBarHiddenset ke YESakan benar-benar telah preferredStatusBarStylememanggil, dan peringatan bagi mereka yang mungkin tersandung pada ini: itu bekerja dengan navigationBarHidden, tetapi tidak dengan navigationBar.hidden!
jcaron
4
harus jelas, tetapi Anda juga perlu "Lihat tampilan bilah status berbasis pengontrol" yang disetel ke YES di Info.plist agar ini berfungsi.
Code Baller
99

Jadi saya benar-benar menambahkan kategori ke UINavigationController tetapi menggunakan metode:

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

dan meminta mereka mengembalikan UIViewController yang terlihat saat ini. Itu memungkinkan pengontrol tampilan yang terlihat saat ini mengatur gaya / visibilitas yang diinginkan.

Berikut cuplikan kode lengkap untuknya:

Dalam Swift:

extension UINavigationController {

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

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

Dalam Objective-C:

@interface UINavigationController (StatusBarStyle)

@end

@implementation UINavigationController (StatusBarStyle)

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

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

@end

Dan untuk ukuran yang baik, inilah cara penerapannya di UIViewController:

Dalam Swift

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

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

Dalam Objective-C

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

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

Terakhir, pastikan daftar aplikasi Anda TIDAK memiliki "Tampilan bilah status berbasis pengontrol" yang disetel ke NO. Hapus baris itu atau setel ke YA (yang saya percaya adalah default sekarang untuk iOS 7?)

serenn
sumber
Sepertinya return self.topViewController;bekerja untuk saya, tetapi return self.visibleViewController;- tidak
k06a
visibleViewController dapat mengembalikan pengontrol modal yang disajikan saat ini ketika Anda mengabaikannya. Yang menyebalkan. Gunakan topViewController.
Ben Sinclair
1
@ d.lebedev ok, tapi saya rasa semua masalah itu tidak berlaku di sini. Anda tidak perlu memanggil supermetode ini dan Anda benar-benar ingin mengubah perilaku semua pengontrol jenis ini
ed '
1
ini tidak berfungsi untuk saya di iOS 9.3. Saya kira, inilah masalahnya: Masalah ini sangat penting karena banyak kelas Kakao diimplementasikan menggunakan kategori. Metode yang ditentukan kerangka kerja yang Anda coba timpa mungkin itu sendiri telah diimplementasikan dalam kategori, dan implementasi mana yang diutamakan tidak didefinisikan.
vikingosegundo
2
Ini salah dan rusak di iOS 13.4. Karena memperluas kelas objektif C di Swift diimplementasikan melalui kategori Objective C. Metode utama melalui kategori Objective C tidak direkomendasikan dan cenderung rusak. Lihat stackoverflow.com/a/38274660/2438634
Marc Etcheverry
79

Bagi siapa pun yang masih berjuang dengan ini, ekstensi sederhana ini dengan cepat harus memperbaiki masalah untuk Anda.

extension UINavigationController {
    override open var childForStatusBarStyle: UIViewController? {
        return self.topViewController
    }
}
Alex Brown
sumber
10
Anda layak mendapatkan medali.
nikans
2
Terima kasih banyak. Sebagai gantinya saya mengembalikan visibleViewController tanpa hasil.
Fábio Salata
1
Ini emas. Saya memiliki pengontrol navigasi yang tertanam di bilah tab dan saya hanya melemparkan ini ke dalam file dan sekarang saya dapat mengubah tampilan bilah status di mana pun saya inginkan.
Vahid Amiri
2
Ini salah dan rusak di iOS 13.4. Karena memperluas kelas objektif C di Swift diimplementasikan melalui kategori Objective C. Metode utama melalui kategori Objective C tidak direkomendasikan dan cenderung rusak. Lihat stackoverflow.com/a/38274660/2438634
Marc Etcheverry
1
@MarcEtcheverry contoh khusus ini tidak salah. Faktanya adalah bahwa subclass dari objek / protokol lain seperti UINavigationController tidak memiliki implementasi sebelumnya untuk konflik dalam pengiriman dinamis. Tidak ada default atau implementasi di dalam subclass yang sebenarnya, itulah sebabnya ini adalah cara paling bersih untuk mengimplementasikan ini di seluruh aplikasi tanpa membuat ketergantungan (periode) yang tidak perlu. Sayangnya, 13,4 tampaknya telah mengubah perilaku ini. Saya menduga di balik layar mereka memiliki pemeriksaan atau implementasi sekarang yang sudah tidak ada selama bertahun-tahun .........
TheCodingArt
20

Aplikasi saya menggunakan semua tiga: UINavigationController, UISplitViewController, UITabBarController, sehingga ini semua tampaknya mengambil kendali atas status bar dan akan menyebabkan preferedStatusBarStyletidak dipanggil untuk anak-anak mereka. Untuk mengesampingkan perilaku ini, Anda dapat membuat ekstensi seperti sisa jawaban yang telah disebutkan. Ini adalah ekstensi untuk ketiganya, di Swift 4. Wish Apple lebih jelas tentang hal-hal semacam ini.

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

Sunting: Perbarui untuk perubahan API Swift 4.2

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
    }
}
Luis
sumber
1
Ini adalah satu-satunya solusi yang berfungsi. Semua jawaban pada SO mengarah ke solusi standar yang tidak akan berfungsi untuk aplikasi apa pun dengan NavigationControllers. Terima kasih!!!
Houman
Menggunakan ekstensi untuk mengganti hanya salah. Itu tidak aman. Ada beberapa solusi sederhana. Gunakan subkelas sebagai gantinya.
Sulthan
2
Ini salah dan rusak di iOS 13.4. Karena memperluas kelas objektif C di Swift diimplementasikan melalui kategori Objective C. Metode utama melalui kategori Objective C tidak direkomendasikan dan cenderung rusak. Lihat stackoverflow.com/a/38274660/2438634
Marc Etcheverry
1
@MarcEtcheverry contoh khusus ini tidak salah. Faktanya adalah bahwa subclass dari objek / protokol lain seperti UINavigationController tidak memiliki implementasi sebelumnya untuk konflik dalam pengiriman dinamis. Tidak ada default atau implementasi di dalam subclass yang sebenarnya, itulah sebabnya ini adalah cara paling bersih untuk mengimplementasikan ini di seluruh aplikasi tanpa membuat ketergantungan (periode) yang tidak perlu. Sayangnya, 13,4 tampaknya telah mengubah perilaku ini. Saya menduga di balik layar mereka memiliki pemeriksaan atau implementasi sekarang yang sudah tidak ada selama bertahun-tahun .........
TheCodingArt
15

Jawaban Tyson benar untuk mengubah warna bilah status menjadi putih UINavigationController.

Jika ada yang ingin mencapai hasil yang sama dengan menulis kode di AppDelegatekemudian gunakan kode di bawah ini dan tulis di dalam AppDelegate's didFinishLaunchingWithOptionsmetode.

Dan jangan lupa untuk mengatur UIViewControllerBasedStatusBarAppearanceke YESdalam file .plist, kalau tidak perubahan tidak akan mencerminkan.

Kode

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

     return YES;
}
Yogesh Suthar
sumber
14

Pada UINavigationController, preferredStatusBarStyletidak dipanggil karena topViewControllerlebih disukai self. Jadi, untuk preferredStatusBarStyledipanggil pada UINavigationController, Anda perlu mengubahnya childViewControllerForStatusBarStyle.

Rekomendasi

Override UINavigationController Anda di kelas Anda:

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

Alternatif yang tidak direkomendasikan

Untuk melakukannya untuk semua UINavigationController, Anda bisa mengganti dalam ekstensi (peringatan: itu mempengaruhi UIDocumentPickerViewController, UIImagePickerController, dll.), Tetapi Anda mungkin tidak boleh melakukannya sesuai dengan dokumentasi Swift :

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

Selain jawaban Serenn, jika Anda menghadirkan view controller dengan modalPresentationStyle(misalnya .overCurrentContext), Anda juga harus menyebutnya pada controller tampilan yang baru disajikan:

presentedViewController.modalPresentationCapturesStatusBarAppearance = true

Jangan lupa juga menimpa preferredStatusBarStylepengontrol tampilan yang disajikan.

frin
sumber
9

Tambahan untuk jawaban Hippo: jika Anda menggunakan UINavigationController, maka mungkin lebih baik untuk menambahkan kategori:

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

Solusi itu mungkin lebih baik daripada beralih ke perilaku yang akan segera ditinggalkan.

Artem Abramov
sumber
Jangan lakukan ini, itu berfungsi untuk saat ini tetapi dapat merusak perilaku di masa depan. Ubah saja gaya navBar - lihat jawaban saya stackoverflow.com/a/19513714/505457
Tyson
2
Anda harus menggunakan subkelas, bukan kategori.
shuiyouren
2Tyson: Mengapa itu akan merusak perilaku masa depan? preferredStatusBarStyle: adalah metode yang disukai Apple untuk mengatur gaya Status Bar.
Artem Abramov
2shuiyouren: Mengapa saya harus menambah kompleksitas dengan mensubklasifikasikan jika saya bisa menggunakan kategori saja dan memasukkannya di setiap tempat yang saya inginkan? Bagaimanapun, itu masalah arsitektur, bukan implementasinya.
Artem Abramov
2
@ ArtemAbramov Karena UINavigationController sudah mengimplementasikan preferredStatusBarStyledan melakukan logika spesifik UINavigationController. Saat ini logika ini didasarkan pada navigationBar.barStyletetapi saya dapat melihat pemeriksaan tambahan sedang ditambahkan (misalnya UISearchDisplayControllerpindah ke menyembunyikan mode navbar). Dengan mengganti logika default, Anda kehilangan semua fungsi ini dan membiarkan diri Anda terbuka untuk momen 'wtf' yang mengganggu di masa depan. Lihat jawaban saya di atas untuk cara yang benar untuk melakukan ini sementara masih mendukung perilaku kontroler nav built-in.
Tyson
9

Cepat 4.2 dan lebih tinggi

Seperti disebutkan dalam jawaban yang dipilih , root menyebabkan untuk memeriksa objek pengontrol tampilan root window Anda.

Kemungkinan kasus struktur aliran Anda

  • Objek kustom UIViewController adalah pengontrol tampilan root jendela Pengontrol tampilan root jendela

    Anda adalah objek UIViewController dan selanjutnya menambah atau menghapus pengontrol navigasi atau tabController berdasarkan aliran aplikasi Anda.

    Aliran jenis ini biasanya digunakan jika aplikasi Anda memiliki aliran pra masuk pada tumpukan navigasi tanpa tab dan mengirim aliran masuk dengan tab dan mungkin setiap tab selanjutnya memegang pengendali navigasi.

  • Objek TabBarController adalah pengontrol tampilan root jendela

    Ini adalah aliran di mana pengontrol tampilan root jendela adalah tabBarController mungkin setiap tab selanjutnya memegang pengontrol navigasi.

  • Objek NavigationController adalah pengontrol tampilan root jendela

    Ini adalah aliran di mana pengontrol tampilan root jendela adalah navigationController.

    Saya tidak yakin apakah ada kemungkinan untuk menambahkan pengontrol tab bar atau pengontrol navigasi baru di pengontrol navigasi yang ada. Tetapi jika ada kasus seperti itu, kita perlu meneruskan kontrol gaya bilah status ke wadah berikutnya. Jadi, saya menambahkan cek yang sama di ekstensi UINavigationController untuk menemukanchildForStatusBarStyle

Gunakan ekstensi berikut, ini menangani semua skenario di atas -

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
    }
}
  • Anda tidak perlu UIViewControllerBasedStatusBarAppearancekunci dalam info.plistkarena benar secara default

Poin yang perlu dipertimbangkan untuk aliran yang lebih kompleks

  • Jika Anda menyajikan aliran baru secara modalnya, aliran ini terlepas dari aliran gaya bilah status yang ada. Jadi, misalkan Anda sedang mempresentasikan NewFlowUIViewControllerdan kemudian menambahkan navigasi baru atau pengontrol tabBar NewFlowUIViewController, kemudian menambahkan ekstensi NewFlowUIViewControllerjuga untuk mengelola gaya bilah status pengontrol tampilan lebih lanjut.

  • Jika Anda mengatur modalPresentationStyle selain fullScreensaat mempresentasikan secara modalnya, Anda harus mengatur modalPresentationCapturesStatusBarAppearanceke true sehingga pengontrol tampilan yang disajikan harus menerima kontrol tampilan bilah status.

abimanyu jindal
sumber
Jawaban yang sangat bagus!
Amin Benarieb
3
Ini salah dan rusak di iOS 13.4. Karena memperluas kelas objektif C di Swift diimplementasikan melalui kategori Objective C. Metode utama melalui kategori Objective C tidak direkomendasikan dan cenderung rusak. Lihat stackoverflow.com/a/38274660/2438634
Marc Etcheverry
@MarcEtcheverry contoh khusus ini tidak salah. Faktanya adalah bahwa subclass dari objek / protokol lain seperti UINavigationController tidak memiliki implementasi sebelumnya untuk konflik dalam pengiriman dinamis. Tidak ada default atau implementasi di dalam subclass yang sebenarnya, itulah sebabnya ini adalah cara paling bersih untuk mengimplementasikan ini di seluruh aplikasi tanpa membuat ketergantungan (periode) yang tidak perlu. Sayangnya, 13,4 tampaknya telah mengubah perilaku ini. Saya menduga di balik layar mereka memiliki pemeriksaan atau implementasi sekarang yang sudah tidak ada selama bertahun-tahun .........
TheCodingArt
8

Solusi iOS 13

UINavigationControlleradalah subkelas dari UIViewController(yang tahu 🙃)!

Karenanya, saat menghadirkan pengontrol tampilan yang tertanam di pengontrol navigasi, Anda tidak benar-benar menghadirkan pengontrol tampilan yang tertanam; Anda sedang menghadirkan pengontrol navigasi! UINavigationController, sebagai subkelas dari UIViewController, mewarisi preferredStatusBarStyledan childForStatusBarStyle, yang dapat Anda atur sesuai keinginan.

Salah satu dari metode berikut harus bekerja:

  1. Menyisih sepenuhnya dari Mode Gelap
    • Di Anda info.plist, tambahkan properti berikut:
      • Kunci - UIUserInterfaceStyle(alias. "Gaya Antarmuka Pengguna")
      • Nilai - Ringan
  2. Timpa preferredStatusBarStyledalamUINavigationController

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

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

      ATAU

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

    • childForStatusBarStyle( doc ) - Dipanggil ketika sistem membutuhkan pengontrol tampilan untuk digunakan untuk menentukan gaya status bar
    • Menurut dokumentasi Apple,

      "Jika pengontrol tampilan wadah Anda memperoleh gaya bilah statusnya dari salah satu pengontrol tampilan anak-nya, [ganti properti ini] dan kembalikan pengontrol tampilan anak itu. Jika Anda mengembalikan nil atau tidak mengesampingkan metode ini, gaya bilah status untuk diri sendiri digunakan Jika nilai balik dari metode ini berubah, panggil metode setNeedsStatusBarAppearanceUpdate (). "

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

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

      ATAU

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

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

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

PS Kode saya menggunakan sintaks Swift 5.1 😎

Andrew Kirna
sumber
Bilah status saya menjadi hitam setelah rotasi layar. Ada yang tahu kenapa? Ini hanya terjadi pada simulator iPad Pro.
Pedro Paulo Amorim
@PedroPauloAmorim, dapatkah Anda memberikan info lebih lanjut? Bagaimana pengontrol tampilan atas disajikan (modal, layar penuh, pertunjukan)? Apakah bersarang di dalam pengontrol navigasi? Apakah teksnya menjadi hitam, atau latar belakangnya juga? Apa yang ingin Anda capai?
Andrew Kirna
Saya mengatur bilah status lampu di seluruh aplikasi saya. Ia mendapat cahaya dalam dua rotasi, di yang ketiga berubah menjadi gelap dan tidak pernah kembali ke cahaya, bahkan memaksa untuk menggambarnya kembali. Ini terjadi pada simulator iPad Pro. Tampilan disajikan dalam layar penuh dan tidak bersarang di dalam pengontrol navigasi. Hanya teks yang menjadi gelap.
Pedro Paulo Amorim
Bagaimana Anda mengatur bilah status lampu di tempat pertama?
Andrew Kirna
3
Penimpaan Anda melalui ekstensi bukan penimpaan nyata. Ini penyalahgunaan bahasa yang tidak aman. Itu bisa pecah dengan sangat mudah.
Sulthan
7

@ serenn jawaban di atas masih bagus untuk kasus UINavigationControllers. Namun, untuk swift 3 fungsi childViewController telah diubah menjadi vars. Jadi UINavigationControllerkode ekstensi harus:

override open var childViewControllerForStatusBarStyle: UIViewController? {
  return topViewController
}

override open var childViewControllerForStatusBarHidden: UIViewController? {
  return topViewController
}

Dan kemudian di view controller yang akan menentukan gaya status bar:

override var preferredStatusBarStyle: UIStatusBarStyle {
   return .lightContent
}
John Stricker
sumber
2
Ini salah dan rusak di iOS 13.4. Karena memperluas kelas objektif C di Swift diimplementasikan melalui kategori Objective C. Metode utama melalui kategori Objective C tidak direkomendasikan dan cenderung rusak. Lihat stackoverflow.com/a/38274660/2438634
Marc Etcheverry
@MarcEtcheverry contoh khusus ini tidak salah. Faktanya adalah bahwa subclass dari objek / protokol lain seperti UINavigationController tidak memiliki implementasi sebelumnya untuk konflik dalam pengiriman dinamis. Tidak ada default atau implementasi di dalam subclass yang sebenarnya, itulah sebabnya ini adalah cara paling bersih untuk mengimplementasikan ini di seluruh aplikasi tanpa membuat ketergantungan (periode) yang tidak perlu. Sayangnya, 13,4 tampaknya telah mengubah perilaku ini. Saya menduga di balik layar mereka memiliki pemeriksaan atau implementasi sekarang yang sudah tidak ada selama bertahun-tahun .........
TheCodingArt
6

Jika viewController Anda berada di bawah UINavigationController.

Subkelas UINavigationController dan tambahkan

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

ViewController's preferredStatusBarStyleakan dipanggil.

PowHu
sumber
4

UIStatusBarStyle di iOS 7

Bilah status di iOS 7 transparan, tampilan di belakangnya terlihat.

Gaya bilah status mengacu pada penampilan kontennya. Di iOS 7, konten bilah status berwarna gelap ( UIStatusBarStyleDefault) atau terang ( UIStatusBarStyleLightContent). Keduanya UIStatusBarStyleBlackTranslucentdan UIStatusBarStyleBlackOpaquesudah usang di iOS 7.0. Gunakan UIStatusBarStyleLightContentsebagai gantinya.

Bagaimana cara mengubahnya UIStatusBarStyle

Jika di bawah bilah status adalah bilah navigasi, gaya bilah status akan disesuaikan agar sesuai dengan gaya bilah navigasi ( UINavigationBar.barStyle):

Khususnya, jika gaya bilah navigasi adalah UIBarStyleDefault, gaya bilah status akan UIStatusBarStyleDefault; jika gaya bilah navigasi adalah UIBarStyleBlack, gaya bilah status akan UIStatusBarStyleLightContent.

Jika tidak ada bilah navigasi di bawah bilah status, gaya bilah status dapat dikontrol dan diubah oleh pengontrol tampilan individual saat aplikasi berjalan.

- [UIViewController preferredStatusBarStyle]adalah metode baru yang ditambahkan di iOS 7. Dapat diganti untuk mengembalikan gaya bilah status yang disukai:

- (UIStatusBarStyle)preferredStatusBarStyle
  {
      return UIStatusBarStyleLightContent;
  }

Jika gaya bilah status harus dikontrol oleh pengontrol tampilan anak alih-alih mandiri, ganti -[UIViewController childViewControllerForStatusBarStyle]untuk mengembalikan pengontrol tampilan anak itu.

Jika Anda memilih untuk keluar dari perilaku ini dan mengatur gaya bilah status dengan menggunakan -[UIApplication statusBarStyle]metode ini, tambahkan UIViewControllerBasedStatusBarAppearancekunci ke Info.plistfile aplikasi dan berikan nilai NO.

oscarr
sumber
3

Jika ada yang menggunakan Pengontrol Navigasi dan ingin semua pengontrol navigasi mereka memiliki gaya hitam, Anda dapat menulis ekstensi ke UINavigationController seperti ini di Swift 3 dan itu akan berlaku untuk semua pengontrol navigasi (alih-alih menugaskannya ke satu pengontrol di sebuah waktu).

extension UINavigationController {

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

        self.navigationBar.barStyle = UIBarStyle.black
    }

}
Benjamin Lowry
sumber
1
Tetapi bagaimana jika saya navigationbar disembunyikan?
Slavcho
1
Karena saya perlu navigasi untuk disembunyikan dan status bar menjadi terlihat.
Slavcho
1

Dalam Swift untuk segala jenis UIViewController:

Di AppDelegateset Anda :

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

myRootControllerdapat berupa apa saja UIViewController, misalnya UITabBarControlleratau UINavigationController.

Kemudian, timpa pengontrol root ini seperti ini:

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

Ini akan mengubah tampilan bilah status di seluruh aplikasi Anda, karena pengontrol root bertanggung jawab penuh atas tampilan bilah status.

Ingatlah untuk mengatur properti View controller-based status bar appearanceke YA di Anda Info.plistuntuk membuat ini berfungsi (yang merupakan default).

Damnum
sumber
@Bagaimana melakukannya di swift3?
Pesawat
1

Solusi Swift 3 iOS 10:

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
 }
Statik
sumber
1

Sebagian besar jawaban tidak termasuk implementasi childViewControllerForStatusBarStylemetode yang baik untuk UINavigationController. Menurut pengalaman saya, Anda harus menangani kasus seperti ketika pengontrol tampilan transparan disajikan di atas pengontrol navigasi. Dalam kasus ini Anda harus memberikan kontrol ke modal controller Anda ( visibleViewController), tetapi tidak ketika itu hilang.

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

Dalam kasus saya, saya tidak sengaja menampilkan View / Navigation Controller sebagai UIModalPresentationStyle.overFullScreen, yang menyebabkan preferredStatusBarStyletidak dipanggil. Setelah beralih kembali ke UIModalPresentationStyle.fullScreen, semuanya berfungsi.

Casey
sumber
1

Sedangkan untuk iOS 13.4 preferredStatusBarStylemetode dalam UINavigationControllerkategori tidak akan dipanggil, swizzling tampaknya menjadi satu-satunya pilihan tanpa perlu menggunakan subkelas.

Contoh:

Header kategori:

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

Penerapan:

#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

Penggunaan di AppDelegate.h:

#import "UINavigationController+StatusBarStyle.h"

[UINavigationController setUseLightStatusBarStyle];
Kevin Flachsmann
sumber
0

Inilah metode saya untuk menyelesaikan ini.

Tetapkan protokol yang disebut AGViewControllerAppearance .

AGViewControllerAppearance.h

#import <Foundation/Foundation.h>

@protocol AGViewControllerAppearance <NSObject>

@optional

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

@end

Tentukan kategori pada UIViewController yang disebut Peningkatan .

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

Sekarang, saatnya untuk mengatakan bahwa Anda melihat pengontrol sedang mengimplementasikan AGViewControllerAppearance protokol .

Contoh:

@interface XYSampleViewController () <AGViewControllerAppearance>

... the rest of the interface

@end

Tentu saja, Anda dapat menerapkan sisa metode ( showsStatusBar , animatesStatusBarVisibility , prefferedStatusBarAnimation ) dari protokol dan UIViewController + upgrade akan melakukan kustomisasi yang tepat berdasarkan nilai-nilai yang disediakan oleh mereka.

arturgrigor
sumber
0

Jika seseorang mengalami masalah ini dengan UISearchController. Cukup buat subkelas baru dari UISearchController, dan kemudian tambahkan kode di bawah ini ke dalam kelas itu:

override func preferredStatusBarStyle() -> UIStatusBarStyle {
    return .LightContent
}
Tai Le
sumber
0

Perhatikan bahwa saat menggunakan self.navigationController.navigationBar.barStyle = UIBarStyleBlack; solusi

pastikan untuk pergi ke plist Anda dan atur "Lihat tampilan bilah status berbasis pengontrol" ke YES. Jika TIDAK, itu tidak akan berhasil.

Richard Garfield
sumber
Menyetel UIViewControllerBasedStatusBarAppearance menjadi YA dalam proyek plist membuat semua perbedaan bagi saya. Saya sudah lupa tentang itu.
filo
0

Sejak Xcode 11.4, menimpa preferredStatusBarStyle properti di ekstensi UINavigationController tidak lagi berfungsi karena tidak akan dipanggil.

Mengatur barStyledari navigationBaruntuk .blackkarya memang tapi ini akan menambah efek samping yang tidak diinginkan jika Anda menambahkan subviews ke navigationbar yang mungkin memiliki penampilan yang berbeda untuk mode terang dan gelap. Karena dengan menyetel barStyleke hitam, userInterfaceStyletampilan yang tertanam di navigationBar akan selalu memiliki userInterfaceStyle.darkterlepas dari userInterfaceStyleaplikasi.

Solusi tepat yang saya temukan adalah dengan menambahkan subkelas UINavigationControllerdan menimpa di preferredStatusBarStylesana. Jika Anda kemudian menggunakan UINavigationController khusus ini untuk semua tampilan Anda, Anda akan berada di sisi penyimpanan.

PatrickDotStar
sumber
-1

NavigationController atau TabBarController adalah yang perlu menyediakan gaya. Inilah cara saya memecahkan: https://stackoverflow.com/a/39072526/242769

aryaxt
sumber
Jika Anda berpikir bahwa ini adalah duplikat dari pertanyaan lain, harap tutup suara sebagai duplikat