1

使用Swift5.5、iOS15.0.1、

我不得不意识到我的圆形 ProgressBar 在更新到 iOS15 后不再动画。

  1. 下面是我的代码 - 谁能告诉我该怎么做才能使圆形 ProgressBar-View 再次动画?

  2. 谁能告诉我如何在这个例子中规避弃用警告animation' was deprecated in iOS 15.0: Use withAnimation or animation(_:value:) instead.

import SwiftUI

struct ContentView: View {
    
    @State var progressValue: Float = 0.28
    
    var body: some View {
        ProgressBar(progress: $progressValue)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct ProgressBar: View {
    @Binding var progress: Float
    
    var body: some View {
        ZStack {
            Circle()
                .stroke(lineWidth: 20.0)
                .opacity(0.3)
                .foregroundColor(Color.red)
            
            Circle()
                .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                .stroke(style: StrokeStyle(lineWidth: 20.0, lineCap: .round, lineJoin: .round))
                .foregroundColor(Color.red)
                .rotationEffect(Angle(degrees: 270.0))
                .animation(.linear)
            Text(String(format: "%.0f %%", min(self.progress, 1.0)*100.0))
                .font(.largeTitle)
                .bold()
        }
    }
}

我的原始版本如下所示:

Circle()
.trim(from: 0, to: showFreespaceRing ? CGFloat(Double(freeDiskspace) / Double(totalDiskspace)) : 0)
.stroke(Color.green.opacity(0.7), style: StrokeStyle(lineWidth: 10, lineCap: .round))
.frame(width: circleDiam, height: circleDiam)
.animation(.easeIn(duration: 1))
.onAppear() {
    showFreespaceRing = true
}
4

2 回答 2

1

value参数采用一个Equatable表示动画的值。在这种情况下:progress

我也搬到.animation了外面ZStack——否则,我在动画上看到了一个有趣的抖动。

struct ContentView: View {
    
    @State var progressValue: Float = 0.28
    
    let timer = Timer.publish(every: 1.0, on: .main, in: .default).autoconnect()
    
    var body: some View {
        ProgressBar(progress: $progressValue)
            .onReceive(timer) { _ in
                progressValue += 0.1
            }
    }
}

struct ProgressBar: View {
    @Binding var progress: Float
    
    var body: some View {
        ZStack {
            Circle()
                .stroke(lineWidth: 20.0)
                .opacity(0.3)
                .foregroundColor(Color.red)
            
            Circle()
                .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                .stroke(style: StrokeStyle(lineWidth: 20.0, lineCap: .round, lineJoin: .round))
                .foregroundColor(Color.red)
                .rotationEffect(Angle(degrees: 270.0))
            Text(String(format: "%.0f %%", min(self.progress, 1.0)*100.0))
                .font(.largeTitle)
                .bold()
        }
        .animation(.linear, value: progress)
    }
}
于 2021-10-12T15:36:00.060 回答
0

我终于发现出错了:

在我的原始版本中,我有

Circle()
    .trim(from: 0, to: showFreespaceRing ? CGFloat(Double(freeDiskspace) / Double(totalDiskspace)) : 0)
    .stroke(Color.green.opacity(0.7), style: StrokeStyle(lineWidth: 10, lineCap: .round))
    .frame(width: circleDiam, height: circleDiam)
    .animation(.easeIn(duration: 1))
    .onAppear() {
        showFreespaceRing = true
    }

现在我有:

Circle()
    .trim(from: 0, to: showFreespaceRing ? 0 : CGFloat(Double(freeDiskspace) / Double(totalDiskspace)))
    .stroke(Color.green.opacity(0.7), style: StrokeStyle(lineWidth: 10, lineCap: .round))
    .frame(width: circleDiam, height: circleDiam)
    .animation(.easeIn(duration: 1), value: showFreespaceRing)
    .onAppear() {
        showFreespaceRing.toggle()
    }

有了这个,动画再次工作(有点 - 见下面的视频,还有一个问题)......

诀窍是.toggle()在方法内部使用onAppear

绝对行不通的方法是showFreespaceRing = true在方法内部onAppear()(而是showFreespaceRing.toggle()!!!!!!!

而且,当然,实现 iOS15 的新value内部animation

.animation(.easeIn(duration: 1), value: showFreespaceRing)

但是,目前的解决方案仍然存在一个烦恼:

动画不流畅!

看这个视频:

如果你仔细看,你会发现动画一点也不流畅,而是闪烁得很厉害。(即环形动画看起来仍然是灾难性的)。我怎样才能获得流畅的动画?

在此处输入图像描述

=================================================

经过1天的调查,这是我发现的:

动画中抖动的根本原因似乎是.sheet!!!

这是一个抖动的完整示例!

import SwiftUI

enum THSheetSelection: Hashable, Identifiable {
        
    case trialSheet
    
    var id: THSheetSelection { self }
}


struct ContentView: View {
    
    @State private var sheetState: THSheetSelection?
    
    var body: some View {
        Text("Hello")
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(2000)) {
                    sheetState = .trialSheet
                }
            }
            .sheet(item: $sheetState) { state in
                switch state {
                case .trialSheet:
                    SessionDiskspaceStatisticsView()
                }
            }
    }
}

struct SessionDiskspaceStatisticsView: View {
    
    @State private var neededDiskSpace: Int64 = 0
    @State private var freeDiskspace: Int64 = 0
    @State private var totalDiskspace: Int64 = 0
    
    @State private var showFreespaceRing = false
    
    let deviceIdiom = UIScreen.main.traitCollection.userInterfaceIdiom
    
    var body: some View {
        ZStack {
            VStack(alignment: .center) {
                Spacer().frame(height: 30)
                ZStack {
                    HStack {
                        Spacer().frame(width: 50)
                        ZStack{
                            Circle()
                                .trim(from: 0, to: 1)
                                .stroke(Color.gray.opacity(0.2), lineWidth: 10)
                                .frame(width: 137.5, height: 137.5)
                                
                                if neededDiskSpace < freeDiskspace {
                                    Circle()
                                        .trim(from: 0, to: showFreespaceRing ? 0 : CGFloat(Double(freeDiskspace) / Double(totalDiskspace)))
                                        .stroke(Color.green.opacity(0.7), style: StrokeStyle(lineWidth: 10, lineCap: .round))
                                        .frame(width: 137.5, height: 137.5)
                                        .animation(.easeIn(duration: 1), value: showFreespaceRing)
                                        .onAppear() {
                                            showFreespaceRing.toggle()
                                        }
                                    .rotationEffect(.init(degrees: 90))
                                } else {
                                    Text(LocalizedStringKey("NotEnoughSpaceKey"))
                                        .font(.system(size: 16))
                                        .fontWeight(.regular)
                                        .foregroundColor(Color.red)
                                        .frame(width: 137.5 - 10)
                                        .multilineTextAlignment(.center)
                                        .rotationEffect(.init(degrees: 90))
                                }
                        }
                        .rotationEffect(.init(degrees: -90))
                        Spacer()
                    }
                }
                Spacer().frame(height: 30)
            }
        }
        .onAppear {
            
            neededDiskSpace = 20000
            freeDiskspace = 130000
            totalDiskspace = 150000
        }
    }
}

关于如何在.sheet没有抖动的情况下为循环进度条设置动画的任何想法??????

于 2021-10-13T10:00:59.540 回答