I have a generated, oversized chart, which I put into a ScrollView so that the user can scroll to the right and see all values. I would like to indicate to the user that there's "more to come" on the right by fading the ScrollView out. Something in Swift was easy by applying CAGradientLayer.
My approach was to apply an overlay with a gradient from clear (starting at 80%) to system background color (ending at 100%). The result can be seen the attached screenshot.
Issue no. 1: Does not look like it's supposed to look.
Issue no. 2: Despite applying zIndex of -1 to the overlay, the ScrollView won't scroll any longer as soon as an overlay is applied.
Any idea how to achieve this? Thanks!
Here's my code:
struct HealthExportPreview: View {
@ObservedObject var carbsEntries: CarbsEntries
var body: some View {
ScrollView(.horizontal) {
HStack {
ForEach(0..<self.carbsEntries.carbsRegime.count, id: \.self) { index in
ChartBar(carbsEntries: self.carbsEntries, entry: self.carbsEntries.carbsRegime[index], requiresTimeSplitting: index == self.carbsEntries.timeSplittingAfterIndex)
}
}
.padding()
.animation(.interactiveSpring())
}
.overlay(Rectangle()
.fill(
LinearGradient(gradient: Gradient(stops: [
.init(color: .clear, location: 0.8),
.init(color: Color(UIColor.systemBackground), location: 1.0)
]), startPoint: .leading, endPoint: .trailing)
)
.zIndex(-1)
)
.frame(height: CGFloat(carbsEntries.previewHeight + 80))
.onAppear() {
self.carbsEntries.fitCarbChartBars()
}
}
}
struct ChartBar: View {
var carbsEntries: CarbsEntries
var entry: (date: Date, carbs: Double)
var requiresTimeSplitting: Bool
static var timeStyle: DateFormatter {
let formatter = DateFormatter()
formatter.timeStyle = .short
return formatter
}
var body: some View {
VStack {
Spacer()
Text(FoodItemViewModel.doubleFormatter(numberOfDigits: entry.carbs >= 100 ? 0 : (entry.carbs >= 10 ? 1 : 2)).string(from: NSNumber(value: entry.carbs))!)
.font(.footnote)
.rotationEffect(.degrees(-90))
.offset(y: self.carbsEntries.appliedMultiplier * entry.carbs <= 40 ? 0 : 40)
.zIndex(1)
if entry.carbs <= self.carbsEntries.maxCarbsWithoutSplitting {
Rectangle()
.fill(Color.green)
.frame(width: 15, height: CGFloat(self.carbsEntries.appliedMultiplier * entry.carbs))
} else {
Rectangle()
.fill(Color.green)
.frame(width: 15, height: CGFloat(self.carbsEntries.getSplitBarHeight(carbs: entry.carbs)))
.overlay(Rectangle()
.fill(Color(UIColor.systemBackground))
.frame(width: 20, height: 5)
.padding([.bottom, .top], 1.0)
.background(Color.primary)
.rotationEffect(.degrees(-10))
.offset(y: CGFloat(self.carbsEntries.getSplitBarHeight(carbs: entry.carbs) / 2 - 10))
)
}
if self.requiresTimeSplitting {
Rectangle()
.fill(Color(UIColor.systemBackground))
.frame(width: 40, height: 0)
.padding([.top], 2.0)
.background(Color.primary)
.overlay(Rectangle()
.fill(Color(UIColor.systemBackground))
.frame(width: 20, height: 5)
.padding([.bottom, .top], 1.0)
.background(Color.black)
.rotationEffect(.degrees(80))
.offset(x: 20)
.zIndex(1)
)
} else {
Rectangle()
.fill(Color(UIColor.systemBackground))
.frame(width: 40, height: 0)
.padding([.top], 2.0)
.background(Color.primary)
}
Text(ChartBar.timeStyle.string(from: entry.date))
.fixedSize()
.layoutPriority(1)
.font(.footnote)
.rotationEffect(.degrees(-90))
.offset(y: 10)
.frame(height: 50)
.lineLimit(1)
}.frame(width: 30)
}
}


