【问题标题】:SwiftUI Strange Animation Transitioning via NavigationLink to a new View?SwiftUI 奇怪的动画通过 NavigationLink 过渡到新视图?
【发布时间】:2021-11-21 20:48:44
【问题描述】:

InsightsHomeView 列表中的任何项目转换到InsightsCard 时,我遇到了奇怪的动画行为。知道什么可能导致此问题或如何解决?

//从此视图导航:

struct InsightsHomeView: View {

    var body: some View {
        NavigationView {
            VStack {
                if historicalDataManager.arrayOfCareerMaxSpeedValuesAsCustomHistoricalSample.count > 0 {
                    List {
                        Section(header: Text("Speed & Distance")) {
                            NavigationLink(destination: InsightsCard(insightChartDataObject: InsightChartDataObject(insightChartType: .maxSpeed, customHistoricalSamples: historicalDataManager.arrayOfCareerMaxSpeedValuesAsCustomHistoricalSample, insightChartDataName: "Max Speed", insightChartColor: colorScheme == .dark ? Color(logoAquaShade5Color) : Color(logoBlueColor)))) {
                                //Label("Max Speed", systemImage: "speedometer")
                                 //Label("Max Speed", image: "maxSpeedV3iPhoneGrey")
                                 InsightsLabel(metricName: "Max Speed", imageName: "MaxSpeediPhoneV3")
                            }
                             NavigationLink(destination: InsightsCard(insightChartDataObject: InsightChartDataObject(insightChartType: .averageBurst, customHistoricalSamples: historicalDataManager.arrayOfCareerAverageSpeedBurstValuesAsCustomHistoricalSample, insightChartDataName: "Average Burst", insightChartColor: colorScheme == .dark ? Color(logoAquaShade5Color) : Color(logoBlueColor)))) {
                                //Label("Average Burst", systemImage: "bolt")
                                InsightsLabel(metricName: "Average Burst", imageName: "AverageBurst_skate")
                                
                            }
                             NavigationLink(destination: InsightsCard(insightChartDataObject: InsightChartDataObject(insightChartType: .distanceSkated, customHistoricalSamples: historicalDataManager.arrayOfCareerDistanceSkatedValuesAsCustomHistoricalSample, insightChartDataName: "Distance Skated", insightChartColor: colorScheme == .dark ? Color(logoAquaShade5Color) : Color(logoBlueColor), ignoreZero: true))) {
                               // Label("Distance Skated", systemImage: "arrow.right")
                                InsightsLabel(metricName: "Distance Skated", imageName: "DistanceSkatediPhoneV3")
                               
                            }
                            
                        }
                        
                    } //end of list
                    
                } else {
                     HStack {
                            Spacer()
                            VStack {
                            Text("Loading Trends Data...")
                                if #available(iOS 15.0, *) {
                                    ProgressView()
                                        .tint(Color(logoBlueColor))
                                        .scaleEffect(1.5)
                                } else {
                                    ProgressView()
                                 
                                        .scaleEffect(1.5)
                                }
                                }
                            Spacer()
                        }
                        .frame(height: 225)
                }
            }
            .navigationTitle("Browse")
            .listStyle(InsetGroupedListStyle())
            .listRowBackground(colorScheme == .dark ?  Color(.secondarySystemBackground) : Color(.systemBackground))
    
            
            
        }
        .background(Color(colorScheme == .dark ?  .black : .secondarySystemBackground))
    }
   
}


struct InsightsLabel: View {

    var metricName: String
    var imageName: String
    
     @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Label {
            Text(metricName)
                .font(.custom(futuraMedium, size: headlineTextSize))
        } icon: {
            Image(imageName)
            .resizable()
             .scaledToFit()
             .foregroundColor(colorScheme == .dark ? .white : Color(logoBlueColor))
            //.frame(width: 15, height: 15)
        }
    }
}

//到这个视图:

struct InsightsCard: View {
    
    var insightChartDataObject: InsightChartDataObject
    
    @State var filterdInsightChartDataObject: InsightChartDataObject?
    
