iOS使用Firebase Authentication的基本使用

1. 簡介

可以讓用戶使用其電子郵件地址和密碼進行 Firebase 身份驗證,還可以管理應用中的帳號

更多詳細內容可以參考官網:

https://firebase.google.com/docs/auth/ios/password-auth

2. 前置作業

請參考iOS專案如何導入Firebase?

3. 建立帳號

備註:前置作業必須先用好

建立以email的方式創建帳號

啟用並儲存

以下程式碼,可以寫在Button按下去後,執行他

email與password皆是String,就是要建立的帳號

執行後,會呼叫Lambda,error如果是nil代表成功,如果有error則是失敗

//記得import Firebase
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
  
}

Firebase建立帳號有一些規則

Email必須是有效的

密碼必須大於六個字符

呼叫上面function,就會建立帳號,建立好後
就會在Firebase後臺上出現剛剛建立好的帳號

到此建立帳號就完成囉

登入帳號

觸發以下後,會登入帳號,email與password是先前建立好的帳號

//記得import Firebase
Auth.auth().signIn(withEmail: email, password: password) { [weak self] authResult, error in
    guard let self = self else { return }
                
}

登出帳號

觸發以下後,會登出帳號

//記得import Firebase
let firebaseAuth = Auth.auth()
do {
    try firebaseAuth.signOut()
    navigationController?.popToRootViewController(animated: true)
} catch let signOutError as NSError {
    print("Error signing out: %@", signOutError)
}


iOS

iOS專案如何導入Firebase?

1. 簡介 Firebase是Google所開發的一個強大的…

u66f4u591au5167u5bb9…


訂閱Codeilin的旅程,若有最新消息會通知。

廣告

iOS專案如何導入Firebase?

1. 簡介

Firebase是Google所開發的一個強大的Library,裡面有許多實用的功能

包含身分認證、機器學習套件、Cloud Firebase、性能監控等等

更多詳細內容可以參考官網:

https://firebase.google.com/docs

2. Firebase導入iOS專案

首先打開官網:

https://firebase.google.com/

取消打勾,因為牽涉很多其他功能,此文章暫時不需要
從XCode複製Bundle identifier
Apple軟體包ID就是指XCode的Bundle identifier
其他兩個選項可選,此文章不填
將下載的plist用拖移的方式,拖移置對應的專案中
選擇需要使用的Library
選擇iOS專案的語言,將此程式碼複製到專案中的AppDelegate

到此Firebase就成功加入至iOS專案囉


iOS


訂閱Codeilin的旅程,若有最新消息會通知。

廣告

iOS SwiftUI 客製化多邊形圖片

簡要

先找到一張想要畫的多邊形圖片

在運用GeoGebra網頁,然後描邊,在按照順序填入

1. 將圖片導入GeoGebra網站,生成座標

先點選數字1,右邊的框框就會對應到相對的位置
先把圖片A與B座標,設定在右下角
方便iOS之後導入座標
快速顯示所有圖片
不小心用錯了可以按這裡還原/重做
點選1,按複製,或者ctrl+c
之後ctrl+v貼上時,會重疊再一起
像這樣描外誆
按順序排
記得如果有圓角要描仔細一點
顯示的圖片才會好看
描完後,左側就有座標囉

按照上面的方法做完後,接下來就回到XCode,這些座標就是畫圖用的

2.將座標畫出來

首先將剛剛網站上畫的軌跡,x與y座標寫成一個Funcion,如下方程式碼內的createPath

注意:剛剛網站的Y是負數,iOS要改為正數

因為網站是第四象限,iOS是左上角是(0,0),往下往右是遞增

放置struct ShowUIView: UIViewRepresentable裡面

