เป็นไปได้หรือไม่ที่จะยกเลิกโหมดมืดบน iOS 13?


297

แอพของฉันส่วนใหญ่ประกอบด้วยมุมมองทางเว็บเพื่อให้ฟังก์ชันการทำงานยังไม่พร้อมใช้งานผ่านการใช้งานดั้งเดิม ทีมงานเว็บไม่มีแผนที่จะใช้ธีมสีเข้มสำหรับเว็บไซต์ ดังนั้นแอพของฉันจะดูเล็กน้อยครึ่ง / ครึ่งพร้อมการรองรับ Dark Mode บน iOS 13

เป็นไปได้หรือไม่ที่จะยกเลิกการรองรับ Dark Mode แอพของเราจะแสดงโหมดแสงให้ตรงกับธีมของเว็บไซต์


71
ตั้งUIUserInterfaceStyleเป็นLightใน Info.Plist ของคุณ ดู developer.apple.com/library/archive/documentation/General/…
— Tieme

1
ขอบคุณที่สอบถาม - สำหรับพวกเราทุกคน แอพที่ผ่านมามากมาย สิ่งนี้เป็นสิ่งจำเป็นเพื่อให้แอปทำงานต่อไปจนกว่าการสลับจะพร้อมใช้งาน
— user3741598

นำเข้ารากฐานการนำเข้าส่วนขยาย UIKit UIViewController {แทนที่ open func awakeFromNib () {super.awakeFromNib () ถ้า #available (iOS 13.0, *) {// นำสไตล์แสงแบบอินเทอร์เฟซมาใช้เสมอ overrideUserInterfaceStyle = .light}}}
— Mohammad Razipour

1
เพียงเพิ่มUIUserInterfaceStyle แบบเต็ม มันง่ายมาก
— Fattie

ในขณะที่ส่งแอพไปยัง appstore แอปเปิ้ลยอมรับเนื่องจาก UIUserInterfaceStyle ในโหมด Light
— kiran

คำตอบ:


684

ก่อนอื่นนี่คือรายการของ Appleที่เกี่ยวข้องกับการยกเลิกโหมดมืด เนื้อหาที่ลิงค์นี้เขียนขึ้นสำหรับ Xcode 11 และ iOS 13 :

ส่วนนี้ใช้กับการใช้ Xcode 11


หากคุณต้องการยกเลิกการสมัครทั้งหมด

วิธีการ # 1

ใช้รหัสต่อไปนี้ในไฟล์info.plist ของคุณ :

UIUserInterfaceStyle

Lightและกำหนดค่าของ

XMLสำหรับUIUserInterfaceStyleการมอบหมาย:

<key>UIUserInterfaceStyle</key>
<string>Light</string>

วิธีการ # 2

คุณสามารถตั้งค่าoverrideUserInterfaceStyleกับwindowตัวแปรของแอพ

ขึ้นอยู่กับว่าโครงการของคุณถูกสร้างขึ้นนี้อาจจะอยู่ในไฟล์หรือAppDelegateSceneDelegate

if #available(iOS 13.0, *) {
    window?.overrideUserInterfaceStyle = .light
}


หากคุณต้องการยกเลิกการใช้ UIViewController เป็นรายบุคคล

override func viewDidLoad() {
    super.viewDidLoad()
    // overrideUserInterfaceStyle is available with iOS 13
    if #available(iOS 13.0, *) {
        // Always adopt a light interface style.
        overrideUserInterfaceStyle = .light
    }
}

เอกสารประกอบ Apple สำหรับ overrideUserInterfaceStyle

ลักษณะของโค้ดด้านบนจะเป็นอย่างไรใน Xcode 11:

ป้อนคำอธิบายรูปภาพที่นี่

ส่วนนี้ใช้กับการใช้ Xcode 10.x


หากคุณใช้ Xcode 11 สำหรับการส่งของคุณคุณสามารถเพิกเฉยต่อทุกสิ่งที่อยู่ด้านล่างบรรทัดนี้ได้อย่างปลอดภัย

เนื่องจาก API ที่เกี่ยวข้องไม่มีอยู่ใน iOS 12 คุณจะได้รับข้อผิดพลาดเมื่อพยายามใช้ค่าที่ให้ไว้ด้านบน:

สำหรับการตั้งค่าoverrideUserInterfaceStyleในUIViewController

ป้อนคำอธิบายรูปภาพที่นี่

หากคุณต้องการยกเลิกการใช้ UIViewController เป็นรายบุคคล

สิ่งนี้สามารถจัดการได้ใน Xcode 10 โดยการทดสอบเวอร์ชันคอมไพเลอร์และเวอร์ชั่น iOS:

#if compiler(>=5.1)
if #available(iOS 13.0, *) {
    // Always adopt a light interface style.
    overrideUserInterfaceStyle = .light
}
#endif

หากคุณต้องการยกเลิกการสมัครทั้งหมด

คุณสามารถแก้ไขตัวอย่างข้างต้นเพื่อทำงานกับแอปพลิเคชันทั้งหมดสำหรับ Xcode 10 โดยเพิ่มรหัสต่อไปนี้ลงในAppDelegateไฟล์ของคุณ

#if compiler(>=5.1)
if #available(iOS 13.0, *) {
    // Always adopt a light interface style.
    window?.overrideUserInterfaceStyle = .light
}
#endif

อย่างไรก็ตามการตั้งค่า plist จะล้มเหลวเมื่อใช้ Xcode เวอร์ชั่น 10.x:

ป้อนคำอธิบายรูปภาพที่นี่

ขอมอบเครดิตให้แก่@Aron Nelson , @Raimundas Sakalauskas , @NSLeaderและrmaddyสำหรับการปรับปรุงคำตอบนี้พร้อมข้อเสนอแนะ


2
ไฟ UIUserInterfaceStyle ถูกบล็อกเมื่ออัปเดต / อัปโหลดแอปของคุณทันที ได้รับการตั้งค่าสถานะเป็นรายการ plist ที่ไม่ถูกต้อง (คีย์ plist ไม่ถูกต้อง)
— Aron Nelson