     static let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .none
        return formatter
    }()
    
    var body: some View {
        ScrollView {
            VStack(alignment: .leading) {
                ZStack {
                    (colorScheme == .dark ?  Color(.secondarySystemBackground) : Color(.systemBackground)) //card background color
                        .cornerRadius(10)
                    VStack {
                        HStack {
                            VStack(alignment: .leading) {
                                Text(insightChartDataObject.insightChartDataName)
                                    .font(.custom(futuraLTPro, size: titleTextSize))
                                    .padding(.bottom)
                                    .unredacted()
                                    .opacity(subscriptionIsActive ? 1 : 0.15)
                                HStack {
                                    VStack {
                                        LargeBasicMetricView(metric: "Max", metricValueAsString: formatDataForLargeBasicMetricView(metricViewType: .max), hasUnitValue: true, unitString: getSuffixForLargeBasicMetricView())
                                    }
                                    .padding(.trailing)
                                    LargeBasicMetricView(metric: "Last", metricValueAsString: formatDataForLargeBasicMetricView(metricViewType: .last), hasUnitValue: true, unitString: getSuffixForLargeBasicMetricView())
                                }
                            }
                            Spacer()
                        }
                        SwiftUIModularTrendChart(insightChartDataObject: filterdInsightChartDataObject ?? insightChartDataObject)
                         .opacity(subscriptionIsActive ? 1 : 0.25)
                        switch insightChartDataObject.insightChartType {
                        case .heartRateRecovery:
                            BarScaleViewInt(valueToBeScaled: 0, scaleMax: 60, numberOfBlocks: 5, colors: [UIColor(Color.red).withAlphaComponent(0.5), UIColor(Color.red).withAlphaComponent(0.6), UIColor(Color.red).withAlphaComponent(0.75), UIColor(Color.red).withAlphaComponent(0.9), UIColor(Color.red)], blockValues: [0, 12, 24, 36, 48], blockNames: ["poor", "average", "good", "excellent", "superior"], lastBlockValue: 60)
                                .padding(.bottom)
                        case .hockeyFitnessLevel:
                              BarScaleViewInt(valueToBeScaled: 0, scaleMax: 300, numberOfBlocks: 4, colors: [orangeShade2Color, orangeShade3Color, orangeShade4Color, orangeShade5Color], blockValues: [0, 75, 150, 225], blockNames: ["poor", "average", "good", "McDavid"], lastBlockValue: 300)
                                .padding(.bottom)
                        case .skateEfficiency:
                            BarScaleViewDouble(valueToBeScaled: 0, scaleMax: 2.0, numberOfBlocks: 4, colors: [orangeShade2Color, orangeShade3Color, orangeShade4Color, orangeShade5Color], blockValues: [0, 0.5, 1.0, 1.5], blockNames: ["poor", "average", "good", "McDavid"], lastBlockValue: 2.0, decimalPlaces: 1)
                                .padding(.bottom)
                        case .vo2Max:
                            BarScaleViewInt(valueToBeScaled: 0, scaleMax: 72, numberOfBlocks: 4, colors: [logoRedShade1Color, logoRedShade2Color, logoRedShade3Color, logoRedShade4Color], blockValues: [0, 18, 36, 54], blockNames: ["poor", "average", "good", "excellent"], lastBlockValue: 72)
                                .padding(.bottom)
                        default: EmptyView()
                        }
                        switch insightChartDataObject.insightChartType {
                        case .heartRateRecovery:
                            Text("Heart rate recovery, or HRR, is a measurement of how quickly your pulse returns to its resting rate after intense exercise. This is one of the best indicators of your cardio fitness.  After performing strenuous exercise for a given period of time, HRR is calculated by taking your peak heart rate during the exercise, and then subtracting your recovered heart rate 1 or 2 minutes later.  So for example if your heart rate during exercise is 180 BPM, and 2 minutes after you stop your heart rate is 110 BPM, your HRR would be 70.   The higher the HRR the better.")
                                .fixedSize(horizontal: false, vertical: true) //this prevents this text from being truncated
                                .padding()
                        case .hockeyFitnessLevel:
                            Text("Hockey Fitness Level® is a ratio using your weight, max speed, and heart rate (at the time of your max speed) that gives an indication of your fitness level.  The faster you can skate at a lower heart rate, the higher your Hockey Fitness Level and vice versa.")
                                .fixedSize(horizontal: false, vertical: true) //this prevents this text from being truncated
                                .padding()
                        case .skateEfficiency:
                            Text("Skating Efficiency® is a measure of how aerobically efficiently you skate based on your speed and heart rate.  HockeyTracker calculates SE based on your top skating speeds and your heart rates during the times the speed samples were measured.")
                                .fixedSize(horizontal: false, vertical: true) //this prevents this text from being truncated
                                .padding()
                        case .vo2Max:
                            Text("VO2 Max is the measurement of the maximum amount of oxygen that an individual can utilize during intense, or maximal exercise. It is measured as milliliters of oxygen used in one minute per kilogram of body weight.  HockeyTracker estimates your VO2 max based on your heart rate during hockey and your resting heart rate which is queried from the Health App.")
                                .fixedSize(horizontal: false, vertical: true) //this prevents this text from being truncated
                                .padding()
                        case .effortLevel:
                            Text("Effort Level uses heart rate data to measure how much cardiovascular work a player puts forth during a session.  To determine an Effort Level score, we look at the cumulative time spent in each of the 5 heart rate zones.  Each zone is progressively weighted higher.  These zones are customized to each player based on the last 5 workouts.  This customization allows two players to compare effort even though they may have different heart rate maxes. Your personalized zones are shown underneath the Effort Level pie chart.  So for example if your personalized max heart rate zone is 183 bpm - 210 bpm, if you log a lot of time in this zone, your Effort Level score is going to rank higher.  Alternatively, if you have a relatively easy skate and the bulk of your heart rate samples are in the lowest zone, your Effort Level score will rank lower.")
                                .fixedSize(horizontal: false, vertical: true) //this prevents this text from being truncated
                                .padding()
                            
                        default: EmptyView()
                        }
                    }
                    .padding([.vertical, .leading])
                    if !subscriptionIsActive {
               
                        Button(action: {
                            pushToSubscribeVC()
                        }) {
                       
                        CardLockButtonView(goProText: "Unlock Historical Charts and Personal Records with HockeyTracker Pro", buttonHeight: 120, showIcon: true)
                        .padding(.horizontal)
                        }
                        
                    }
                }
                .padding(.horizontal)
                
            } //end of Master VStack
             .if(!subscriptionIsActive) { $0.redacted(reason: .placeholder) }
            .navigationBarItems(trailing:
                                    Button(action: {
               
            }) {
                Menu("Filter") {
                     ForEach(allSessionTypes, id: \.self) { sessionType in
                      Button(sessionType, action: {
                          filterdInsightChartDataObject = InsightChartDataObject(insightChartType: insightChartDataObject.insightChartType, customHistoricalSamples: insightChartDataObject.customHistoricalSamples.filter { $0.sessionType?.rawValue ?? "Game" == sessionType }, insightChartDataName: insightChartDataObject.insightChartDataName, insightChartColor: insightChartDataObject.insightChartColor)
                      
                      })
                     }
                

                }
            }
            )
  
            .background(Color(colorScheme == .dark ?  .black : .secondarySystemBackground))  //background color
        } //endOfScrollView
         
       
    }
    
    
    
    
}

