SwiftUI-淡出ScrollView [英] SwiftUI - fade out a ScrollView
问题描述
我有一个生成的超大图表,将其放入ScrollView中,以便用户可以向右滚动并查看所有值.我想向用户指出,还有更多的东西要来".通过将ScrollView淡出在右侧.通过应用CAGradientLayer,Swift中的操作很容易.
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.
我的方法是应用从透明(从80%开始)到系统背景颜色(从100%结束)渐变的叠加层.结果可以在所附的屏幕截图中看到.
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.
问题编号. 1:看起来不像应该看起来的那样.
Issue no. 1: Does not look like it's supposed to look.
问题编号. 2:尽管将zIndex -1应用于叠加层,但ScrollView在叠加层应用后将不再滚动.
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!
这是我的代码:
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)
}
}
推荐答案
好吧,众所周知的SwiftUI问题是,它甚至不透明地通过覆盖传递一些手势.
Ok, it is known SwiftUI issue that it does not pass some gestures via overlays even transparent.
这里是解决此问题的一种可能方法-想法是使渐变仅覆盖较小的边缘位置,因此可以直接访问滚动视图的其他部分(是的,在渐变下,它仍不可拖动,但它只是很小的一部分).
Here is possible approach to solve this - the idea is to have gradient to cover only small edge location, so other part of scroll view be accessed directly (yes, under gradient it will be still not draggable, but it is small part).
演示已准备好&在Xcode 11.7/iOS 13.7上进行了测试
Demo prepared & tested with Xcode 11.7 / iOS 13.7
(您的视图的简化变体)
(simplified variant of your view)
struct HealthExportPreview: View {
var body: some View {
GeometryReader { gp in
ZStack {
ScrollView(.horizontal) {
HStack {
// simplified content
ForEach(0..<20, id: \.self) { index in
Rectangle().fill(Color.red)
.frame(width: 40, height: 80)
}
}
.padding()
.animation(.interactiveSpring())
}
// inject gradient at right side only
Rectangle()
.fill(
LinearGradient(gradient: Gradient(stops: [
.init(color: Color(UIColor.systemBackground).opacity(0.01), location: 0),
.init(color: Color(UIColor.systemBackground), location: 1)
]), startPoint: .leading, endPoint: .trailing)
).frame(width: 0.2 * gp.size.width)
.frame(maxWidth: .infinity, alignment: .trailing)
}.fixedSize(horizontal: false, vertical: true)
}
}
}
这篇关于SwiftUI-淡出ScrollView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!