struct ShowUIView: UIViewRepresentable {
    func createPath() -> UIBezierPath {
        let path = UIBezierPath()
        path.move(to: CGPoint(
                    x: 10,
                    y: 20))
        path.addLine(to: CGPoint(
                        x: 5.0131866949857,
                        y: 19.9479187627672))
        path.addLine(to: CGPoint(
                        x: 5.0417361556575,
                        y: 12.1197330991145))
        path.addLine(to: CGPoint(
                        x: 2.0710520438094,
                        y: 12.0451656773068))
        path.addLine(to: CGPoint(
                        x: 12.0363540202362,
                        y: 3.0948821110817))
        path.addLine(to: CGPoint(
                        x: 22,
                        y: 12))
        path.addLine(to: CGPoint(
                        x: 19.030971884815,
                        y: 12.069872043932))
        path.addLine(to: CGPoint(
                        x: 19.030971884815,
                        y: 19.7983355972197))
        path.addLine(to: CGPoint(
                        x: 14,
                        y: 20))
        path.addLine(to: CGPoint(
                        x: 14,
                        y: 14))
        path.addLine(to: CGPoint(
                        x: 10,
                        y: 14))
        path.close()
        
        return path
    }
    func getViewbyPath(type: Int) -> UIView {
        let path = createPath()
        let view = UIView()
        let backgroundView = UIView(
            frame: CGRect(
                x: 0,
                y: 0,
                width: 24,
                height: 24)
        )
        
        let orangeView = UIView(frame: backgroundView.frame)
        orangeView.backgroundColor =
            UIColor(
                red: 255/255,
                green: 82/255,
                blue: 0/255, alpha: 1
            )
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = path.cgPath
        //將橘色背景加入mask,就是剛剛描的圖片
        orangeView.layer.mask = shapeLayer
        backgroundView.addSubview(orangeView)
        view.addSubview(backgroundView)
        return view
    }
    
    func makeUIView(context: Context) -> UIView {
        return getViewbyPath(type: type)
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
        
    }
    
    typealias UIViewType = UIView

}

這樣簡單的UIView就建立完成了

3. 顯示UIView

struct ShowView: View {
    var body: some View {
        return GeometryReader { geometry in
            ZStack {
                Color
                    .black
                    .contentShape(Path(CGRect(
                                        origin: .zero,
                                        size: geometry.size)))
                ShowUIView(type: 0)
                    .frame(width: 24, height: 24)
            }
        }
    }
}
效果圖

剛剛描的圖片放上去囉,圖片大小在最初描的時候,就已經決定了

不過他可以使用.scaleEffect(2, anchor: .center)

將圖片放大,anchor:放大/縮小的基準位置

不過在有些地方使用scale會比較難控制,最初選好大小會比較方便喔


訂閱Codeilin的旅程,若有最新消息會通知。

廣告

iOS SwiftUI PreferenceKey監聽變化

PreferenceKey是key與value的存取,監聽之間的變化

以下以監聽View大小為範例

建立流程

1. 先輸輸入下圖方式,再按修復

2. 修復後如下圖

3.  typealias Value輸入要監聽的資料,輸入後打defaultValue就可以直接選到對應的func

4. reduce裡面的value是當前,nextValue 是變更後的資料

本範例只需要存入即可

這樣基本的建立就完成了

使用方法

1. 設定Preference為geometry.size

2. 引用方式

Text("1234567890abcdefg")
     .background(ListenerView())

3. 監聽PreferenceKey變化

struct MainView: View {
    @State var size: CGSize = .zero
    var body: some View {
        VStack {
            Text("1234567890abcdefg")
                .background(ListenerView())
                .onPreferenceChange(
                    ViewSizeKey.self
                ) { value in
                    //當ViewSizeKey發生改變,會觸發此
                    print("value \(value)")
            }
        }
    }
}


訂閱Codeilin的旅程,若有最新消息會通知。

廣告

iOS Swift 螢幕翻轉(Screen Rotation)

1. 前置設定

2. 手動螢幕翻轉

3. 恢復自動螢幕翻轉

1. 前置設定

在 AppDelegate.swift 內輸入以下程式碼,以下範例鎖定portrait

static var orientationLock = UIInterfaceOrientationMask.portrait
func application(
    _ application: UIApplication, 
    supportedInterfaceOrientationsFor window: UIWindow?
) -> UIInterfaceOrientationMask {
    return AppDelegate.orientationLock
}

2. 手動螢幕翻轉

AppDelegate.orientationLock = UIInterfaceOrientationMask.landscapeLeft
UIDevice.current.setValue(
    UIInterfaceOrientation.landscapeLeft.rawValue,
    forKey: "orientation"
)
UIViewController.attemptRotationToDeviceOrientation()

3. 恢復自動螢幕翻轉

AppDelegate.orientationLock = UIInterfaceOrientationMask.all
UIDevice.current.setValue(
    UIInterfaceOrientation.landscapeLeft.rawValue,
    forKey: "orientation"
)
UIViewController.attemptRotationToDeviceOrientation()

