Compare commits

..

1 Commits

Author SHA1 Message Date
Simon fd8ebae3b9 better pyhsics as standard 2022-03-13 23:09:37 +01:00
7 changed files with 30 additions and 118 deletions

View File

@ -26,12 +26,9 @@ let package = Package(
// Targets can depend on other targets in this package, and on products in packages this package depends on. // Targets can depend on other targets in this package, and on products in packages this package depends on.
.target( .target(
name: "ConfettiSwiftUI", name: "ConfettiSwiftUI",
dependencies: [], dependencies: []),
path: "Sources"),
.testTarget( .testTarget(
name: "ConfettiSwiftUITests", name: "ConfettiSwiftUITests",
dependencies: ["ConfettiSwiftUI"], dependencies: ["ConfettiSwiftUI"]),
path: "Tests"),
] ]
) )

View File

@ -79,21 +79,19 @@ If you prefer not to use any of dependency managers, you can integrate `Confetti
First, add `import ConfettiSwiftUI` on every `swift` file you would like to use `ConfettiSwiftUI`. Define a integer as a state varable which is responsible for triggering the animation. Any change to that variable will span a new animation (increment and decrement). First, add `import ConfettiSwiftUI` on every `swift` file you would like to use `ConfettiSwiftUI`. Define a integer as a state varable which is responsible for triggering the animation. Any change to that variable will span a new animation (increment and decrement).
```swift ```swift
import ConfettiSwiftUI
import SwiftUI import SwiftUI
import ConfettiSwiftUI
struct ContentView: View { struct ContentView: View {
@State var counter:Int = 0
@State private var counter: Int = 0
var body: some View { var body: some View {
Button("🎉") { ZStack{
counter += 1 Text("🎉").font(.system(size: 50)).onTapGesture(){counter += 1}
ConfettiCannon(counter: $counter)
} }
.confettiCannon(counter: $counter)
} }
} }
``` ```
### Parameters ### Parameters
@ -119,9 +117,9 @@ struct ContentView: View {
You can use the configurator app in [demo project here](https://github.com/simibac/ConfettiSwiftUIDemo) to make your desired animation or get inspired by one of the many examples. You can use the configurator app in [demo project here](https://github.com/simibac/ConfettiSwiftUIDemo) to make your desired animation or get inspired by one of the many examples.
<p align="center"> <p align="center">
<img src="./Gifs/configurator.png" width="150" /> <img src="./Gifs/configurator.png" width="150" />
<img src="./Gifs/examples.png" width="150" /> <img src="./Gifs/examples.png" width="150" />
</p> </p>
### Examples ### Examples
@ -132,7 +130,7 @@ You can use the configurator app in [demo project here](https://github.com/simib
</p> </p>
```swift ```swift
.confettiCannon(counter: $counter, colors: [.red, .black], confettiSize: 20) ConfettiCannon(counter: $counter2, colors: [.red, .black], confettiSize: 20)
``` ```
#### Repeat Configuration #### Repeat Configuration
@ -142,7 +140,7 @@ You can use the configurator app in [demo project here](https://github.com/simib
</p> </p>
```swift ```swift
.confettiCannon(counter: $counter, repetitions: 3, repetitionInterval: 0.7) ConfettiCannon(counter: $counter3, repetitions: 3, repetitionInterval: 0.7)
``` ```
#### Firework Configuration #### Firework Configuration
@ -152,7 +150,7 @@ You can use the configurator app in [demo project here](https://github.com/simib
</p> </p>
```swift ```swift
.confettiCannon(counter: $counter, num: 50, openingAngle: Angle(degrees: 0), closingAngle: Angle(degrees: 360), radius: 200) ConfettiCannon(counter: $counter4, num: 50, openingAngle: Angle(degrees: 0), closingAngle: Angle(degrees: 360), radius: 200)
``` ```
#### Emoji Configuration #### Emoji Configuration
@ -162,7 +160,7 @@ You can use the configurator app in [demo project here](https://github.com/simib
</p> </p>
```swift ```swift
.confettiCannon(counter: $counter, confettis: [.text("❤️"), .text("💙"), .text("💚"), .text("🧡")]) ConfettiCannon(counter: $counter5, confettis: [.text("❤️"), .text("💙"), .text("💚"), .text("🧡")])
``` ```
#### Endless Configuration #### Endless Configuration
@ -172,7 +170,7 @@ You can use the configurator app in [demo project here](https://github.com/simib
</p> </p>
```swift ```swift
.confettiCannon(counter: $counter, num:1, confettis: [.text("💩")], confettiSize: 20, repetitions: 100, repetitionInterval: 0.1) ConfettiCannon(counter: $counter6, num:1, confettis: [.text("💩")], confettiSize: 20, repetitions: 100, repetitionInterval: 0.1)
``` ```
#### Make-it-Rain Configuration #### Make-it-Rain Configuration
@ -182,7 +180,7 @@ You can use the configurator app in [demo project here](https://github.com/simib
</p> </p>
```swift ```swift
.confettiCannon(counter: $counter, num:1, confettis: [.text("💵"), .text("💶"), .text("💷"), .text("💴")], confettiSize: 30, repetitions: 50, repetitionInterval: 0.1) ConfettiCannon(counter: $counter7, num:1, confettis: [.text("💵"), .text("💶"), .text("💷"), .text("💴")], confettiSize: 30, repetitions: 50, repetitionInterval: 0.1)
``` ```
## 👨‍💻 Contributors ## 👨‍💻 Contributors

View File

@ -19,7 +19,6 @@ public enum ConfettiType:CaseIterable, Hashable {
case shape(Shape) case shape(Shape)
case text(String) case text(String)
case sfSymbol(symbolName: String)
public var view:AnyView{ public var view:AnyView{
switch self { switch self {
@ -33,8 +32,6 @@ public enum ConfettiType:CaseIterable, Hashable {
return AnyView(RoundedCross()) return AnyView(RoundedCross())
case let .text(text): case let .text(text):
return AnyView(Text(text)) return AnyView(Text(text))
case .sfSymbol(let symbolName):
return AnyView(Image(systemName: symbolName))
default: default:
return AnyView(Circle()) return AnyView(Circle())
} }
@ -51,8 +48,8 @@ public struct ConfettiCannon: View {
@StateObject private var confettiConfig:ConfettiConfig @StateObject private var confettiConfig:ConfettiConfig
@State var animate:[Bool] = [] @State var animate:[Bool] = []
@State var finishedAnimationCounter = 0 @State var finishedAnimationCouter = 0
@State var firstAppear = false @State var firtAppear = false
@State var error = "" @State var error = ""
/// renders configurable confetti animaiton /// renders configurable confetti animaiton
@ -115,22 +112,22 @@ public struct ConfettiCannon: View {
public var body: some View { public var body: some View {
ZStack{ ZStack{
ForEach(finishedAnimationCounter..<animate.count, id:\.self){ i in ForEach(finishedAnimationCouter..<animate.count, id:\.self){ i in
ConfettiContainer( ConfettiContainer(
finishedAnimationCounter: $finishedAnimationCounter, finishedAnimationCouter: $finishedAnimationCouter,
confettiConfig: confettiConfig confettiConfig: confettiConfig
) )
} }
} }
.onAppear(){ .onAppear(){
firstAppear = true firtAppear = true
} }
.onChange(of: counter){value in .onChange(of: counter){value in
if firstAppear{ if firtAppear{
for i in 0...confettiConfig.repetitions{ for i in 0...confettiConfig.repetitions{
DispatchQueue.main.asyncAfter(deadline: .now() + confettiConfig.repetitionInterval * Double(i)) { DispatchQueue.main.asyncAfter(deadline: .now() + confettiConfig.repetitionInterval * Double(i)) {
animate.append(false) animate.append(false)
if(value > 0 && value < animate.count){ if(value < animate.count){
animate[value-1].toggle() animate[value-1].toggle()
} }
} }
@ -142,7 +139,7 @@ public struct ConfettiCannon: View {
@available(iOS 14.0, macOS 11.0, watchOS 7, tvOS 14.0, *) @available(iOS 14.0, macOS 11.0, watchOS 7, tvOS 14.0, *)
struct ConfettiContainer: View { struct ConfettiContainer: View {
@Binding var finishedAnimationCounter:Int @Binding var finishedAnimationCouter:Int
@StateObject var confettiConfig:ConfettiConfig @StateObject var confettiConfig:ConfettiConfig
@State var firstAppear = true @State var firstAppear = true
@ -155,7 +152,7 @@ struct ConfettiContainer: View {
.onAppear(){ .onAppear(){
if firstAppear{ if firstAppear{
DispatchQueue.main.asyncAfter(deadline: .now() + confettiConfig.animationDuration) { DispatchQueue.main.asyncAfter(deadline: .now() + confettiConfig.animationDuration) {
self.finishedAnimationCounter += 1 self.finishedAnimationCouter += 1
} }
firstAppear = false firstAppear = false
} }
@ -191,7 +188,7 @@ struct ConfettiView: View{
} }
func getAnimation() -> Animation { func getAnimation() -> Animation {
return Animation.timingCurve(0.1, 0.8, 0, 1, duration: getAnimationDuration()) return Animation.timingCurve(0, 1, 0, 1, duration: getAnimationDuration())
} }
func getDistance() -> CGFloat { func getDistance() -> CGFloat {
@ -199,7 +196,7 @@ struct ConfettiView: View{
} }
func getDelayBeforeRainAnimation() -> TimeInterval { func getDelayBeforeRainAnimation() -> TimeInterval {
confettiConfig.explosionAnimationDuration * 0.1 confettiConfig.explosionAnimationDuration * 0.1
} }
var body: some View{ var body: some View{
@ -282,7 +279,7 @@ class ConfettiConfig: ObservableObject {
self.radius = radius self.radius = radius
self.repetitions = repetitions self.repetitions = repetitions
self.repetitionInterval = repetitionInterval self.repetitionInterval = repetitionInterval
self.explosionAnimationDuration = Double(radius / 1300) self.explosionAnimationDuration = Double(radius / 1400)
self.rainAnimationDuration = Double((rainHeight + radius) / 200) self.rainAnimationDuration = Double((rainHeight + radius) / 200)
} }

View File

@ -1,80 +0,0 @@
//
// View+ConfettiCannon.swift
//
//
// Created by Abdullah Alhaider on 24/03/2022.
//
import SwiftUI
public extension View {
/// renders configurable confetti animaiton
///
/// - Usage:
///
/// ```
/// import SwiftUI
///
/// struct ContentView: View {
///
/// @State private var counter: Int = 0
///
/// var body: some View {
/// Button("Wow") {
/// counter += 1
/// }
/// .confettiCannon(counter: $counter)
/// }
/// }
/// ```
///
/// - Parameters:
/// - counter: on any change of this variable the animation is run
/// - num: amount of confettis
/// - colors: list of colors that is applied to the default shapes
/// - confettiSize: size that confettis and emojis are scaled to
/// - rainHeight: vertical distance that confettis pass
/// - fadesOut: reduce opacity towards the end of the animation
/// - opacity: maximum opacity that is reached during the animation
/// - openingAngle: boundary that defines the opening angle in degrees
/// - closingAngle: boundary that defines the closing angle in degrees
/// - radius: explosion radius
/// - repetitions: number of repetitions of the explosion
/// - repetitionInterval: duration between the repetitions
///
@ViewBuilder func confettiCannon(
counter: Binding<Int>,
num: Int = 20,
confettis: [ConfettiType] = ConfettiType.allCases,
colors: [Color] = [.blue, .red, .green, .yellow, .pink, .purple, .orange],
confettiSize: CGFloat = 10.0,
rainHeight: CGFloat = 600.0,
fadesOut: Bool = true,
opacity: Double = 1.0,
openingAngle: Angle = .degrees(60),
closingAngle: Angle = .degrees(120),
radius: CGFloat = 300,
repetitions: Int = 0,
repetitionInterval: Double = 1.0
) -> some View {
ZStack {
self
ConfettiCannon(
counter: counter,
num: num,
confettis: confettis,
colors: colors,
confettiSize: confettiSize,
rainHeight: rainHeight,
fadesOut: fadesOut,
opacity: opacity,
openingAngle: openingAngle,
closingAngle: closingAngle,
radius: radius,
repetitions: repetitions,
repetitionInterval: repetitionInterval
)
}
}
}