2
สิ่งนี้จะไม่รวบรวมกับ iOS SDK 12 (ปัจจุบันมีเสถียรภาพ SDK ล่าสุด) ดูstackoverflow.com/a/57521901/2249485สำหรับโซลูชันที่จะทำงานกับ iOS 12 SDK ได้เช่นกัน
— Raimundas Sakalauskas

นี่ไม่ยุติธรรมเลยที่คำถามที่มีมุมมองมากกว่า "คำถามดั้งเดิม" นั้นถูกล็อคไว้เพื่อให้คำตอบ :(
— Raimundas Sakalauskas

7
แทนที่จะตั้งค่าoverrideUserInterfaceStyleในviewDidLoadทุกตัวควบคุมมุมมองคุณสามารถตั้งค่าได้ครั้งเดียวในหน้าต่างหลักของแอพ ง่ายกว่านี้มากถ้าคุณต้องการให้แอปทั้งหมดทำงานในทิศทางเดียว
— rmaddy

2
ใช้#if compiler(>=5.1)แทนresponds(to:)และsetValue
— NSLeader

162

ตามเซสชั่นแอปเปิ้ลใน "โหมดเข้มการใช้บน iOS" ( https://developer.apple.com/videos/play/wwdc2019/214/เริ่มต้นที่ 31:13) มันเป็นไปได้ที่จะตั้งค่าoverrideUserInterfaceStyleการUIUserInterfaceStyleLightหรือUIUserInterfaceStyleDarkบนตัวควบคุมมุมมองใด ๆ หรือมุมมอง ซึ่งจะถูกใช้ในการtraitCollectionสำหรับมุมมองย่อยหรือตัวควบคุมมุมมอง

ดังที่ได้กล่าวไว้แล้วโดย SeanR คุณสามารถตั้งค่าUIUserInterfaceStyleเป็นLightหรือDarkในไฟล์ plist ของแอปเพื่อเปลี่ยนแปลงสิ่งนี้สำหรับแอปทั้งหมดของคุณ


17
หากคุณตั้งค่า UIUserInterfaceStyle คีย์แอปของคุณจะถูกปฏิเสธใน App store
— Sonius

2
Apple ถูกปฏิเสธด้วยรหัสข้อผิดพลาด ITMS-90190 forums.developer.apple.com/thread/121028
— PRASAD1240

11
การปฏิเสธมักเกิดขึ้นเนื่องจาก iOS 13 SDK ยังไม่ออกจากเบต้า ฉันคิดว่านี่น่าจะใช้งานได้ทันทีที่ Xcode 11 GM พร้อมใช้งาน
— dorbeetle

2
@dorbeetle ไม่เป็นความจริงฉันอัพโหลดแอปของฉันด้วยคีย์นี้เรียบร้อยแล้วเช่น 1 เดือนที่ผ่านมาด้วย Xcode 10 การปฏิเสธเกิดขึ้นเร็ว ๆ นี้ ดูเหมือนว่ากลยุทธ์ใหม่ของ Apple บางชนิด
— steven

1
มันยังคงเกิดขึ้น Xcode GM2 ส่งคืนข้อผิดพลาดในการเซ็นชื่อแอป Xcode 10.3 ส่งคืน: "คีย์ Info.plist ไม่ถูกต้องคีย์ 'UIUserInterfaceStyle' ในไฟล์ Payload / Galileo.appInfo.plist ไม่ถูกต้อง"
— Evgen Bodunov

64

หากคุณไม่ได้ใช้ Xcode 11 หรือใหม่กว่า (i, e iOS 13 หรือใหม่กว่า SDK) แอปของคุณไม่ได้เลือกที่จะรองรับโหมดมืดโดยอัตโนมัติ ดังนั้นไม่จำเป็นต้องยกเลิกโหมดมืด

หากคุณใช้ Xcode 11 หรือใหม่กว่าระบบจะเปิดใช้งานโหมดมืดสำหรับแอปของคุณโดยอัตโนมัติ มีสองวิธีในการปิดใช้งานโหมดมืดขึ้นอยู่กับความต้องการของคุณ คุณสามารถปิดการใช้งานทั้งหมดหรือปิดการใช้งานมันสำหรับหน้าต่างมุมมองหรือมุมมองที่เฉพาะเจาะจง

ปิดใช้งานโหมดมืดทั้งหมดสำหรับแอปของคุณ

คุณสามารถปิดการใช้งานโหมดมืดได้โดยใส่UIUserInterfaceStyleรหัสด้วยค่าเช่นเดียวกับLightในไฟล์ Info.plist ของแอป การดำเนินการนี้จะไม่สนใจการตั้งค่าของผู้ใช้และจะใช้ลักษณะที่ปรากฏเล็กน้อยกับแอปของคุณ
UIUserInterfaceStyle เป็น Light

ปิดใช้งานโหมดมืดสำหรับ Window, View หรือ View Controller

คุณสามารถบังคับให้อินเทอร์เฟซของคุณปรากฏในลักษณะที่มืดหรือมืดได้เสมอโดยการตั้งค่าoverrideUserInterfaceStyleคุณสมบัติของหน้าต่างมุมมองหรือตัวควบคุมมุมมองที่เหมาะสม

ดูตัวควบคุม:

override func viewDidLoad() {
    super.viewDidLoad()
    /* view controller’s views and child view controllers 
     always adopt a light interface style. */
    overrideUserInterfaceStyle = .light
}

การเข้าชม:

// The view and all of its subviews always adopt light style.
youView.overrideUserInterfaceStyle = .light

หน้าต่าง:

/* Everything in the window adopts the style, 
 including the root view controller and all presentation controllers that 
 display content in that window.*/
window.overrideUserInterfaceStyle = .light

หมายเหตุ: Apple สนับสนุนอย่างยิ่งให้สนับสนุนโหมดมืดในแอปของคุณ ดังนั้นคุณสามารถปิดการใช้งานโหมดมืดชั่วคราวเท่านั้น

อ่านเพิ่มเติมได้ที่นี่: การเลือกสไตล์อินเทอร์เฟซเฉพาะสำหรับแอพ iOS ของคุณ


34

********** วิธีที่ง่ายที่สุดสำหรับ Xcode 11 ขึ้นไป ***********

เพิ่มลงใน info.plist ก่อน </dict></plist>

<key>UIUserInterfaceStyle</key>
<string>Light</string>

วิธีการแก้ปัญหานี้จะล้มเหลวเมื่อไม่ส่งแอพใน Xcode 10.x
— Tawfik Bouabid

27

ฉันคิดว่าฉันพบวิธีแก้ปัญหาแล้ว ผมเริ่มปะติดปะต่อมันเข้าด้วยกันจากUIUserInterfaceStyle - ข้อมูลรายการทรัพย์สินและUIUserInterfaceStyle - UIKitแต่ตอนนี้ได้พบว่าเอกสารจริงในการเลือกรูปแบบหน้าจอที่เฉพาะเจาะจงสำหรับแอป iOS ของคุณ

ในของคุณinfo.plistตั้งค่าUIUserInterfaceStyle( ลักษณะส่วนต่อประสานผู้ใช้ ) เป็น1 ( UIUserInterfaceStyle.light)

แก้ไข: ตามคำตอบ dorbeetle ของการตั้งค่าที่เหมาะสมสำหรับอาจจะUIUserInterfaceStyleLight


การบังคับใช้โหมดมืดโดยการตั้งค่าที่ 2 ไม่ทำงานแม้ว่า:[UIInterfaceStyle] '2' is not a recognized value for UIUserInterfaceStyle. Defaulting to Light.
— funkenstrahlen

3
การใช้คีย์นี้ในการวางแผนจะส่งผลให้การปฏิเสธ App Store
— José

1
AppStore ไม่ปฏิเสธคุณสมบัตินี้ใน plist.info อีกต่อไป ฉันใส่ "Dark" (ตัวพิมพ์ใหญ่) เนื่องจากแอปของเรามืดแล้ว ไม่มีปัญหา. สิ่งนี้ช่วยให้เราใช้ระบบควบคุมได้อย่างถูกต้อง
— nickdnk

@nickdnk ฉันคิดว่าคุณสร้างแอปของคุณด้วย Xcode 11 ซึ่ง Apple แนะนำ
— DawnSong

1
ใช่ฉันทำ. มันไม่ได้เปลี่ยนความจริงที่ว่า Apple ยอมรับพารามิเตอร์นี้ในแผนการซึ่งเป็นสิ่งที่ฉันพยายามทำให้ชัดเจน
— nickdnk

23

คำตอบข้างต้นใช้งานได้หากคุณต้องการยกเลิกแอปทั้งหมด หากคุณกำลังทำงานกับ lib ที่มี UI และคุณไม่มีความหรูหราในการแก้ไข. plist คุณสามารถทำได้ผ่านรหัสเช่นกัน

หากคุณกำลังรวบรวมกับ iOS 13 SDK คุณสามารถใช้รหัสต่อไปนี้:

สวิฟท์:

if #available(iOS 13.0, *) {
    self.overrideUserInterfaceStyle = .light
}

Obj-C:

if (@available(iOS 13.0, *)) {
    self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}

อย่างไรก็ตามหากคุณต้องการให้โค้ดรวบรวมกับiOS 12 SDKเช่นกัน (ซึ่งตอนนี้ยังคงเป็น SDK ที่เสถียรล่าสุด) คุณควรใช้ตัวเลือก รหัสที่มีตัวเลือก:

Swift (XCode จะแสดงคำเตือนสำหรับรหัสนี้ แต่นั่นเป็นวิธีเดียวที่จะทำได้ในขณะนี้เนื่องจากไม่มีคุณสมบัติใน SDK 12 ดังนั้นจะไม่รวบรวม):

if #available(iOS 13.0, *) {
    if self.responds(to: Selector("overrideUserInterfaceStyle")) {
        self.setValue(UIUserInterfaceStyle.light.rawValue, forKey: "overrideUserInterfaceStyle")
    }
}