訂閱Codeilin的旅程,若有最新消息會通知。

廣告

iOS SwiftUI Animation Complete Listener

執行效果

重寫可動畫類數據

//VectorArithmetic 可動畫類型的數據
extension View {
    //定義Data為VectorArithmetic
    //ModifiedContent是指,將此Self示圖
    //經由AnimationDataChangeModifier,修改後產生新的示圖
    //modifier主要是回傳ModifiedContent
    
    func onAnimationDataChange(
        for data: Data,
        onComplete: @escaping () -> Void
    )
    -> ModifiedContent<Self, AnimationDataChangeModifier> {
        return modifier(AnimationDataChangeModifier(
                            changeData: data,
                            onComplete: onComplete))
    }
}

//指處where Data: VectorArithmetic
//確保資料類型是VectorArithmetic
//AnimatableModifier繼承於 
//Animatable, ViewModifier,可動畫的修改器
struct AnimationDataChangeModifier
: AnimatableModifier where Data: VectorArithmetic {
    //animatableData是繼承Animatable的資料,監聽變化
    var animatableData: Data {
        didSet {
            dataChangeCallback()
        }
    }

    private var previousData: Data
    private var onComplete: () -> Void
    //此處要注意,順序很重要
    init(
        changeData: Data,
        onComplete: @escaping () -> Void
    ) {
        //先註冊callback,完成時回調
        self.onComplete = onComplete
        
        //此處是關鍵
        //animatableData改變會先呼叫didSet
        //此時呼叫dataChangeCallback
        //animatableData已改變資料,previousData尚未改變
        self.animatableData = changeData
        
        //執行這行後previousData才改變資料
        previousData = changeData
    }

    private func dataChangeCallback() {
        guard animatableData == previousData else {
            return
        }

        DispatchQueue.main.async {
            self.onComplete()
        }
    }

    func body(content: Content) -> some View {
        return content
    }
}

使用方法

//onAnimationDataChange
//必須要使用withAnimation的變數變化,才會觸發
//因為VectorArithmetic 可動畫類型的數據
struct MainView: View {
    @State var opacity: Double = 1
    @State var animation = false
    var body: some View {
        Text("1234567890abcdefg")
            .opacity(animation ? opacity : 1)
            .animation(animation ?
                           Animation.linear : nil
            )
            .onAnimationDataChange(for: opacity) {
                if opacity == 0.1 {
                    withAnimation(
                        Animation.linear(duration: 1)) {
                        opacity = 1
                    }
                } else {
                    withAnimation(
                        Animation.linear(duration: 1)) {
                        opacity = 0.1
                    }
                }
            }
            .onAppear {
                animation = true
                withAnimation(
                    Animation.linear(duration: 1)) {
                    opacity = 0.1
                }

            }
    }
}

訂閱Codeilin的旅程,若有最新消息會通知。

廣告

iOS SwiftUI Text跑馬燈(Marquee)

執行效果

Text基礎設定

Text("PPPPPPPP OOOOOOOOOO IIIIIIIIII UUUUUUUUUU YYYYYYYYYY")
     //縮放最小的大小
     .minimumScaleFactor(0.5)
     //最大兩行
     .lineLimit(2)
     //allowsTightening設定成true的時,適應文本大小
     //空間太小直接變...
     .allowsTightening(false)
     //多行皆以.center為對齊方式
     .multilineTextAlignment(.center)
     .foregroundColor(Color.white)
     .padding(.leading, 10)
     .padding(.trailing, 10)

Text文字大小讀取

//1.繼承String新增方式
 extension String {
     func widthOfString(usingFont font: UIFont) -> CGFloat {
         let fontAttributes = [NSAttributedString.Key.font: font]
         let size = self.size(withAttributes: fontAttributes)
         return size.width
     }

     func heightOfString(usingFont font: UIFont) -> CGFloat {
         let fontAttributes = [NSAttributedString.Key.font: font]
         let size = self.size(withAttributes: fontAttributes)
         return size.height
     }

     func sizeOfString(usingFont font: UIFont) -> CGSize {
         let fontAttributes = [NSAttributedString.Key.font: font]
         return self.size(withAttributes: fontAttributes)
     }
 }
 //2.讀取Text大小方式
 let width: CGFloat = String("1234567890abc")
     .widthOfString(usingFont: UIFont.systemFont(ofSize: 18))
 let height: CGFloat = String("1234567890abc")
     .heightOfString(usingFont: UIFont.systemFont(ofSize: 18))
 let size: CGSize = String("1234567890abc")
     .sizeOfString(usingFont: UIFont.systemFont(ofSize: 18))

