SwiftUI項(xiàng)目總結(jié)

最近使用SwiftUI做項(xiàng)目,鄙人沒(méi)有想到還會(huì)用它做項(xiàng)目,SwiftUI的優(yōu)勢(shì)不用多說(shuō),把開(kāi)發(fā)過(guò)程中遇到問(wèn)題歸納一下

一 給list加側(cè)滑

在iOS15中 使用 .swipeActions(edge: .trailing,allowsFullSwipe: false) 所有的層疊布局(overlay 和 backgroond 全部失效),。文字顏色,圖片大小 都無(wú)法修改。通過(guò)蘋(píng)果官方文檔只能實(shí)現(xiàn)如下:

image.png

而如果要實(shí)現(xiàn)這種該如何呢???

截屏2024-12-04 15.51.34.png

解決辦法: 自定義Drap手勢(shì),利用ViewModifier進(jìn)行實(shí)現(xiàn)。

ViewModifier是SwiftUI中一個(gè)用于封裝和重用視圖修改邏輯的協(xié)議。通過(guò)實(shí)現(xiàn)這個(gè)協(xié)議,可以創(chuàng)建自定義的修改器(modifier),這樣就可以應(yīng)用于任何視圖,以改變其外觀、行為或其它屬性。使用ViewModifier可以方便地統(tǒng)一調(diào)整全局效果,提高代碼的可重用性和維護(hù)性。

二 給某個(gè)組件加部分圓角的方法

2.1 使用clipShape
 Blur()
            .clipShape(CustomRoundedRectangle(corners: [.bottomLeft,.bottomRight], radius: 24~))
2.2 使用 background
 .background {
                CustomRoundedRectangle(corners: [.bottomLeft,.bottomRight], radius: 24~)
            }

使用background在某些視圖上設(shè)置圓角沒(méi)效果,比如這里的 Blur()組件

struct Blur: UIViewRepresentable {
    let style: UIBlurEffect.Style = .dark
    func makeUIView(context: Context) -> UIVisualEffectView {
        return UIVisualEffectView(effect: UIBlurEffect(style: style))
    }

    func updateUIView(_ uiView: UIVisualEffectView, context: Context) {
        uiView.effect = UIBlurEffect(style: style)
    }
}
struct CustomRoundedRectangle: Shape {
    var corners: UIRectCorner
    var radius: CGFloat
    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        return Path(path.cgPath)
    }
}

三 Image的使用誤區(qū)

Image(“face_1”) face_1必須在Assets.xcassets的圖片
如果不在Assets.xcasse里面可以使用 Image(uiImage: UIImage(named: taskItem.taskEmoIcon ?? "") ?? UIImage())
Image(<#T##String#>, bundle: <#T##Bundle?#>) 它可以嗎 bundle 又該如何設(shè)置呢???

四 Accessing StateObject's object without being installed on a View. This will create a new instance each time

在init里面更新StateObject的值,不行的 。
https://stackoverflow.com/questions/68930434/accessing-stateobjects-object-without-being-installed-on-a-view-this-will-crea

錯(cuò)誤代碼:

  @StateObject var  tabBarViewModel :DailDeilTabBarViewModel =  DailDeilTabBarViewModel()
init() {
         DaiDelPushManger.manger.didReceivePushMsg = { targetContentIdentifier in
            // 跳轉(zhuǎn)到首頁(yè)
            if tabBarViewModel.tabBarIndex != 0 {
                tabBarViewModel.tabBarIndex = 0
            }
        }
    }

五 Swiftui 處理冷啟動(dòng)

struct DailyDelightApp: App 里面init方法并不能處理冷啟動(dòng)業(yè)務(wù)。
iOS使用 @UIApplicationDelegateAdaptor 裝飾器,來(lái)處理冷啟動(dòng)的相關(guān)業(yè)務(wù)。
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate


struct DailyDelightApp: App {
    let persistenceController = PersistenceController.shared
    @StateObject var  tabBarViewModel :DailDeilTabBarViewModel =  DailDeilTabBarViewModel()
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    init() {
        //appInit()
    }
}
class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions options: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 在這里處理冷啟動(dòng)邏輯
        DebugPrint("應(yīng)用冷啟動(dòng)完成")
        return true
    }
}

6 Swiftui 類(lèi)中嵌套enum和Struct

SwiftUI 類(lèi)中確實(shí)可以嵌套枚舉。這種做法可以在類(lèi)內(nèi)部定義特定的枚舉類(lèi)型,以便專門(mén)用于該類(lèi)。這有助于組織相關(guān)的功能和數(shù)據(jù),使得代碼更加模塊化和易于維護(hù)。
萬(wàn)萬(wàn)沒(méi)想到,太high了?。。。。?/p>

class SubScribleViewModel:ObservableObject {
    enum SubScribleType {
    case Month
    case FreeYear
    }
}

7 Animation

