滚动视图+;NavigationView动画故障SwiftUI
我有一个简单的观点:滚动视图+;NavigationView动画故障SwiftUI,swift,animation,swiftui,scrollview,Swift,Animation,Swiftui,Scrollview,我有一个简单的观点: var主体:一些视图{ 导航视图{ 滚动视图{ VStack{ ForEach(0..这里有一个解决方法。将.padding(.top,1)添加到滚动视图中: struct ContentView: View { var body: some View { NavigationView { ScrollView { VStack {
var主体:一些视图{
导航视图{
滚动视图{
VStack{
ForEach(0..这里有一个解决方法。将.padding(.top,1)
添加到滚动视图中
:
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView {
VStack {
ForEach(0..<2) { _ in
Color.blue.frame(width: 350, height: 200)
}
}
}
.padding(.top, 1)
.navigationBarTitle("Testing", displayMode: .automatic)
}
}
}
struct ContentView:View{
var body:一些观点{
导航视图{
滚动视图{
VStack{
ForEach(0..将顶部填充设置为1会破坏至少两个主要方面:
滚动视图不在NavigationView和TabView下扩展-这使得它失去了滚动条下内容的美丽模糊效果
在滚动视图上设置背景将导致大标题导航视图停止折叠
当我不得不更改我正在使用的应用程序的所有屏幕的背景色时,我遇到了这些问题。
所以我做了更多的挖掘和实验,设法找到了一个很好的解决方案
以下是原始解决方案:
我们将滚动视图包装为两个几何体读取器
最上面的一个是关于安全区域的-我们需要这个来阅读安全区域插图
第二个是全屏
我们将滚动视图放入第二个几何体阅读器,使其大小达到全屏
然后,通过应用安全区域填充,使用VStack添加内容
最后,我们有一个滚动视图,它不会闪烁,并且在不破坏导航栏大标题的情况下接受背景
struct ContentView: View {
var body: some View {
NavigationView {
GeometryReader { geometryWithSafeArea in
GeometryReader { geometry in
ScrollView {
VStack {
Color.red.frame(width: 100, height: 100, alignment: .center)
ForEach(0..<5) { i in
Text("\(i)")
.frame(maxWidth: .infinity)
.background(Color.green)
Spacer()
}
Color.red.frame(width: 100, height: 100, alignment: .center)
}
.padding(.top, geometryWithSafeArea.safeAreaInsets.top)
.padding(.bottom, geometryWithSafeArea.safeAreaInsets.bottom)
.padding(.leading, geometryWithSafeArea.safeAreaInsets.leading)
.padding(.trailing, geometryWithSafeArea.safeAreaInsets.trailing)
}
.background(Color.yellow)
}
.edgesIgnoringSafeArea(.all)
}
.navigationBarTitle(Text("Example"))
}
}
}
例1
struct ContentView:View{
var body:一些观点{
导航视图{
滚动视图{
VStack{
颜色。红色。边框(宽度:100,高度:100,对齐:。中心)
ForEach(0..面对同样的问题,我做了一些调查。
这个小故障似乎来自scrollview反弹和滚动上下文减速的速度
目前,我通过将减速率设置为fast,成功地消除了这个小故障。它似乎让swiftui在保持反弹动画活动的同时,更好地计算布局
我的解决方法很简单,就是在视图的init中设置以下内容。缺点是这会影响滚动减速的速度
init() {
UIScrollView.appearance().decelerationRate = .fast
}
一个可能的改进是计算显示内容的大小,然后根据需要动态切换减速率。我简化了。这里是:
extension ScrollView {
private typealias PaddedContent = ModifiedContent<Content, _PaddingLayout>
func fixFlickering() -> some View {
GeometryReader { geo in
ScrollView<PaddedContent>(axes, showsIndicators: showsIndicators) {
content.padding(geo.safeAreaInsets) as! PaddedContent
}
.edgesIgnoringSafeArea(.all)
}
}
}
谢谢你发布这篇文章!我很好奇是什么思维过程让你找到了这个解决方案…@PeterFriese,我开始在scrollView上方放置一个额外的视图,认为scrollView和导航栏之间存在交互作用。这很有效。然后我缩小了视图的大小,发现它可能非常短而且仍然有效k、 因为这个视图是作为填充的,所以我决定尝试用填充替换它,并且发现它也起了作用。所以这个公式是一部分直觉,一部分尝试的东西。@PeterFriese,如果你查看编辑历史,你会看到我的第一个解决方案是使用额外的视图。在swiftui两年后,我们仍然需要这些wo,这太疯狂了rkarounds!无论如何,谢谢你!@RicoCrescenzio,是的,我同意。有时它的边缘仍然有点粗糙。Swift语言需要3到4年的时间才能成熟。谢谢你这么详细的解释,我真的很感激这应该是公认的答案。这几乎是完美的,只是它没有更新滚动指示器集ode>!遗憾的是,我想知道您是否需要UIKit来真正正确地执行此操作。不幸的是,它不能与Stack V LazyTIL的pinnedView
配合使用,关于\u PaddingLayout
-这是否有文档记录?这看起来更优雅,但也更脆弱。@Steipet我通常通过打印SwiftUI视图来找到类似的东西,然后重新编写正在加载它生成的类型。我在任何地方都没有发现它的文档。如果您感兴趣,我还发现了Xcode自动完成初始值设定项,例如,我假设它是私有的。@Steipte虽然这个解决方案是“健壮的”,但我不确定使用诸如\u PaddingLayout
之类的东西是否算作“私有API”。毕竟,这个解决方案pe通常是推断出来的。如果你像我一样有点不确定,你可以制作类似于struct ContentAcceptingScrollView{…}
的东西,它只是在主体中创建一个ScrollView
,但是内容类型是推断出来的,所以我们不需要这种类型转换。
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView {
VStack {
Color.red.frame(width: 100, height: 100, alignment: .center)
ForEach(0..<5) { i in
Text("\(i)")
.frame(maxWidth: .infinity)
.background(Color.green)
Spacer()
}
Color.red.frame(width: 100, height: 100, alignment: .center)
}
}
.fixFlickering()
.navigationBarTitle(Text("Example"))
}
}
}
init() {
UIScrollView.appearance().decelerationRate = .fast
}
extension ScrollView {
private typealias PaddedContent = ModifiedContent<Content, _PaddingLayout>
func fixFlickering() -> some View {
GeometryReader { geo in
ScrollView<PaddedContent>(axes, showsIndicators: showsIndicators) {
content.padding(geo.safeAreaInsets) as! PaddedContent
}
.edgesIgnoringSafeArea(.all)
}
}
}
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView {
/* ... */
}
.fixFlickering()
}
}
}