Obj-C:

if (@available(iOS 13.0, *)) {
    if ([self respondsToSelector:NSSelectorFromString(@"overrideUserInterfaceStyle")]) {
        [self setValue:@(UIUserInterfaceStyleLight) forKey:@"overrideUserInterfaceStyle"];
    }
}

มันจะดีกว่าถ้าคุณระบุสิ่งที่ทรัพย์สินที่overrideUserInterfaceStyleเป็นของ
— DawnSong

12

ปรับปรุงล่าสุด-

หากคุณกำลังใช้ Xcode 10.x แล้วเริ่มต้นUIUserInterfaceStyleเป็นlightสำหรับ iOS 13.x. เมื่อทำงานบนอุปกรณ์ iOS 13 มันจะทำงานในโหมดแสงเท่านั้น

ไม่จำเป็นต้องเพิ่มUIUserInterfaceStyleคีย์ในไฟล์ Info.plist อย่างชัดเจนการเพิ่มคีย์จะทำให้เกิดข้อผิดพลาดเมื่อคุณตรวจสอบแอปของคุณว่า:

คีย์ Info.plist ไม่ถูกต้อง คีย์ 'UIUserInterfaceStyle' ในไฟล์ Payload / AppName.appInfo.plist ไม่ถูกต้อง

เพิ่มUIUserInterfaceStyleคีย์ในไฟล์ Info.plist เมื่อใช้ Xcode 11.x เท่านั้น


1
สิ่งนี้ไม่เกี่ยวกับ Xcode 10 หรือ 11 หากผู้ใช้ปรับใช้แอปฟอร์ม Xcode 10 และไม่ดูแลโหมดมืดแอพเมื่อติดตั้งใน iPhone 11, Pro หรือ Pro Max จะมีปัญหาโหมดมืด คุณต้องอัปเดตเป็น Xcode 11 และแก้ไขปัญหานี้
— Niranjan Molkeri

3
@NiranjanMolkeri สิ่งนี้ไม่เกี่ยวกับ iPhones ที่ใหม่กว่า เป็นเรื่องเกี่ยวกับโหมด Dark ใน iOS 13 ใน iOS เวอร์ชันเบต้า 13 ของ iOS แอพมีปัญหาเกี่ยวกับโหมดมืด แต่ในเวอร์ชั่นล่าสุดนั้นได้รับการแก้ไขแล้ว หากคุณใช้ XCode 10 ค่าเริ่มต้นของ UIUserInterfaceStyle นั้นจะเบาสำหรับ iOS13 หากคุณใช้ Xode11 คุณต้องจัดการมัน
— kumarsiddharth123