7.1 timingCurve
在 SwiftUI 中,animation.timingCurve 是一種用于定義動(dòng)畫(huà)時(shí)序的方式,它通過(guò)貝塞爾曲線控制動(dòng)畫(huà)的速度變化。這種方法允許開(kāi)發(fā)者創(chuàng)建自定義的動(dòng)畫(huà)效果,使得動(dòng)畫(huà)過(guò)程更加生動(dòng)和自然。
timingCurve 是一種插值動(dòng)畫(huà),可以定義動(dòng)畫(huà)在不同時(shí)間點(diǎn)的速度變化。具體來(lái)說(shuō),它包含四個(gè)參數(shù),這些參數(shù)表示貝塞爾曲線控制點(diǎn)的位置:

animation(timingCurve: c1x, c1y, c2x, c2y)  
c1x 和 c1y: 第一個(gè)控制點(diǎn)的x和y坐標(biāo)。
c2x 和 c2y: 第二個(gè)控制點(diǎn)的x和y坐標(biāo)。
Each(0..<5) { index in
                Group {
                    Circle()
                        .frame(width: geometry.size.width / 5, height: geometry.size.height / 5)
                        .scaleEffect(calcScale(index: index))
                        .offset(y: calcYOffset(geometry))
                }.frame(width: geometry.size.width, height: geometry.size.height)
                    .rotationEffect(!self.isAnimating ? .degrees(0) : .degrees(360))
                    .animation(Animation
                                .timingCurve(0.5, 0.15 + Double(index) / 5, 0.25, 1, duration: 1.5)
                                .repeatForever(autoreverses: false))

常見(jiàn)的easeInOut easeIn easeOuti其實(shí)系統(tǒng)給我們通過(guò)timingCurve封裝的特殊類(lèi)型,我們只是拿過(guò)來(lái)用而已。

8 SwiftUI 可以在主線程刷新UI,而不閃退

我們知道在UIKit中在子線程刷新UI,閃退是必然的。而SwiftUI 子線程刷新 UI 時(shí)不會(huì)閃退,因?yàn)?SwiftUI 中的視圖能夠直接在后臺(tái)線程中更新。但是,必須要保證 UI 的更新是在 UI 線程(也稱為主線程)中進(jìn)行的,這是由于 UIKit 和 SwiftUI 都是設(shè)計(jì)為在主線程上操作 UI 元素,以保證響應(yīng)性和流暢度。如果在子線程中直接進(jìn)行 UI 更新,應(yīng)用程序可能會(huì)出現(xiàn)閃退或其他未知行為。
這點(diǎn)確實(shí)出乎意料啊?。。?!

 subScribleViewModel.goSubscriblePay{ message, succeed in
            DispatchQueue.main.async {
                subScribleViewModel.isShowLoading = false
                showToast(msg: message)
                if succeed {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
                        isShowSubScribleAlert = false
                    })
                }
            }
        }

9 GeometryReader

過(guò)度依賴 GeometryReader 會(huì)導(dǎo)致視圖布局變得僵化,失去了 SwiftUI 的靈活性優(yōu)勢(shì)。
GeometryReader 打破了 SwiftUI 聲明式編程的理念,使得需要直接操作視圖框架,更接近命令式編程。少用?。。?!

  // SubscribeNow
           // GeometryReader {  render in
                Text("SubscribeNow".getInternationalText(key: .SubscribeNowText))
                    .font(.system(size: 16~,weight: .medium))
                    .foregroundStyle(Color(hex: "#FFFFFFFF") ?? .black)
                    .padding(.vertical,18~)
                    .padding(.horizontal,116~)
                    .modifier(DailDelTypeCornerModifier(cornerRadius: 28~, fillColor: "#FF0A0F14"))
                    .padding(.top,subScribleViewModel.subScribleType == .Month ? 32~ : 16~)
                    .onTapGesture {
                        goSubsciblePay()
                }
            //}

用上后,布局就會(huì)混亂。

9 監(jiān)聽(tīng)app 進(jìn)入前后和后臺(tái)

.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
                   DebugPrint("進(jìn)入后臺(tái)!")
            }
            .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
                DebugPrint("進(jìn)入前臺(tái)!")
                isOpenPush(isOnReminder: true)
                // 第二次如果沒(méi)授權(quán) 就不要彈窗了
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
                    isOpenPushPresented = false
                })
            } 

10 鍵盤(pán)遮擋輸入框的解決防范

鍵盤(pán)遮擋是個(gè)非常頭疼的問(wèn)題,無(wú)論是uikit還是swifui,在swifui可以通過(guò)onReceive來(lái)監(jiān)聽(tīng)鍵盤(pán)活動(dòng):

 .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillChangeFrameNotification)) { notification in
                          
                           guard let userInfo = notification.userInfo,
                                 let keyboardEndFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
                               return
                           }
                           let keyboardHeight = keyboardEndFrame.height
                           bottomPadding = keyboardHeight
                       }
                       .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
                               bottomPadding = 0
                       }

10 error: Couldn't lookup symbols:

DailyDelight.DailDelHomePage.isCurrentDayTask.getter : Swift.Bool
Xcode 無(wú)法po SwiftUI 的裝飾器的變量
po self._someProperty而不是po self.someProperty。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容