【问题讨论】:

  • 这是 NavigationView 的 bug!你的代码太小了,难以阅读!你在某些地方使用动画吗?或者您是在子视图或父视图中开始关于颜色或位置的动画吗?我需要知道与动画相关的位置和内容以及如何被解雇。
  • @swiftPunk 谢谢,对不起,我试图删除它的一部分,以便您可以看到我正在做的一切,以防万一导致这种行为意外。我没有在任何地方使用任何动画,这就是为什么它如此奇怪? ????‍♂️
  • 如果您从代码中删除更多好的部分,您可以验证这不会导致问题,这将非常有帮助。此外,当您不小心删除了 bad 位时,您可能会知道是哪个位导致了这种行为;)
  • 那么这个问题是因为 NavigationLink 触发了 NavigationView 错误!首先尝试这个测试,从链接中删除图像并运行项目并告诉我会发生什么。
  • @swiftPunk 我尝试在 NavigationLink 中嵌入一个 Text() (无图像),结果相同。我清理了一些代码,还添加了我未能包含的InsightsLabel 的代码。 ???仍然不知道可能是什么原因?

标签: ios swift swiftui swiftui-navigationview swiftui-animation


【解决方案1】:

您必须将您的第二个视图包含在 NavigationView 中,这应该可以解决问题。如果您没有用内容填充屏幕并使用 Spacer 将项目移动到 VStack 的顶部,还有一个次要问题。

这有点小技巧,但如果你在底部放置一个空的scrollview 可以解决次要问题

【讨论】:

  • 一个好的答案将始终包括解释为什么这会解决问题,以便 OP 和任何未来的读者可以从中学习。
  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-22
  • 1970-01-01
  • 1970-01-01
  • 2020-03-25
相关资源
最近更新 更多