คุณจะมีปัญหาหากคุณอัปโหลดแอปไปยัง TestFligth โดยใช้ Xcode 10.3 และตัวย่อรวมถึงคีย์ UIUserInterfaceStyle มันจะบอกว่ามันเป็นไฟล์ plist ที่ไม่ถูกต้อง คุณต้องลบมันออกถ้าสร้างใน Xcode 10 หรืออัปโหลดโดยใช้ Xcode 11
— eharo2

9

หากคุณจะเพิ่มUIUserInterfaceStyleที่สำคัญในการไฟล์ plist อาจจะเป็นแอปเปิ้ลจะปฏิเสธการเปิดตัวสร้างเป็นที่กล่าวถึงที่นี่: https://stackoverflow.com/a/56546554/7524146 อย่างไรก็ตามมันน่ารำคาญอย่างชัดเจนบอกแต่ละ self.overrideUserInterfaceStyle = .lightViewController แต่คุณสามารถใช้รหัสสันติภาพนี้หนึ่งครั้งสำหรับwindowวัตถุรูตของคุณ:

if #available(iOS 13.0, *) {
    if window.responds(to: Selector(("overrideUserInterfaceStyle"))) {
        window.setValue(UIUserInterfaceStyle.light.rawValue, forKey: "overrideUserInterfaceStyle")
    }
}

เพิ่งสังเกตเห็นว่าคุณไม่สามารถทำสิ่งนี้ภายในapplication(application: didFinishLaunchingWithOptions:)เพราะสำหรับตัวเลือกนี้จะไม่ตอบสนองtrueในช่วงแรกนั้น แต่คุณสามารถทำได้ในภายหลัง มันง่ายมากถ้าคุณใช้กำหนดเองAppPresenterหรือAppRouterคลาสในแอพของคุณแทนที่จะเริ่ม UI ใน AppDelegate โดยอัตโนมัติ


9

คุณสามารถปิดโหมดมืดในแอปพลิเคชันทั้งหมดใน Xcode 11:

  1. ไปที่ Info.plist
  2. เพิ่มร้องเหมือน

    <key>UIUserInterfaceStyle</key>
    <string>Light</string>

Info.plist จะมีลักษณะดังนี้ ...

ป้อนคำอธิบายรูปภาพที่นี่


1
ใช้งานไม่ได้กับ Xcode เวอร์ชัน 11.3.1 (11C504) ด้วยเหตุผลบางอย่าง
— Andrew

7

- สำหรับแอปทั้งหมด (หน้าต่าง):

window!.overrideUserInterfaceStyle = .light

คุณสามารถรับหน้าต่างได้จาก SceneDelegate

- สำหรับ ViewController เดียว:

viewController.overrideUserInterfaceStyle = .light

คุณสามารถตั้งค่าใด ๆviewControllerแม้ใน viewController มันด้วยตนเอง

- สำหรับมุมมองเดียว:

view.overrideUserInterfaceStyle = .light

คุณสามารถตั้งค่าใด ๆviewแม้ในมุมมองมันด้วยตนเอง

คุณอาจต้องใช้if #available(iOS 13.0, *) { ,,, }หากคุณรองรับ iOS เวอร์ชันก่อนหน้า


6

นอกเหนือจากการตอบสนองอื่น ๆ จากความเข้าใจของฉันต่อไปนี้คุณจะต้องเตรียมตัวสำหรับโหมดมืดเมื่อรวบรวมกับ iOS 13 SDK (ใช้ XCode 11)

ระบบจะถือว่าแอพที่เชื่อมโยงกับ iOS 13 หรือ SDK ที่ใหม่กว่ารองรับการปรากฏทั้งรูปแบบแสงและสีเข้ม ใน iOS คุณระบุลักษณะที่ปรากฏที่คุณต้องการโดยกำหนดสไตล์อินเตอร์เฟสเฉพาะให้กับหน้าต่างมุมมองหรือมุมมองคอนโทรลเลอร์ของคุณ นอกจากนี้คุณยังสามารถปิดการใช้งานการรองรับ Dark Mode โดยใช้ปุ่ม Info.plist

ลิงค์



2

แอพของฉันไม่รองรับโหมดมืดในขณะนี้และใช้สีแถบแอพแบบเบา ฉันสามารถบังคับให้เนื้อหาแถบสถานะเป็นข้อความและไอคอนสีเข้มได้โดยการเพิ่มคีย์ต่อไปนี้ในInfo.plist:

<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleDarkContent</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>

ค้นหาค่าที่เป็นไปได้อื่น ๆ ที่นี่: https://developer.apple.com/documentation/uikit/uistatusbarstyle


2

วัตถุประสงค์ -c รุ่น

 if (@available(iOS 13.0, *)) {
        _window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
    }

1

นี่คือเคล็ดลับและกลเม็ดเล็ก ๆ น้อย ๆ ที่คุณสามารถใช้ในแอพของคุณเพื่อสนับสนุนหรือเลี่ยงโหมดมืด

เคล็ดลับแรก: เพื่อแทนที่ลักษณะของ ViewController

คุณสามารถลบล้างลักษณะอินเตอร์เฟสของ UIViewController โดย

1: overrideUserInterfaceStyle = .dark // สำหรับโหมดมืด

2: overrideUserInterfaceStyle = .light // สำหรับโหมดไฟ

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        overrideUserInterfaceStyle = .light    
    }
}

เคล็ดลับที่สอง: การเพิ่มคีย์ใน info.plist

เพียงคุณสามารถเพิ่มรหัสใหม่

UIUserInterfaceStyle

ในข้อมูลแอพพลิเคชั่นของคุณและตั้งค่าเป็น Light หรือ Dark สิ่งนี้จะแทนที่สไตล์เริ่มต้นของแอปตามค่าที่คุณระบุ คุณไม่ต้องเพิ่ม overrideUserInterfaceStyle = .light บรรทัดนี้ในทุก viewController เพียงหนึ่งบรรทัดใน info.plist เท่านั้น


1

เพียงเพิ่มคีย์ต่อไปนี้ในinfo.plistไฟล์ของคุณ:

<key>UIUserInterfaceStyle</key>
    <string>Light</string>