Text跑馬燈

struct paramModel {
    var animation: Int = 0
    var textSize: CGFloat = 0
    var opacity: Double = 1
    var offsetXCurrent: CGFloat = 0
    var offsetXMax: CGFloat = 0
}

struct AMainView: View {
    @State var param = paramModel()
    let moveTime = 2.0//移動時間
    let lastStopTime = 1.0//移動到最後,停止時間
    let opacityTime = 0.1//停止後,隱藏文字動畫時間
    let hideTime = 0.6//動畫結束後,至初始化等待時間
    let firstStopTime = 1.0//初始化後,等待移動文字時間
    
    func getFirstStopTime() -> DispatchTime {
        return DispatchTime.now()+firstStopTime
    }
    
    func getMoveAndStopTime() -> DispatchTime {
        return DispatchTime.now()+moveTime+lastStopTime
    }
    
    func getMoveToEndTime() -> DispatchTime {
        return DispatchTime.now()+moveTime+lastStopTime+hideTime+opacityTime
    }
    var body: some View {
        return GeometryReader { geometry in
            let maxSize = geometry.size.width//最大文字範圍(避免變...)
            let limitSize = geometry.size.width / 2//要顯示文字範圍
            Group {
                Text("1234567890abcdefghiABCDEFGHIJKLMNOP")
                    .foregroundColor(.red)
                    .font(.system(size: 18))
                    .lineLimit(1)
                    .allowsTightening(true)
                    .background(ListenerView())
                    .onPreferenceChange(ViewSizeKey.self) { _ in
                        param.textSize = CGFloat(
                            String("1234567890abcdefghiABCDEFGHIJKLMNOP")
                                .widthOfString(usingFont: UIFont.systemFont(ofSize: 18))
                        )
                        withAnimation(Animation.linear) {
                            param.offsetXCurrent = limitSize-param.textSize
                            param.offsetXMax = limitSize-param.textSize
                        }
                    }
                    .offset(x:
                               (param.animation != 0 && param.textSize != 0) ?
                             param.offsetXCurrent : 0 ,
                            y: 0
                    )
                    .opacity(param.opacity)
                    .animation(
                     param.animation == 1 ?
                         Animation.linear(duration: moveTime) : param.animation == 2 ?
                         Animation.linear(duration: opacityTime) : nil
                    )
                    .onAnimationDataChange(for: param.offsetXCurrent) {
                        if param.offsetXMax == 0 {
                            return
                        }
                        if param.offsetXCurrent == 0 {
                            DispatchQueue.main.asyncAfter(
                                deadline:
                                    getFirstStopTime(),
                                execute: {
                                    withAnimation(Animation.default, {
                                    param.offsetXCurrent = param.offsetXMax
                                   })
                               })
                        } else if param.offsetXCurrent != 0  {
                            param.animation = 1
                            DispatchQueue.main.asyncAfter(
                                deadline:
                                    getMoveAndStopTime(),
                                execute: {
                                    param.animation = 2
                                    param.opacity = 0
                                })

                            DispatchQueue.main.asyncAfter(
                            deadline:
                                getMoveToEndTime(),
                            execute: {
                                param.animation = 0
                                withAnimation(Animation.default, {
                                    param.offsetXCurrent = 0
                                })
                                param.opacity = 1
                           })
                       }
                    }
                    .frame(width: maxSize, alignment: .leading)//這不設定,過長文字會變成...
           }.frame(width: limitSize, alignment: .leading)
           .mask (
            HStack(spacing: 0) {
                LinearGradient(
                    gradient: Gradient(
                        colors: [Color.black, Color.black]
                    ),
                    startPoint: .leading,
                    endPoint: .trailing
                )
            }
           ).frame(width: limitSize)
       }
    }
}

訂閱Codeilin的旅程,若有最新消息會通知。

廣告

iOS SwiftUI Button背景透明無法點擊問題

問題如下

ZStack內的Color.clear是透明色時

該Button點擊範圍為Text的文字長度

會導致點擊的範圍,只能點在文字上

如果Button width = 200,Text width = 100, 點擊範圍只有"100″在文字上

