Closed jeffgrann closed 3 years ago
Hi @jeffgrann thanks for trying out Liquid!
Line 20 of Sources/Liquid/PrivateViews/LiquidCircleView.swift
establishes a Combine trigger from a repeating timer on the main run loop that regularly animates the view.
The problem you describe is not expected behavior. Can you share a snippet of your code that replicates the problem?
Hi @maustinstar thanks for creating Liquid!
After some investigation, it looks like this only happens when Liquid is within a TabView. I'm not sure if the PageTabViewStyle is necessary to cause the issue since I haven't tried it without it. When I run the following code in a simulator or an actual device, Liquid on the first page animates for a few seconds and then freezes. The same thing happens after moving to other pages too, but not always. In the supplied video, it happened on every page. I'm using Xcode 12.2 (12B45b).
struct ContentView: View {
var body: some View {
TabView {
Liquid(samples: 6, period: 6)
.frame(width: 250, height: 175)
.foregroundColor(Color.blue)
Liquid(samples: 6, period: 6)
.frame(width: 250, height: 175)
.foregroundColor(Color.red)
Liquid(samples: 6, period: 6)
.frame(width: 250, height: 175)
.foregroundColor(Color.yellow)
}
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
https://user-images.githubusercontent.com/2565267/103177662-65585680-484a-11eb-8021-fb4630600613.mp4
Any movement on this one?
I had the same experience.
Animation stops because onDisappear
is called when the View in TabView is displayed.
In iOS 14.4 and earlier, onAppear
and onDisappear
are called multiple times when viewing a View in TabView.
In iOS 14.5, onAppear
and onDisappear
are now called only once.
So by changing LiquidCircleView.swift
as follows, I confirmed that the animation can be resumed even when switching tabs. (IOS 14.5 only)
//
// LiquidCircleView.swift
//
//
// Created by Michael Verges on 8/17/20.
//
import SwiftUI
import Combine
struct LiquidCircleView: View {
@State var samples: Int
@State var radians: AnimatableArray
@State var trigger: Timer.TimerPublisher?
@State var cancellable: Cancellable?
let period: TimeInterval
init(samples: Int, period: TimeInterval) {
self._samples = .init(initialValue: samples)
self._radians = .init(initialValue: AnimatableArray(LiquidCircleView.generateRadial(samples)))
self.period = period
startTimer()
}
var body: some View {
LiquidCircle(radians: radians)
.animation(.linear(duration: period))
.onAppear {
self.radians = AnimatableArray(LiquidCircleView.generateRadial(self.samples))
self.startTimer()
}
.onDisappear {
self.stopTimer()
}
}
static func generateRadial(_ count: Int = 6) -> [Double] {
var radians: [Double] = []
let offset = Double.random(in: 0...(.pi / Double(count)))
for i in 0..<count {
let min = Double(i) / Double(count) * 2 * .pi
let max = Double(i + 1) / Double(count) * 2 * .pi
radians.append(Double.random(in: min...max) + offset)
}
return radians
}
private func startTimer() {
guard self.cancellable == nil else {
return
}
self.cancellable = Timer.publish(every: period, on: .main, in: .common)
.autoconnect()
.sink { _ in
self.radians = AnimatableArray(LiquidCircleView.generateRadial(self.samples))
}
}
private func stopTimer() {
self.cancellable?.cancel()
self.cancellable = nil
}
}
That's awesome @daisuke-t-jp! Thank you for the investigation here. Would you like to open a pull request for this? If not, I can paste it in myself.
Fixed in #5 please close
Could you release a 0.0.2 with this fix?
@jeffgrann tagged a new release
Thanks. 😊
The animation only lasts for a few seconds. Is there a way to keep it going?