admin管理员组文章数量:1301534
I have the following example view with no zIndex modifications. Currently, when selecting a grid item, it will animate to the center of the screen. However, this does not change zIndex and items will stay below others.
I tried adding ZStacks to various parts of the code, with a .zIndex() on the Rectangle, none of which worked.
The closest i got to a fix: adding .id() of the selected item to the LazyVGrid, with a .zindex conditionally setting it on the GeometryReader. While this sets hierarchy properly, each time an item is selected, the entire grid flashes and there is no animating the item from its grid position to the center.
struct SwiftUIView: View {
let colors: [Color] = [.red, .blue, .green, .yellow, .purple, .orange]
let columns = [GridItem(.flexible()), GridItem(.flexible())]
@State private var selectedItem: Int? = nil
@State private var selectedItemPosition: CGRect? = nil
var body: some View {
GeometryReader { screenGeometry in
LazyVGrid(columns: columns, spacing: 20) {
ForEach(colors.indices, id: \.self) { index in
GeometryReader { geometry in
let isSelected = selectedItem == index
Rectangle()
.fill(colors[index])
.cornerRadius(12)
.frame(width: 150, height: 200)
.shadow(radius: isSelected ? 10 : 0)
.onTapGesture {
withAnimation(.spring(response: 0.5, dampingFraction: 0.7)) {
if isSelected {
selectedItem = nil
selectedItemPosition = nil
} else {
selectedItem = index
selectedItemPosition = geometry.frame(in: .global)
}
}
}
.offset(
x: isSelected ? (screenGeometry.size.width / 2 - geometry.frame(in: .global).midX) : 0,
y: isSelected ? (screenGeometry.size.height / 2 - geometry.frame(in: .global).midY) : 0
)
}
.frame(height: 200) // Needed to ensure GeometryReader does not shrink
}
}
.padding()
}
}
}
I have the following example view with no zIndex modifications. Currently, when selecting a grid item, it will animate to the center of the screen. However, this does not change zIndex and items will stay below others.
I tried adding ZStacks to various parts of the code, with a .zIndex() on the Rectangle, none of which worked.
The closest i got to a fix: adding .id() of the selected item to the LazyVGrid, with a .zindex conditionally setting it on the GeometryReader. While this sets hierarchy properly, each time an item is selected, the entire grid flashes and there is no animating the item from its grid position to the center.
struct SwiftUIView: View {
let colors: [Color] = [.red, .blue, .green, .yellow, .purple, .orange]
let columns = [GridItem(.flexible()), GridItem(.flexible())]
@State private var selectedItem: Int? = nil
@State private var selectedItemPosition: CGRect? = nil
var body: some View {
GeometryReader { screenGeometry in
LazyVGrid(columns: columns, spacing: 20) {
ForEach(colors.indices, id: \.self) { index in
GeometryReader { geometry in
let isSelected = selectedItem == index
Rectangle()
.fill(colors[index])
.cornerRadius(12)
.frame(width: 150, height: 200)
.shadow(radius: isSelected ? 10 : 0)
.onTapGesture {
withAnimation(.spring(response: 0.5, dampingFraction: 0.7)) {
if isSelected {
selectedItem = nil
selectedItemPosition = nil
} else {
selectedItem = index
selectedItemPosition = geometry.frame(in: .global)
}
}
}
.offset(
x: isSelected ? (screenGeometry.size.width / 2 - geometry.frame(in: .global).midX) : 0,
y: isSelected ? (screenGeometry.size.height / 2 - geometry.frame(in: .global).midY) : 0
)
}
.frame(height: 200) // Needed to ensure GeometryReader does not shrink
}
}
.padding()
}
}
}
Share
edited Feb 11 at 10:11
Benzy Neez
22.1k3 gold badges14 silver badges41 bronze badges
asked Feb 11 at 5:04
Flynn Flynn
2131 silver badge8 bronze badges
0
1 Answer
Reset to default 1Changing the zIndex
of items in a LazyVGrid
does not work well, as demonstrated in this post. Changing the .id
of the items is a way to work around the issue. However, this may make it harder to animate the changes, as you have found.
An alternative way to solve is to use .matchedGeometryEffect
to position the visible items:
- The grid contains hidden placeholders for the tiles in their normal positions.
- The position of the centered item is also determined by a hidden placeholder. By showing this as a separate layer, there is no need to use a
GeometryReader
to determine the screen size, because it will be centered automatically. - The visible items are matched to the placeholders using their own index as id or, in the case of the selected item, using the id of the centered placeholder.
- By using a second state variable to hold the index of the last selected item, an item that is moving back to its grid position can be given a
zIndex
that is higher than the other items too (but lower than the currently selected item). If this is not done, an item that is returning to its grid position will travel under the tiles that follow it in the layout.
struct SwiftUIView: View {
let colors: [Color] = [.red, .blue, .green, .yellow, .purple, .orange]
let columns = [GridItem(.flexible()), GridItem(.flexible())]
let centeredItemId = -1
@State private var selectedItem: Int? = nil
@State private var lastSelectedItem: Int? = nil
@Namespace private var ns
var body: some View {
LazyVGrid(columns: columns, spacing: 20) {
// Placeholders for tiles
ForEach(0..<colors.count, id: \.self) { index in
Color.clear
.frame(width: 150, height: 200)
.matchedGeometryEffect(id: index, in: ns)
}
}
.padding()
.background {
// Placeholder for the centered item
Color.clear
.frame(width: 150, height: 200)
.matchedGeometryEffect(id: centeredItemId, in: ns)
}
.overlay {
ZStack {
// The visible items
ForEach(Array(colors.enumerated()), id: \.offset) { index, color in
let isSelected = selectedItem == index
RoundedRectangle(cornerRadius: 12)
.fill(color)
.shadow(radius: isSelected ? 10 : 0)
.zIndex(isSelected ? 2 : (lastSelectedItem == index ? 1 : 0))
.matchedGeometryEffect(id: isSelected ? centeredItemId : index, in: ns, isSource: false)
.onTapGesture {
withAnimation(.spring(response: 0.5, dampingFraction: 0.7)) {
if isSelected {
selectedItem = nil
} else {
selectedItem = index
}
} completion: {
lastSelectedItem = selectedItem
}
}
}
}
}
}
}
本文标签: iosCant change zIndex of LazyVGrid element to bring it to the front with animationStack Overflow
版权声明:本文标题:ios - Cant change zIndex of LazyVGrid element to bring it to the front with animation - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741677832a2391988.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论