如果點擊在文字外,將無法點擊

 Button(action: {
         print("click")
 }, label: {
     ZStack {
         Color.clear
         Text("1234567")
             .foregroundColor(contentIndex == index ? 
                    Color("blue_2") : Color("gray_5"))
             .padding()
     }
 })

解決方法如下:

Color.clear用GeometryReader包住

取得此區域的最大Size

然後contentShape設定能點擊的範圍

設定後,此Color.clear將是Button能點擊範圍

不會因為設定成透明色而無法點擊

 Button(action: {
         print("click")
 }, label: {
     ZStack {
         GeometryReader { geometry in
             Color.clear.contentShape(Path(CGRect(origin: .zero, size: geometry.size)))
         }
         Text(contentArrayTemp[index].id ?? "")
             .foregroundColor(contentIndex == index ? 
                    Color("blue_2") : Color("gray_5"))
             .padding()
     }
 })

訂閱Codeilin的旅程,若有最新消息會通知。

廣告

iOS Swift Core Data資料庫使用

1. 在創建專案的時候,將Use Core Data打勾

2. 打勾後專案建立時,會在專案目錄下,出現xxxx.xcdatamodeld,xxxx是專案名字

3. 幫Model建立資料

4. Model處理完後,就能拿來使用

5. 建立一個class架構來使用Core Data

6. 使用方法

1. 在創建專案的時候,將Use Core Data打勾

2. 打勾後專案建立時,會在專案目錄下
出現xxxx.xcdatamodeld,xxxx是專案名字

3. 幫Model建立資料,如下圖
a. Add Entity
b. 修改Entity名字
c. 新增資料和資料形態

4. Model處理完後,就能拿來使用

//記得import才能使用
import CoreData

//取得Context
let context = appDelegate.persistentContainer.viewContext

//forEntityName,就是3.那張圖裡面數字 2 的名字,如下
let coreDataName = "CameraInfoModel"
NSEntityDescription.insertNewObject(
                         forEntityName: coreDataName, 
                         into: context
                     ) as? CameraInfoModel

5. 建立一個class架構來使用Core Data

//1.初始化傳入使用的EntityName,還有NSManagedObjectContext
class CoreDataBase {
    let coreDataName: String?
    let context: NSManagedObjectContext
    init(
    coreDataName: String?,
    context: NSManagedObjectContext
    ) {
        self.coreDataName = coreDataName
        self.context = context
    }
    ...
}
//2.資料讀取,傳入NSPredicate條件篩選
//以及如何排列資料和限制數量
//為了可以彈性所以皆使用?
func fetch(
    predicate: String?,
    sort: [[String: Bool]]?,
    limit:Int?
) -> [CameraInfoModel]? {
    if let coreDataName = self.coreDataName {
        //選擇
        let request = NSFetchRequest<NSFetchRequestResult>(
            entityName: coreDataName
        )
        //條件篩選
        if let predicate = predicate {
            request.predicate = 
                   NSPredicate(format: predicate)
        }
        //資料排列,可以有多個組合
        if let sort = sort {
            var array: [NSSortDescriptor] = []
            for sortCondition in sort {
                for(key, value) in sortCondition {
                array.append(NSSortDescriptor(
                    key: key,
                    ascending: value
                ))
            }
            }
            request.sortDescriptors = array
        }
        //設定長度限制
        if let limitNumber = limit {
            request.fetchLimit = limitNumber
        }
        do {
            //讀取資料
            let results =
            try context.fetch(request) 
                    as? [CameraInfoModel]
                if let results = results {
                    //資料不為nil則回傳
                    return results
                }
            } catch {
                fatalError("\(error)")
            }
        }
    return nil
}
//3. 新增資料
func insert(
    attributes: [[String: String]]
) -> Bool {
    if let coreDataName = self.coreDataName {
        //取得要新增的資料
        let data = NSEntityDescription.insertNewObject(
                forEntityName: coreDataName,
        into: context
        ) as? CameraInfoModel
        //如果有取得到才做
        if let data = data {
            //傳入要設定的資料
            for attribute in attributes {
                for (key, value) in attribute {
                //檢查資料型態
                let type = data
                    .entity
                    .attributesByName[key]?
                    .attributeType
                if type == .integer16AttributeType
                      || type == .integer32AttributeType
                      || type == .integer64AttributeType {
                    //設定資料
                    data.setValue(
                        Int(value), 
                        forKey: key
                    )
                } else if type == .doubleAttributeType
                        || type == .floatAttributeType {
                    //設定資料
                    data.setValue(
                        Double(value), 
                        forKey: key
                    )
                } else if type == .booleanAttributeType {
                    //設定資料
                    data.setValue(
                        value == "true" ?
                            true : false, 
                        forKey: key
                    )
                } else {
                    //設定資料
                    data.setValue(
                        value, 
                        forKey: key
                    )
                }
            }
            }
            do {
                //設定完後將資料儲存
                try context.save()
                    //設定完成返回成功
                    return true
                } catch {
                }
            }
    }
    return false
}
//4. 更新資料
func update(
    predicate: String?,
    attritube: [String: String]
) -> Bool {
    //讀取資料
    if let results = fetch(
            predicate: predicate,
    sort: nil,
    limit: nil
    ) {
        //將讀取的資料做改變
        for result in results {
            for(key, value) in attritube {
            let type = result
                .entity
                .attributesByName[key]?
                .attributeType
            if type == .integer16AttributeType
                    || type == .integer32AttributeType
                    || type == .integer64AttributeType {
                result.setValue(Int(value), forKey: key)
            } else if type == .doubleAttributeType
                    || type == .floatAttributeType {
                result.setValue(Double(value), forKey: key)
            } else if type == .booleanAttributeType {
                result.setValue(
                          value == "true" ? true : false,
                          forKey: key
                )
            } else {
                result.setValue(value, forKey: key)
            }
        }
        }
        do {
            //儲存資料
            try self.context.save()
                //設定完成返回成功
                return true
            } catch {
                fatalError("\(error)")
            }
        }
    return false
}
//5. 刪除資料
func delete(
    predicate: String?
) -> Bool {
    //讀取資料
    if let results = fetch(
            predicate: predicate,
    sort: nil,
    limit: nil
    ) {
        //將讀取的資料刪除
        for result in results {
            context.delete(result)
        }
        do {
            //儲存資料
            try context.save()
                //設定完成返回成功
                return true
            } catch {
            }
        }
    return false
}