1
 if #available(iOS 13.0, *) {
            overrideUserInterfaceStyle = .light
        } else {
            // Fallback on earlier versions
        }

คุณช่วยอธิบายได้นิดหน่อยว่าคำตอบนี้จะแก้ปัญหาได้อย่างไรแทนที่จะโพสต์คำตอบเฉพาะรหัสเท่านั้น
— Arun Vinoth

ใช่ @ArunVinoth ใน IOS 13 จะมีการเปิดตัวโหมดมืดดังนั้นหากเป้าหมายการปรับใช้ของคุณต่ำกว่า 13 ให้ใช้รหัสข้างต้นอื่นคุณสามารถใช้คำสั่งง่ายๆที่เขียนไว้ในบล็อก
— Talha Rasool

1

สวิฟท์ 5

สองวิธีในการสลับโหมดมืดเป็นแสง:

1- info.plist

    <key>UIUserInterfaceStyle</key>
    <string>Light</string>

2- โดยทางโปรแกรม

 UIApplication.shared.windows.forEach { window in
     window.overrideUserInterfaceStyle = .light
  } 

0

ฉันจะใช้วิธีแก้ปัญหานี้เนื่องจากคุณสมบัติของหน้าต่างอาจมีการเปลี่ยนแปลงระหว่างวงจรชีวิตของแอพ ดังนั้นการกำหนด "overrideUserInterfaceStyle = .light" จึงจำเป็นต้องทำซ้ำ UIWindow.appearance () ช่วยให้เราสามารถตั้งค่าเริ่มต้นที่จะใช้สำหรับวัตถุ UIWindow ที่สร้างขึ้นใหม่

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

      if #available(iOS 13.0, *) {
          UIWindow.appearance().overrideUserInterfaceStyle = .light
      }

      return true
    }
}

0

เพียงเพิ่มบรรทัดเหล่านี้ในไฟล์ info.plist:

<key>UIUserInterfaceStyle</key>
<string>light</string>

สิ่งนี้จะบังคับให้แอปทำงานในโหมดไฟเท่านั้น


สิ่งนี้มีการแสดงความคิดเห็นแล้วและตอบหลายครั้ง แม้แต่คำตอบที่ได้รับการยอมรับก็คือการแนะนำสิ่งนี้ ดังนั้นความคิดเห็นนี้จะไม่เพิ่มข้อมูลใหม่
— JeroenJK

0
import UIKit

extension UIViewController {

    override open func awakeFromNib() {

        super.awakeFromNib()

        if #available(iOS 13.0, *) {

            overrideUserInterfaceStyle = .light

        }

    }
}

2
โปรดเพิ่มคำอธิบายให้กับคำตอบของคุณโดยแก้ไขมันเพื่อให้คนอื่นสามารถเรียนรู้จากมันได้
— Nico Haase

0

คุณสามารถทำได้: เพิ่มคีย์ใหม่ UIUserInterfaceStyle เป็น Info.plist และตั้งค่าเป็น Light และตรวจสอบตัวควบคุมการแจ้งเตือนปรากฏขึ้นพร้อมโหมดแสง

UIUserInterfaceStyle Light หากคุณเป็นโหมดบังคับแสง / มืดในแอปพลิเคชันทั้งหมดโดยไม่คำนึงถึงการตั้งค่าของผู้ใช้โดยการเพิ่มคีย์ UIUserInterfaceStyle ลงในไฟล์ Info.plist ของคุณและตั้งค่าเป็น Light หรือ Dark


0

คำถามนี้มีคำตอบมากมายแทนที่จะใช้ในinfo.plistคุณสามารถตั้งเป็นAppDelegateดังนี้:

#if compiler(>=5.1)
        if #available(iOS 13.0, *) {
            self.window?.overrideUserInterfaceStyle = .light
        }
        #endif

ทดสอบ Xcode 11.3, iOS 13.3


-8

ที่จริงแล้วฉันเพิ่งเขียนโค้ดบางอย่างที่จะช่วยให้คุณสามารถยกเลิกโหมดมืดในโค้ดโดยไม่ต้อง putz กับคอนโทรลเลอร์ viw ทุกตัวในแอปพลิเคชันของคุณ สิ่งนี้อาจได้รับการขัดเกลาเพื่อเลือกไม่เข้าชั้นเรียนตามระดับชั้นเรียนโดยจัดการรายการของชั้นเรียน สำหรับฉันสิ่งที่ฉันต้องการคือให้ผู้ใช้ของฉันดูว่าพวกเขาชอบอินเทอร์เฟซโหมดมืดสำหรับแอพของฉันหรือไม่และถ้าพวกเขาไม่ชอบมันพวกเขาสามารถปิดได้ นี่จะช่วยให้พวกเขาใช้โหมดมืดต่อไปสำหรับแอปพลิเคชั่นที่เหลือ

ตัวเลือกของผู้ใช้เป็นสิ่งที่ดี (อะแฮ่มมองคุณ Apple นี่เป็นวิธีที่คุณควรนำไปใช้)

ดังนั้นวิธีการทำงานนี้เป็นเพียงหมวดหมู่ของ UIViewController เมื่อมันโหลดมันจะแทนที่เมธอด native viewDidLoad ด้วยวิธีที่จะตรวจสอบค่าสถานะโกลบอลเพื่อดูว่าโหมดมืดถูกปิดใช้งานสำหรับทุกสิ่งหรือไม่

เนื่องจากมันถูกทริกเกอร์ในการโหลด UIViewController มันควรจะเริ่มต้นโดยอัตโนมัติและปิดการใช้งานโหมดมืดโดยค่าเริ่มต้น หากนี่ไม่ใช่สิ่งที่คุณต้องการคุณจะต้องเข้าที่ก่อนกำหนดและตั้งค่าสถานะหรืออื่น ๆ เพียงตั้งค่าสถานะเริ่มต้น

ฉันยังไม่ได้เขียนอะไรเพื่อตอบสนองต่อผู้ใช้ในการเปิดหรือปิดการตั้งค่าสถานะ ดังนั้นนี่คือตัวอย่างโค้ดโดยทั่วไป หากเราต้องการให้ผู้ใช้โต้ตอบกับสิ่งนี้ผู้ควบคุมมุมมองทั้งหมดจะต้องโหลดซ้ำ ฉันไม่รู้ว่าจะทำอย่างไรในทันทีทันใด แต่การส่งการแจ้งเตือนบางอย่างอาจเป็นการหลอกลวง ดังนั้นในตอนนี้การเปิด / ปิดส่วนกลางสำหรับโหมดมืดจะทำงานเมื่อเริ่มต้นหรือเริ่มแอพใหม่เท่านั้น

ตอนนี้มันยังไม่เพียงพอที่จะลองปิดโหมดมืดในทุก ๆ มุมมอง MFING viewController ในแอพขนาดใหญ่ของคุณ หากคุณกำลังใช้สินทรัพย์สีคุณจะมีกระดูกสมบูรณ์ พวกเราเป็นเวลากว่า 10 ปีที่เข้าใจวัตถุที่ไม่เปลี่ยนรูปแบบซึ่งไม่อาจเปลี่ยนแปลงได้ สีที่คุณได้รับจากแคตตาล็อกสินทรัพย์สีระบุว่าเป็น UIColor แต่เป็นสีแบบไดนามิก (ไม่แน่นอน) และจะเปลี่ยนแปลงภายใต้ตัวคุณเนื่องจากระบบจะเปลี่ยนจากโหมดมืดเป็นแสง นั่นควรจะเป็นคุณสมบัติ แต่แน่นอนว่าไม่มีการสลับหลักเพื่อขอให้สิ่งเหล่านี้หยุดทำการเปลี่ยนแปลง (เท่าที่ฉันรู้ในตอนนี้บางทีอาจมีใครบางคนสามารถปรับปรุงได้)

ดังนั้นวิธีการแก้ปัญหาอยู่ในสองส่วน:

  1. หมวดหมู่สาธารณะบน UIViewController ที่ให้ประโยชน์ด้านสาธารณูปโภคและความสะดวกสบาย ... ตัวอย่างเช่นฉันไม่คิดว่าแอปเปิลคิดเกี่ยวกับข้อเท็จจริงที่ว่าพวกเราบางคนผสมโค้ดเว็บลงในแอพของเรา ด้วยเหตุนี้เราจึงมีสไตล์ชีทที่ต้องเปิดใช้งานตามโหมดมืดหรือสว่าง ดังนั้นคุณต้องสร้างวัตถุสไตล์ชีตแบบไดนามิก (ซึ่งจะดี) หรือถามว่าสถานะปัจจุบันคืออะไร (ไม่ดี แต่ง่าย)

  2. หมวดหมู่นี้เมื่อโหลดจะแทนที่เมธอด viewDidLoad ของคลาส UIViewController และการสกัดกั้นการโทร ฉันไม่รู้ว่านี่ทำผิดกฎของ App Store หรือไม่ ถ้าเป็นเช่นนั้นมีวิธีอื่นที่อาจเป็นไปได้ แต่คุณสามารถพิจารณาได้ว่าเป็นการพิสูจน์แนวคิด ตัวอย่างเช่นคุณสามารถสร้างคลาสย่อยหนึ่งประเภทของตัวควบคุมมุมมองหลักทั้งหมดและทำให้ตัวควบคุมมุมมองของคุณเองทั้งหมดสืบทอดจากสิ่งเหล่านั้นจากนั้นคุณสามารถใช้แนวคิดหมวดหมู่ DarkMode และเรียกใช้เพื่อบังคับให้ยกเลิกตัวควบคุมมุมมองทั้งหมดของคุณ มันน่าเกลียด แต่มันจะไม่ผิดกฎใด ๆ ฉันชอบที่จะใช้ runtime เพราะนั่นคือสิ่งที่ runtime ทำขึ้นมา ดังนั้นในรุ่นของฉันคุณเพียงแค่เพิ่มหมวดหมู่คุณตั้งค่าตัวแปรส่วนกลางในหมวดหมู่ว่าคุณต้องการให้มันปิดกั้นโหมดมืดหรือไม่และมันจะทำเช่นนั้น

  3. คุณยังไม่ได้ออกจากป่าดังที่กล่าวมาปัญหาอีกข้อคือ UIColor ทำสิ่งที่มันต้องการ ดังนั้นแม้ว่าตัวควบคุมมุมมองของคุณกำลังบล็อกโหมดมืด UIColor ไม่ทราบว่าคุณกำลังใช้อยู่ที่ไหนหรือวิธีการดังกล่าวไม่สามารถปรับได้ เป็นผลให้คุณสามารถดึงข้อมูลได้อย่างถูกต้อง แต่จากนั้นจะสามารถคืนค่าคุณได้ในอนาคต อาจจะช้าในภายหลัง ทางรอบนั้นคือการจัดสรรมันสองครั้งโดยใช้ CGColor และเปลี่ยนมันเป็นสีคงที่ ซึ่งหมายความว่าหากผู้ใช้ของคุณย้อนกลับไปและเปิดใช้งานโหมดมืดบนหน้าการตั้งค่าของคุณ (ความคิดที่นี่คือการทำให้การทำงานนี้เพื่อให้ผู้ใช้สามารถควบคุมแอปของคุณมากกว่าและเหนือส่วนที่เหลือของระบบ) สีคงทั้งหมดเหล่านั้น จำเป็นต้องเปลี่ยน จนถึงตอนนี้เหลือสำหรับคนอื่นที่จะแก้ปัญหา วิธีที่ง่ายที่สุดในการทำคือการเริ่มต้นให้คุณ กำลังออกจากโหมดมืดโดยแบ่งเป็นศูนย์เพื่อหยุดแอพเนื่องจากคุณไม่สามารถออกจากมันและบอกให้ผู้ใช้เพิ่งรีสตาร์ท นั่นอาจเป็นการละเมิดหลักเกณฑ์ของ App Store เช่นกัน แต่เป็นแนวคิด

