问题描述
我很难让子视图正确布置,尤其是高处。我讨厌硬编码子视图的高度,但这是我唯一可以使用的方法。如果我从子视图中删除这些frame(heights)
,则这些子视图在父视图中重叠。对于没有硬编码高度的更好的架构方法,有什么建议吗?
struct SkateDetailView: View {
@EnvironmentObject var combineWorkoutManager: CombineWorkoutManager
@Environment(\.colorScheme) var colorScheme
@State var subscriptionIsActive = false
var body: some View {
ScrollView {
vstack(alignment: .leading) {
combineWorkoutManager.workout.map { SkateDetailHeaderView(workout: $0)}
combineWorkoutManager.heartRateSamplesFromWorkout.map { HeartRateRecoveryCard(heartRateSamples: $0) }
combineWorkoutManager.vo2MaxFromWorkout.map { vo2MaxCard(vo2MaxValue: $0) }
}
.padding(.top)
.background(colorScheme == .dark ? Color.black : Color.offWhite)
.onAppear {
combineWorkoutManager.loadHeartRatesFromWorkout()
combineWorkoutManager.loadVo2MaxFromWorkout()
combineWorkoutManager.getWorkout()
self.subscriptionIsActive = UserDefaults.standard.bool(forKey: subscriptionIsActiveKey)
}
//Code for conditional view modifer from: https://fivestars.blog/swiftui/conditional-modifiers.html
.if(subscriptionIsActive) { $0.redacted(reason: .placeholder)}
}
}
}
struct SkateDetailHeaderView: View {
var workout: HKWorkout
@Environment(\.colorScheme) var colorScheme
@State var sessionTypeImage = Image("Game_playerhelmet")
var body: some View {
ZStack(alignment: .leading) {
(colorScheme == .dark ? Color.black : Color.white)
.cornerRadius(10)
vstack(alignment: .leading) {
HStack() {
sessionTypeImage
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 35.0,height: 35.0)
.unredacted()
Text(WorkoutManager.ReadOutHockeyTrackerMetadata(workout: workout)?.sessionType ?? "")
.font(.custom(futuraLTPro,size: largeTitleTextSize))
.unredacted()
}
.padding(.leading)
.onAppear {
setSessionTypeImage()
}
HStack {
Text("Goals")
Text("Assists")
Text("+/-")
}
.font(.custom(futuraMedium,size: captionTextSize))
.unredacted()
}
.padding(.all)
}
.padding(.horizontal)
}
struct HeartRateRecoveryCard: View {
//Don't download HR samples for this view the parent view should download HR samples and pass them into it's children views
@State var heartRateSamples: [HKQuantitySample]
@State var HRRAnchor = 0
@State var HRRTwoMinutesLater = 0
@State var heartRateRecoveryValue = 0
@Environment(\.colorScheme) var colorScheme
var body: some View {
ZStack {
(colorScheme == .dark ? Color.black : Color.white)
.cornerRadius(10)
vstack(alignment: .leading) {
vstack(alignment: .leading) {
Text("Heart Rate Recovery")
.font(.custom(futuraLTPro,size: titleTextSize))
.unredacted()
Text("\(heartRateRecoveryValue) bpm")
.font(.custom(futuraMedium,size: titleTextSize))
.font(Font.body.monospacedDigit())
Text("\(HRRAnchor) bpm - \(HRRTwoMinutesLater) bpm")
.font(.custom(futuraMedium,size: captionTextSize))
.font(Font.body.monospacedDigit())
.foregroundColor(Color(.secondaryLabel))
}
.padding(.leading)
SwiftUILineChart(chartLabelName: "Heart Rate Recovery",entries: convertHeartRatesToLineChartDataAndSetFormatter(heartRates: heartRateSamples).0,chartLineAndGradientColor: ColorCompatibility.label,xAxisFormatter: convertHeartRatesToLineChartDataAndSetFormatter(heartRates: heartRateSamples).1,showGradient: false)
.frame(width: 350,height: 180,alignment: .center)
.cornerRadius(12)
.onAppear {
if let unwrappedHRRObject = HeartRateRecoveryManager.calculateHeartRateRecoveryForHRrgraph(heartRateSamples: heartRateSamples) {
HRRAnchor = unwrappedHRRObject.anchorHR
HRRTwoMinutesLater = unwrappedHRRObject.twoMinLaterHR
heartRateRecoveryValue = unwrappedHRRObject.hrr
print("HRR = \(heartRateRecoveryValue)")
}
}
BarScaleView(valuetoBeScaled: heartRateRecoveryValue,scaleMax: 60,numberOfBlocks: 5,colors: [logoAquaShade1Color,logoAquaShade2Color,logoAquaShade3Color,logoAquaShade4Color,logoAquaShade5Color],blockValues: [0,12,24,36,48])
}
.padding(.top)
}
.frame(height: 375)
.padding(.all)
}
struct vo2MaxCard: View {
@State var vo2MaxValue: Int
@Environment(\.colorScheme) var colorScheme
var body: some View {
ZStack {
(colorScheme == .dark ? Color.black : Color.white)
.cornerRadius(10)
vstack(alignment: .leading) {
vstack(alignment: .leading) {
Text("VO2 Max")
.font(.custom(futuraLTPro,size: titleTextSize))
.padding(.top)
.unredacted()
Text("\(vo2MaxValue) mL/(kg - min)")
.font(.custom(futuraMedium,size: titleTextSize))
.font(Font.body.monospacedDigit())
}
.padding(.leading)
BarScaleView(valuetoBeScaled: vo2MaxValue,scaleMax: 72,numberOfBlocks: 4,colors: [logoRedShade1Color,logoRedShade2Color,logoRedShade3Color,logoRedShade4Color,logoRedShade5Color],18,54])
}
}
.frame(height: 175)
.padding(.all)
}
}
struct BarScaleView: View {
var valuetoBeScaled: Int
var scaleMax: Int
var numberOfBlocks: Int
var colors: [UIColor]
var blockValues: [Int] //e.g. 0,48
var body: some View {
GeometryReader { geometry in
vstack {
HStack(spacing: 0) {
ForEach(0..<numberOfBlocks) { index in
ScaleBarBlock(numberOfBlocks: numberOfBlocks,blockColor: Color(colors[index]),proxy: geometry,blockValue: blockValues[index])
}
}
Image(systemName: "triangle.fill")
.padding(.top)
.unredacted()
// .if(subscriptionIsActive) { $0.redacted(reason: .placeholder)}
.if(valuetoBeScaled >= scaleMax) { $0.position(x: geometry.size.width - 5) }
.if(valuetoBeScaled < scaleMax) { $0.position(x: geometry.size.width * CGFloat(Double(valuetoBeScaled) / Double(scaleMax))) }
}
}
.padding()
}
}
struct SwiftUILineChart: UIViewRepresentable {
var chartLabelName: String
//Line Chart accepts data as array of BarChartDataEntry objects
var entries: [ChartDataEntry]
var chartLineAndGradientColor = logoRedShade1Color
var xAxisFormatter: ChartXAxisFormatter?
var showGradient = true
// this func is required to conform to UIViewRepresentable protocol
func makeUIView(context: Context) -> LineChartView {
//crate new chart
let chart = LineChartView()
//it is convenient to form chart data in a separate func
chart.data = addData()
chart.backgroundColor = .clear
chart.pinchZoomEnabled = false
chart.dragEnabled = false
chart.isUserInteractionEnabled = false
//If available pass xAsisFormatter to chart
if let unwrappedxAxisFormatter = xAxisFormatter {
chart.xAxis.valueFormatter = unwrappedxAxisFormatter
chart.xAxis.setLabelCount(5,force: true) //set number of labels at top of graph to avoid too many (Not using since setting granularity works)
chart.xAxis.avoidFirstLastClippingEnabled = true
chart.xAxis.labelPosition = .bottom
}
return chart
}
// this func is required to conform to UIViewRepresentable protocol
func updateUIView(_ uiView: LineChartView,context: Context) {
//when data changes chartd.data update is required
uiView.data = addData()
}
func addData() -> LineChartData {
let data = LineChartData()
//BarChartDataSet is an object that contains information about your data,styling and more
let dataSet = LineChartDataSet(entries: entries)
if showGradient == true {
let gradientColors = [chartLineAndGradientColor.cgColor,UIColor.clear.cgColor]
let colorLocations: [CGFloat] = [1.0,0.0] //positioning of gradient
let gradient = CGGradient(coloRSSpace: nil,colors: gradientColors as CFArray,locations: colorLocations)!
dataSet.fillAlpha = 1
dataSet.fill = Fill(linearGradient: gradient,angle: 90)
dataSet.drawFilledEnabled = true
}
// change bars color to green
dataSet.colors = [chartLineAndGradientColor]
dataSet.drawCirclesEnabled = false //no circles
dataSet.drawValuesEnabled = false //hide labels on the datapoints themselves
//change data label
dataSet.label = chartLabelName
data.addDataSet(dataSet)
return data
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)