6. 使用方法

//取得AppDelegate
let appDelegate = 
          (UIApplication.shared.delegate as? AppDelegate)
if let appDelegate = appDelegate {
    //取得NSManagedObjectContext
    let context = 
        appDelegate.persistentContainer.viewContext
    //初始化CoreDataBase
    let coreDataBase = CoreDataBase(
        coreDataName: "CameraInfoModel", 
        context: context
    )
    //插入資料
    var array: [[String: String]] = [[:]]
    array.append(["name": "John"])
    array.append(["ssid": "DIE12345321"])
    let successed = coreDataBase.insert(attributes: array)
    //讀取資料
    if let results = coreDataBase.fetch(
                        predicate: nil, 
                        sort: [["name": true]], limit: nil
                    ) {
        for result in results {
            print("result \(result.name), \(result.ssid)")
        }
    }
    //更新資料
    let successed = coreDataBase.update(
                        predicate: nil, 
                        attritube: ["ssid": "12345"]
                    )
    //刪除資料
    let successed = coreDataBase.delete(predicate: nil)
    //條件選擇,讀取資料
    if let results = coreDataBase.fetch(
                        predicate: "name = \"John\" || 
                                ssid = \"DIE12345321\"", 
                        sort: [["name": true]], limit: nil
                    ) {
        for result in results {
            print("result \(result.name), \(result.ssid)")
        }
    }
}

訂閱Codeilin的旅程,若有最新消息會通知。

廣告

iOS Swift Status bar style變更

  1. 從手機改變Status bar style
  2. 由App專案改變Status bar style,有兩個方法

1. 從手機改變Status bar style

根據iPhone -> 設定 -> 螢幕顯示與亮度 -> 淺色/深色,選擇的則為預設

2. 由App專案改變Status bar style

方法1

在SceneDelegate.swift裡面,新增一個class,如下

class HostingController: UIHostingController 
        where ContentView : View {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        //要使用的Status文字預設樣式
        //.darkContent or .lightContent
        return .darkContent
    }
}

將預設的
window.rootViewController = UIHostingController(rootView: contentView)
改為
window.rootViewController = HostingController(rootView: contentView)

方法2

改變圖片內,紅框的部分

訂閱Codeilin的旅程,若有最新消息會通知。

廣告

透過 WordPress.com 建置的網站.

向上 ↑