1

In a MacOS app, I have a LazyVGrid. As we resize the window width, it adapts the layout, i.e. rearranges its items.

I would like to animate these layout changes. Afaik the recommended ways are withAnimation and .animation(Animation?, value: Equatable), but grid layout is automatic based on its container, it does not depend on a variable that I manage. For my use, .animation(Animation?) would be suitable, but it is now deprecated - it still works, though.

Shall I manage some state variable, e.g. a windowWidth (which I update on window-resize events), just for this animation? Or do you know a better way?

import SwiftUI

@main
struct MacosPlaygroundApp: App {
    let colors: [Color] = [.red, .pink, .blue, .brown, .cyan, .gray, .green, .indigo, .orange, .purple]
    let gridItem = GridItem(
        .adaptive(minimum: 100, maximum: 100),
        spacing: 10,
        alignment: .center
    )

    var body: some Scene {
        WindowGroup {
            ScrollView(.vertical, showsIndicators: false) {
                LazyVGrid(columns: [gridItem], alignment: .center, spacing: 10) {
                    ForEach(colors, id: \.self) { color in
                        color
                            .contentShape(Rectangle())
                            .cornerRadius(4)
                            .frame(width: 100, height: 100)
                    }
                }.animation(.easeIn)
            }
            .frame(minWidth: 120, maxWidth: .infinity, minHeight: 120, maxHeight: .infinity)
        }
    }
}
bzyr
  • 289
  • 1
  • 11

1 Answers1

0

You can make the columns as state in this view and calculate the values within the withAnimation block.

Like this:

@State var gridItems: [GridItem] = []

var body: some View {
        GeometryReader { proxy in
            ScrollView(.vertical) {
                LazyVGrid(columns: gridItems) {
                    itemGrid()
                }
            }.onChange(of: proxy.size) { newValue in
                if gridItems.isEmpty {
                    updateGridItems(newValue.width)
                } else {
                    withAnimation(.easeOut(duration: 0.2)) {
                        updateGridItems(newValue.width)
                    }
                }
            }.onAppear {
                if gridItems.isEmpty {
                    updateGridItems(proxy.size.width)
                }
            }
        }
    }

You can access the full example in my app in GitHub: https://github.com/JuniperPhoton/MyerTidy.Apple/blob/main/Shared/View/BatchOperationSelectView.swift#L47

JuniperPhoton
  • 736
  • 5
  • 14