หมวดหมู่ UIColor ไม่จำเป็นต้องถูกเปิดเผยเพียงแค่ใช้งานการเรียก colorNamed: ... ถ้าคุณไม่บอกคลาส DarkMode ViewController ให้บล็อกโหมดมืดมันจะทำงานได้อย่างสมบูรณ์แบบอย่างที่คาดไว้ พยายามทำให้บางสิ่งบางอย่างสวยงามแทนรหัสแอปเปิ้ลสปาเก็ตตี้มาตรฐานซึ่งหมายความว่าคุณจะต้องแก้ไขแอพส่วนใหญ่หากคุณต้องการยกเลิกโหมดมืดโดยใช้โปรแกรมหรือสลับมัน ตอนนี้ฉันไม่รู้ว่ามีวิธีที่ดีกว่าในการเปลี่ยน Info.plist แบบเป็นโปรแกรมเพื่อปิดโหมดมืดตามต้องการหรือไม่ เท่าที่ความเข้าใจของฉันไปถึงนั่นคือคุณลักษณะการรวบรวมเวลาและหลังจากนั้นคุณก็รู้สึกผิด

ดังนั้นนี่คือรหัสที่คุณต้องการ ควรดร็อปอินและใช้วิธีเดียวในการตั้งค่าสไตล์ UI หรือตั้งค่าเริ่มต้นในโค้ด คุณมีอิสระที่จะใช้แก้ไขทำอะไรก็ได้ที่คุณต้องการด้วยสิ่งนี้ไม่ว่าจะเพื่อวัตถุประสงค์ใดและไม่มีการรับประกันและฉันไม่รู้ว่าจะผ่านแอพสโตร์หรือไม่ การปรับปรุงยินดีมาก

การเตือนที่เป็นธรรมฉันไม่ได้ใช้ ARC หรือวิธีการจับอื่น ๆ

////// H file

#import <UIKit/UIKit.h>

@interface UIViewController(DarkMode)

// if you want to globally opt out of dark mode you call these before any view controllers load
// at the moment they will only take effect for future loaded view controllers, rather than currently
// loaded view controllers

// we are doing it like this so you don't have to fill your code with @availables() when you include this
typedef enum {
    QOverrideUserInterfaceStyleUnspecified,
    QOverrideUserInterfaceStyleLight,
    QOverrideUserInterfaceStyleDark,
} QOverrideUserInterfaceStyle;

// the opposite condition is light interface mode
+ (void)setOverrideUserInterfaceMode:(QOverrideUserInterfaceStyle)override;
+ (QOverrideUserInterfaceStyle)overrideUserInterfaceMode;

// utility methods
// this will tell you if any particular view controller is operating in dark mode
- (BOOL)isUsingDarkInterfaceStyle;
// this will tell you if any particular view controller is operating in light mode mode
- (BOOL)isUsingLightInterfaceStyle;

// this is called automatically during all view controller loads to enforce a single style
- (void)tryToOverrideUserInterfaceStyle;

@end


////// M file


//
//  QDarkMode.m

#import "UIViewController+DarkMode.h"
#import "q-runtime.h"


@implementation UIViewController(DarkMode)

typedef void (*void_method_imp_t) (id self, SEL cmd);
static void_method_imp_t _nativeViewDidLoad = NULL;
// we can't @available here because we're not in a method context
static long _override = -1;

+ (void)load;
{
#define DEFAULT_UI_STYLE UIUserInterfaceStyleLight
    // we won't mess around with anything that is not iOS 13 dark mode capable
    if (@available(iOS 13,*)) {
        // default setting is to override into light style
        _override = DEFAULT_UI_STYLE;
        /*
         This doesn't work...
        NSUserDefaults *d = NSUserDefaults.standardUserDefaults;
        [d setObject:@"Light" forKey:@"UIUserInterfaceStyle"];
        id uiStyle = [d objectForKey:@"UIUserInterfaceStyle"];
        NSLog(@"%@",uiStyle);
         */
        if (!_nativeViewDidLoad) {
            Class targetClass = UIViewController.class;
            SEL targetSelector = @selector(viewDidLoad);
            SEL replacementSelector = @selector(_overrideModeViewDidLoad);
            _nativeViewDidLoad = (void_method_imp_t)QMethodImplementationForSEL(targetClass,targetSelector);
            QInstanceMethodOverrideFromClass(targetClass, targetSelector, targetClass, replacementSelector);
        }
    }
}

// we do it like this because it's not going to be set often, and it will be tested often
// so we can cache the value that we want to hand to the OS
+ (void)setOverrideUserInterfaceMode:(QOverrideUserInterfaceStyle)style;
{
    if (@available(iOS 13,*)){
        switch(style) {
            case QOverrideUserInterfaceStyleLight: {
                _override = UIUserInterfaceStyleLight;
            } break;
            case QOverrideUserInterfaceStyleDark: {
                _override = UIUserInterfaceStyleDark;
            } break;
            default:
                /* FALLTHROUGH - more modes can go here*/
            case QOverrideUserInterfaceStyleUnspecified: {
                _override = UIUserInterfaceStyleUnspecified;
            } break;
        }
    }
}
+ (QOverrideUserInterfaceStyle)overrideUserInterfaceMode;
{
    if (@available(iOS 13,*)){
        switch(_override) {
            case UIUserInterfaceStyleLight: {
                return QOverrideUserInterfaceStyleLight;
            } break;
            case UIUserInterfaceStyleDark: {
                return QOverrideUserInterfaceStyleDark;
            } break;
            default:
                /* FALLTHROUGH */
            case UIUserInterfaceStyleUnspecified: {
                return QOverrideUserInterfaceStyleUnspecified;
            } break;
        }
    } else {
        // we can't override anything below iOS 12
        return QOverrideUserInterfaceStyleUnspecified;
    }
}

- (BOOL)isUsingDarkInterfaceStyle;
{
    if (@available(iOS 13,*)) {
        if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark){
            return YES;
        }
    }
    return NO;
}

- (BOOL)isUsingLightInterfaceStyle;
{
    if (@available(iOS 13,*)) {
        if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight){
            return YES;
        }
        // if it's unspecified we should probably assume light mode, esp. iOS 12
    }
    return YES;
}

- (void)tryToOverrideUserInterfaceStyle;
{
    // we have to check again or the compile will bitch
    if (@available(iOS 13,*)) {
        [self setOverrideUserInterfaceStyle:(UIUserInterfaceStyle)_override];
    }
}

