簡體   English   中英

Swiftui animation 日歷日期

[英]Swiftui animation calendar dates

在我的應用程序中,我想通過從一個日期到下一個日期、到下一個日期、到下一個日期等的“日歷”過渡來顯示時間的流逝。因此,例如,如果我想顯示從18th, to 19th, to 20th, 我會顯示 18 1 秒,然后淡出,淡入 19,淡出,然后淡入 20。

我有以下顯示一個日期動畫到下一個(例如 18 > 19th):

struct Calendar: View {
    @State var date:  String

    var body: some View {
        
        VStack {
            Spacer()
        ZStack {
            
            RoundedRectangle(cornerRadius: 20)
                .stroke(Color.black, lineWidth: 2)
                .frame(width: 200, height: 200)

        RoundedRectangle(cornerRadius: 20)
            .fill(Color.red)
            .frame(width: 200, height: 200)
            .offset(y: 160)
            .clipped()
            .offset(y: -160)
            
            RoundedRectangle(cornerRadius: 20)
                    .stroke(Color.black, lineWidth: 2)
                    .frame(width: 200, height: 200)
                    .offset(y: 160)
                    .clipped()
                    .offset(y: -160)
            
Text(date).font(.system(size: 70.0))
                .offset(y: 20)
                    
           
        }
           
            Spacer()
            
            Spacer()

        }.padding()
        }
}

我在我的代碼中使用:

 ScrollView(showsIndicators: false) {
                
                VStack {
                    Spacer()
                    ZStack {
                        
                        
                        if showseconddate == false {
                            Calendar(date: "18").animation(.easeInOut(duration: 1.0))
                                .transition(.opacity)
                        }
                        if showseconddate == true {
                            Calendar(date: "19").animation(.easeInOut(duration: 1.0))
                                .transition(.opacity)
                          
                        }
                        Spacer()
                        
                    }
                    
                }.onAppear {
                    Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
                        
                        withAnimation(Animation.linear(duration: 0.5)) {
                            self.showseconddate.toggle()
                            self.showfirstdate.toggle() }
                        
                        timer.invalidate()
                        
                    }
                }
                
            }

這一切都按預期工作,但我正在努力將其擴展到我想顯示它通過多個日期轉換的情況,例如 18 > 19 > 20 > 21 等。有誰知道如何擴展它,或者使用替代解決方案? 任何解決方案都必須淡出舊日期,然后淡入新日期。 非常感謝!

這是一個相對緊湊的解決方案。 它不依賴於Bool值,而是在數組中循環:

struct ContentView: View {
    
    private var dates = ["18","19","20","21","22"]
    @State private var dateIndex = 0
    
    private let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()
    
    var body: some View{
        ScrollView(showsIndicators: false) {
            VStack {
                Spacer()
                ZStack {
                    Calendar(date: dates[dateIndex])
                        .transition(.opacity)
                        .id("date-\(dateIndex)")
                    Spacer()
                }
            }.onReceive(timer) { _ in
                var newIndex = dateIndex + 1
                if newIndex == dates.count { newIndex = 0 }
                withAnimation(.easeInOut(duration: 0.5)) {
                    dateIndex = newIndex
                }
            }
        }
    } 
}

我重新編寫了您的代碼以使動畫運行,我覺得觀看整個日歷 flash 有點煩人,所以我將其重新編寫為CalendarPage (我將 Calendar 重命名為 CalendarPage,因為 Calendar 是 Swift 中的一種類型)和CalendarView日期並將其覆蓋在頁面上。

CalendarPage 是刪除了date變量和Text()的日歷:

struct CalendarPage: View {
    
    var body: some View {
        
        VStack {
            Spacer()
            ZStack {
                RoundedRectangle(cornerRadius: 20)
                    .stroke(Color.black, lineWidth: 2)
                    .frame(width: 200, height: 200)
                
                RoundedRectangle(cornerRadius: 20)
                    .fill(Color.red)
                    .frame(width: 200, height: 200)
                    .offset(y: 160)
                    .clipped()
                    .offset(y: -160)
                
                RoundedRectangle(cornerRadius: 20)
                    .stroke(Color.black, lineWidth: 2)
                    .frame(width: 200, height: 200)
                    .offset(y: 160)
                    .clipped()
                    .offset(y: -160)
            }
            Spacer()
            
            Spacer()
        }.padding()
    }
}

CalendarView 使用計時器來增加您的日期,直到您到達endDate ,它只影響日期本身的不透明度,而不是整個日歷:

struct CalendarView: View {
    
    @State var date: Int = 0
    @State var animate = false
    @State var calendarSize: CGFloat = 20
    let endDate = 31
    
    // This keeps the font size consistent regardless of the size of the calendar
    var fontSize: CGFloat {
        calendarSize * 0.45
    }
    
    private let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()
    
    var body: some View {
        CalendarPage(date: date.description)
            .overlay(alignment: .bottom) {
                VStack {
                    Text(date.description)
                        .font(.system(size: fontSize))
                        .opacity(animate ? 1 : 0)
                }
                .frame(height: calendarSize * 0.8)
            }
        
            .frame(width: 200, height: 200)
            .readSize(onChange: { size in
                calendarSize = min(size.width, size.height)
            })
            .onReceive(timer) { _ in
                date += 1
                withAnimation(.linear(duration: 0.3)) {
                    animate = true
                }
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.75) {
                    if date != endDate {
                        withAnimation(.linear(duration: 0.2)) {
                            animate = false
                        }
                    } else {
                        timer.upstream.connect().cancel()
                    }
                }
            }
    }
}

我還使用來自FiveStars 博客View擴展使用首選項鍵來計算CalendarPage的高度(盡管我可以對其進行硬編碼)

extension View {
    func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
        background(
            GeometryReader { geometryProxy in
                Color.clear
                    .preference(key: SizePreferenceKey.self, value: geometryProxy.size)
            }
        )
            .onPreferenceChange(SizePreferenceKey.self, perform: onChange)
    }
}

fileprivate struct SizePreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero
    static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM