admin管理员组文章数量:1405194
I'm trying to create a pinned section header in a LazyVStack
in SwiftUI while also applying a unified style to the entire section. The problem is that when I apply a style to a Section
, the style gets applied separately to the header and content. I could wrap everything in a VStack
, but that breaks the pinned header behavior in LazyVStack. Is there a way to keep the pinned header behavior while ensuring the entire section is styled as a single view or do I need an alternative approach to get this layout?
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack(pinnedViews: [.sectionHeaders]) {
Section {
Text("Content")
} header: {
Text("Header")
}
.padding()
.overlay {
RoundedRectangle(cornerRadius: 12)
.stroke(.blue, lineWidth: 1)
}
}
}
}
}
I'm trying to create a pinned section header in a LazyVStack
in SwiftUI while also applying a unified style to the entire section. The problem is that when I apply a style to a Section
, the style gets applied separately to the header and content. I could wrap everything in a VStack
, but that breaks the pinned header behavior in LazyVStack. Is there a way to keep the pinned header behavior while ensuring the entire section is styled as a single view or do I need an alternative approach to get this layout?
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack(pinnedViews: [.sectionHeaders]) {
Section {
Text("Content")
} header: {
Text("Header")
}
.padding()
.overlay {
RoundedRectangle(cornerRadius: 12)
.stroke(.blue, lineWidth: 1)
}
}
}
}
}
Share
Improve this question
asked Mar 9 at 9:20
Berry BlueBerry Blue
16.6k22 gold badges77 silver badges147 bronze badges
0
1 Answer
Reset to default 1If you are aiming to add a border around the header + content, then you could try using a container for the content inside the Section
. Then:
- use
.onGeometryChange
to measure the scroll offset of the container - use another
.onGeometryChange
to measure the scroll offset of the header - apply the border as an overlay to the container
- apply negative padding to the top of the overlay shape, so that the border incorporates the header too
- the size of the negative padding is computed as the difference between the two scroll offsets.
struct ContentView: View {
@State private var headerOffset = CGFloat.zero
@State private var contentOffset = CGFloat.zero
var body: some View {
ScrollView {
LazyVStack(pinnedViews: [.sectionHeaders]) {
Section {
LazyVStack {
ForEach(1..<11) { n in
Text("Row \(n)")
}
}
.overlay {
RoundedRectangle(cornerRadius: 12)
.stroke(.blue, lineWidth: 1)
.padding(.top, min(0, headerOffset - contentOffset))
}
.onGeometryChange(for: CGFloat.self) { proxy in
proxy.frame(in: .scrollView).minY
} action: { minY in
contentOffset = minY
}
} header: {
Text("Header")
.onGeometryChange(for: CGFloat.self) { proxy in
proxy.frame(in: .scrollView).minY
} action: { minY in
headerOffset = minY
}
}
.padding()
}
}
}
}
Since .onGeometryChange
is being used twice, you might find it convenient to create a ViewModifier
to perform the work, plus a view extension to apply it:
struct ScrollOffsetReader: ViewModifier {
@Binding var offset: CGFloat
func body(content: Content) -> some View {
content
.onGeometryChange(for: CGFloat.self) { proxy in
proxy.frame(in: .scrollView).minY
} action: { minY in
offset = minY
}
}
}
extension View {
func scrollOffsetReader(offset: Binding<CGFloat>) -> some View {
modifier(ScrollOffsetReader(offset: offset))
}
}
The code now simplifies to the following:
Section {
LazyVStack {
// ...
}
.overlay {
// ...
}
.scrollOffsetReader(offset: $contentOffset)
} header: {
Text("Header")
.scrollOffsetReader(offset: $headerOffset)
}
本文标签: swiftHow to create pinned views in SwiftUIStack Overflow
版权声明:本文标题:swift - How to create pinned views in SwiftUI - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744874060a2629808.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论