// this method will be called via the viewDidLoad chain as we will patch it into the
// UIViewController class
- (void)_overrideModeViewDidLoad;
{
    if (_nativeViewDidLoad) {
        _nativeViewDidLoad(self,@selector(viewDidLoad));
    }
    [self tryToOverrideUserInterfaceStyle];
}


@end

// keep this in the same file, hidden away as it needs to switch on the global ... yeah global variables, I know, but viewDidLoad and colorNamed: are going to get called a ton and already it's adding some inefficiency to an already inefficient system ... you can change if you want to make it a class variable. 

// this is necessary because UIColor will also check the current trait collection when using asset catalogs
// so we need to repair colorNamed: and possibly other methods
@interface UIColor(DarkMode)
@end

@implementation UIColor (DarkMode)

typedef UIColor *(*color_method_imp_t) (id self, SEL cmd, NSString *name);
static color_method_imp_t _nativeColorNamed = NULL;
+ (void)load;
{
    // we won't mess around with anything that is not iOS 13 dark mode capable
    if (@available(iOS 13,*)) {
        // default setting is to override into light style
        if (!_nativeColorNamed) {
            // we need to call it once to force the color assets to load
            Class targetClass = UIColor.class;
            SEL targetSelector = @selector(colorNamed:);
            SEL replacementSelector = @selector(_overrideColorNamed:);
            _nativeColorNamed = (color_method_imp_t)QClassMethodImplementationForSEL(targetClass,targetSelector);
            QClassMethodOverrideFromClass(targetClass, targetSelector, targetClass, replacementSelector);
        }
    }
}


// basically the colors you get
// out of colorNamed: are dynamic colors... as the system traits change underneath you, the UIColor object you
// have will also change since we can't force override the system traits all we can do is force the UIColor
// that's requested to be allocated out of the trait collection, and then stripped of the dynamic info
// unfortunately that means that all colors throughout the app will be static and that is either a bug or
// a good thing since they won't respond to the system going in and out of dark mode
+ (UIColor *)_overrideColorNamed:(NSString *)string;
{
    UIColor *value = nil;
    if (@available(iOS 13,*)) {
        value = _nativeColorNamed(self,@selector(colorNamed:),string);
        if (_override != UIUserInterfaceStyleUnspecified) {
            // the value we have is a dynamic color... we need to resolve against a chosen trait collection
            UITraitCollection *tc = [UITraitCollection traitCollectionWithUserInterfaceStyle:_override];
            value = [value resolvedColorWithTraitCollection:tc];
        }
    } else {
        // this is unreachable code since the method won't get patched in below iOS 13, so this
        // is left blank on purpose
    }
    return value;
}
@end

มีชุดยูทิลิตี้ฟังก์ชั่นที่ใช้สำหรับการทำวิธีการแลกเปลี่ยน แยกไฟล์ นี่คือสิ่งมาตรฐานแม้ว่าและคุณสามารถค้นหารหัสที่คล้ายกันได้ทุกที่

// q-runtime.h

#import <Foundation/Foundation.h>
#import <objc/message.h>
#import <stdatomic.h>

// returns the method implementation for the selector
extern IMP
QMethodImplementationForSEL(Class aClass, SEL aSelector);

// as above but gets class method
extern IMP
QClassMethodImplementationForSEL(Class aClass, SEL aSelector);


extern BOOL
QClassMethodOverrideFromClass(Class targetClass, SEL targetSelector,
                              Class replacementClass, SEL replacementSelector);

extern BOOL
QInstanceMethodOverrideFromClass(Class targetClass, SEL targetSelector,
                                 Class replacementClass, SEL replacementSelector);


// q-runtime.m

static BOOL
_QMethodOverride(Class targetClass, SEL targetSelector, Method original, Method replacement)
{
    BOOL flag = NO;
    IMP imp = method_getImplementation(replacement);
    // we need something to work with
    if (replacement) {
        // if something was sitting on the SEL already
        if (original) {
            flag = method_setImplementation(original, imp) ? YES : NO;
            // if we're swapping, use this
            //method_exchangeImplementations(om, rm);
        } else {
            // not sure this works with class methods...
            // if it's not there we want to add it
            flag = YES;
            const char *types = method_getTypeEncoding(replacement);
            class_addMethod(targetClass,targetSelector,imp,types);
            XLog_FB(red,black,@"Not sure this works...");
        }
    }
    return flag;
}

BOOL
QInstanceMethodOverrideFromClass(Class targetClass, SEL targetSelector,
                                 Class replacementClass, SEL replacementSelector)
{
    BOOL flag = NO;
    if (targetClass && replacementClass) {
        Method om = class_getInstanceMethod(targetClass,targetSelector);
        Method rm = class_getInstanceMethod(replacementClass,replacementSelector);
        flag = _QMethodOverride(targetClass,targetSelector,om,rm);
    }
    return flag;
}


BOOL
QClassMethodOverrideFromClass(Class targetClass, SEL targetSelector,
                              Class replacementClass, SEL replacementSelector)
{
    BOOL flag = NO;
    if (targetClass && replacementClass) {
        Method om = class_getClassMethod(targetClass,targetSelector);
        Method rm = class_getClassMethod(replacementClass,replacementSelector);
        flag = _QMethodOverride(targetClass,targetSelector,om,rm);
    }
    return flag;
}

IMP
QMethodImplementationForSEL(Class aClass, SEL aSelector)
{
    Method method = class_getInstanceMethod(aClass,aSelector);
    if (method) {
        return method_getImplementation(method);
    } else {
        return NULL;
    }
}

IMP
QClassMethodImplementationForSEL(Class aClass, SEL aSelector)
{
    Method method = class_getClassMethod(aClass,aSelector);
    if (method) {
        return method_getImplementation(method);
    } else {
        return NULL;
    }
}

ฉันกำลังคัดลอกและวางไฟล์นี้สองสามไฟล์ตั้งแต่ q-runtime.h เป็นไลบรารีที่ใช้ซ้ำได้ของฉันและนี่เป็นเพียงส่วนหนึ่งของมัน หากสิ่งที่ไม่ได้รวบรวมแจ้งให้ฉันทราบ


คุณไม่โชคดีเมื่อพูดถึงการควบคุมพฤติกรรมของ UIColor ดังที่กล่าวไว้ในคำถามนี้: stackoverflow.com/questions/56487679/…
— raven_raven
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.