SwiftUI:如何为 ScrollView 制作可拉伸(灵活)的粘性标题?

问题描述 投票:0回答:3

好吧,老实说,我做到了,因为我需要它,然后环顾四周,没有在 SwiftUI 中找到任何原生的东西,所以想分享。因此,这只是一个自我回答的问题。

最初,我需要粘性可拉伸粘性标题,用于仅依赖于

ScrollView
的惰性内容。

后来(在我得到解决方案后)我在 Medium 上发现了这个,但我不喜欢它(并且至少不会推荐原样),因为:

    过于复杂(许多不需要的代码,许多不需要的计算)
  1. 仅依赖(并加入)安全区域,因此适用性有限
  2. 基于
  3. offset
    (我不喜欢使用offset,因为它与布局不一致等)
  4. 它不具有粘性,要使其具有粘性,需要更多代码
所以,实际上所有这些文本只是为了满足这样的问题要求 - 谁认识我就知道我不喜欢输入很多文本,最好输入代码😀,简而言之 - 我的方法可能在下面的答案中有人发现它很有用。

SwiftUI 免费为我们提供的初始代码

ScrollView { LazyVStack(spacing: 8, pinnedViews: [.sectionHeaders]) { Section { ForEach(0...100) { Text("Item \($0)") .frame(maxWidth: .infinity, minHeight: 60) } } header: { Image("picture").resizable().scaledToFill() .frame(height: 200) } } }
标题向上滚动时会粘住,但向下滚动(随内容拖动)时不会粘住,并且不可拉伸。

ios swift swiftui scrollview
3个回答
4
投票
iOS 15.5(初始)

好的,我们需要解决两个问题:


    向下拖动时将标题顶部固定到
  1. ScrollView
     的顶部

  2. 向下拖动时拉伸标题以使标题内容(大多数情况下为图像)缩放以填充
解决此问题的可能方法:

  1. ScrollView
     现在可以私下管理内容偏移量(UIKit 变体不在此处的主题范围内),因此可以使用覆盖层固定到顶部
ScrollView { // ... } .overlay( // >> any header Image("picture").resizable().scaledToFill() // << header end .frame(height: imageHeight) // will calculate below .clipped()

  1. 使用

    Section

    默认标题(作为占位符)来计算距
    ScrollView
    顶部
    的当前距离

    Section(...) { // ... } header: { // here is only caculable part GeometryReader { // detect current position of header bottom edge Color.clear.preference(key: ViewOffsetKey.self, value: $0.frame(in: .named("area")).maxY) } .frame(height: headerHeight) .onPreferenceChange(ViewOffsetKey.self) { // prevent image negative height if header is not pinned // for simplicity (can be optional, etc.) imageHeight = $0 < 0 ? 0.001 : $0 } }
    
    
实际上就是这样,其他一切都只是演示部分。

使用 Xcode 13.4 / iOS 15.5 进行测试

测试模块在这里


-1
投票

如果您需要基于

ScrollView的解决方案:

1/找到

scrollOffset(参见示例或使用ScrollViewWithScrollOffset

2/ 使用

GeometryReader 包裹图像,以避免帧故障并在设备屏幕上获得正常的图像大小

3/使用GeometryReader中的尺寸和scrollOffset来设置图像框架

完整代码:

struct ContentView: View { @State var scrollOffset: CGFloat = 0 private let coordinateSpaceName = "scrollViewSpaceName" var body: some View { ScrollView { VStack { image Color.gray.frame(height: 1000) } .background( // 1. find scrollOffset GeometryReader { proxy in let offset = proxy.frame(in: .named(coordinateSpaceName)).minY Color.clear.preference(key: ScrollViewWithPullDownOffsetPreferenceKey.self, value: offset) } ) } .coordinateSpace(name: coordinateSpaceName) .onPreferenceChange(ScrollViewWithPullDownOffsetPreferenceKey.self) { value in scrollOffset = value } } var image: some View { frame GeometryReader { proxy in // 2. get actual size on screen Image(systemName: "heart.fill") // 3. use scrollOffset to adjust image .resizable() .aspectRatio(contentMode: .fit) .padding(.horizontal, min(0, -scrollOffset)) .frame(width: proxy.size.width, height: proxy.size.height + max(0, scrollOffset)) .offset(CGSize(width: 0, height: min(0, -scrollOffset))) } .aspectRatio(CGSize(width: 375, height: 280), contentMode: .fit) } }
    

-1
投票
感谢精彩的 Swift 内容。

我很乐意考虑为您提供一份高薪的基于项目的工作,但我不确定如何联系您。

    Apple 设计奖竞争应用程序。
  • 仅限iPad。
  • PencilKit 很重。
  • 大量的艺术指导自由。

随时给我留言:

  • [电子邮件受保护]
  • https://www.linkedin.com/in/damse/
  • WhatsApp:+66 63 343 6346
© www.soinside.com 2019 - 2024. All rights reserved.