Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConditionalEffect doesn't stop immediately when condition becomes false #65

Open
davidpasztor opened this issue May 16, 2024 · 2 comments

Comments

@davidpasztor
Copy link

I want to mimic the edit mode of the iOS Home Screen, where cells wiggle while in edit mode and stop wiggling as soon as the user exits edit mode.

I've tried using .conditionalEffect(.repeat(.wiggle, every: .seconds(0.1)), condition: shouldWiggle), but when the condition becomes false, the effect doesn't stop immediately.

Here's a minimum, reproducible example showcasing the issue:

import Pow
import SwiftUI

struct WiggleTester: View {
  @State private var shouldWiggle: Bool = false
  let cellModels: [String]

  init() {
    self.init(
      cellModels: (1...10).map(\.description)
    )
  }

  init(cellModels: [String]) {
    self.cellModels = cellModels
  }

  var body: some View {
    VStack {
      grid
        .frame(maxWidth: .infinity, maxHeight: .infinity)
      Button(
        action: { shouldWiggle.toggle() },
        label: { Text("Turn Wiggle \(shouldWiggle ? "OFF" : "ON")") }
      )
    }
  }

  @ViewBuilder
  private var grid: some View {
    let columns = [
      // Using adaptive columns with a min size to allow the system to fit the appropriate number
      // of columns on the screen.
      GridItem(.adaptive(minimum: 85), spacing: 8)
    ]
    LazyVGrid(columns: columns) {
      ForEach(cellModels, id: \.self) { cellModel in
        cell(model: cellModel)
          .conditionalEffect(
            .repeat(.wiggle, every: .seconds(0.1)),
            condition: shouldWiggle
          )
      }
    }
  }

  private func cell(model: String) -> some View {
    Button(
      action: {
        print("Button tapped \(model)")
      }, label: {
        VStack {
          Text(model)
            .padding()
            .foregroundStyle(Color.primary)
            .background { Color.secondary }
            .clipShape(Circle())
          Text(model)
        }
      }
    )
  }
}

Screen recording of the problem:
wiggle issue

@mergesort
Copy link
Collaborator

Hey @davidpasztor, I took a look at the code and the way that the wiggle animation works is that it creates a TimelineView to run a simulation of a 3D transform that moves the icon left and right. I haven't quite deciphered how to achieve the effect you're looking for, especially because it appears that using a conditionalEffect adds even more wiggles like this.

if isConditionalEffect {
    wiggleCount += 4
}

I may take a look at this in the future but don't have it on my immediate radar. That said, if you would like to contribute I will gladly accept pull requests that create a new parameter that can stop the shaking on demand, I can imagine that it would be useful to others not just yourself!

Sorry I don't have a better answer, I'm still getting familiar with the library well enough to make changes to the physics portion, beyond just maintaining the APIs.

@davidpasztor
Copy link
Author

davidpasztor commented May 28, 2024

@mergesort thanks for the update, that is valuable information!

I'll see if I can find a way to fix the issue myself, but I'm not that familiar with the physics involved of such effect, so not sure if I'll succeed in a reasonable timeframe.

that create a new parameter that can stop the shaking on demand

The thing that confused me was that the conditionalEffect takes a condition Bool - I'd expect this to take effect immediately, not to let any in-progress effects run their course. Do you think that the docs should be updated to reflect this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants