Coder Social home page Coder Social logo

cypherpoet / animatablegradients Goto Github PK

View Code? Open in Web Editor NEW
87.0 3.0 6.0 58.65 MB

A collection of SwiftUI View Modifiers for creating animated color gradients.

License: MIT License

Swift 100.00%
swift swift-package swift-package-manager swift-library swift-animation swiftui swiftui-animations animation-is-magic gradients more-gradients-more-life

animatablegradients's Introduction

SwiftUI Animatable Gradients

A collection of SwiftUI View Modifiers for creating animated color gradients.

CI Status Twitter: @cypher_poet

Features

  • Linear Gradients
  • Radial Gradients
  • Angular Gradients
  • Direct ViewModifier Usage on Shapes
  • Direct ViewModifier Usage on Views -- when a custom Shape is defined.
  • Interpolate between as many start and end colors as you want.

Requirements

  • iOS 13.0+
  • iPadOS 13.0+
  • tvOS 13.0+
  • Xcode 11.3+ (for developing)

Installation

AnimatableGradients can be used through the Swift Package Manager. You can add it as a dependency in your Package.swift file:

let package = Package(
    //...
    dependencies: [
        .package(url: "https://github.com/CypherPoet/AnimatableGradients", from: "0.1.1"),
    ],
    //...
)

Then simply import AnimatableGradients wherever you’d like to use it.

Usage

The view modifiers exposed by AnimatableGradients all conform to its AnimatableGradientModifier protocol. (You can view the implementation here.)

AnimatableGradientModifier Protocol
protocol AnimatableGradientModifier: AnimatableModifier {
    associatedtype BaseShape: Shape
    associatedtype GradientShapeStyle: ShapeStyle

    var baseShape: BaseShape { get }
    var startColors: [UIColor] { get }
    var endColors: [UIColor] { get }

    var completionPercentage: CGFloat { get set }

    func gradientFill(in geometry: GeometryProxy) -> GradientShapeStyle
}

To use these modifiers, AnimatableGradients provides the following extensions on Views and Shapes:

  • animatableLinearGradient
  • animatableRadialGradient
  • animatableAngularGradient

(More detailed explanations of each can be found below.)

πŸ”‘ In order to achieve animation, your containing views will need to provide the aforementioned modifiers with a bound CGFloat state value that ranges between 0.0 and 1.0.

@State private var animationCompletion: CGFloat = 0.0

This is the "animation completion" percentage that each AnimatableGradientModifier will use to generate interpolated color values during each rendered frame.

Additionally, the same containing views will need to animate the change of the animation completion. A common pattern consists of animating the value repeatedly from the containing view's onAppear modifier to create a continuous animation effect:

.onAppear {
    withAnimation(
        Animation.easeInOut(duration: 1.0).repeatForever(autoreverses: true)
    ) {
        self.animationCompletion = 1.0
    }
}

Taken together, a minimal functional example could look like this:

struct ContentView {
    @State private var animationCompletion: CGFloat = 0.0

    var body: some View {
        RoundedRectangle(cornerRadius: 24)
            .animatableLinearGradient(
                startColors: [.red, .blue],
                endColors: [.green, .yellow],
                completionPercentage: animationCompletion
            )
            .onAppear {
                withAnimation(
                    Animation.easeInOut(duration: 1.0).repeatForever(autoreverses: true)
                ) {
                    self.animationCompletion = 1.0
                }
            }
    }
}

But now for some more detail...

Animatable Linear Gradients

Usage on Shapes

extension Shape {

    public func animatableLinearGradient (
        startColors: [UIColor],
        endColors: [UIColor],
        startPoint: UnitPoint = .topLeading,
        endPoint: UnitPoint = .bottomTrailing,
        completionPercentage: CGFloat
    ) -> some View {
      ...
    }
}
What you're using πŸ‘†

RoundedRectangle(cornerRadius: 24)
    .animatableLinearGradient(
        startColors: [.systemPurple, .systemBlue, .systemGreen, .white],
        endColors: [.systemGray, .systemPink, .systemOrange, .systemRed],
        completionPercentage: animationCompletion
    )
How you might use it πŸ‘†

Usage on Views

extension View {

    public func animatableLinearGradient<BaseShape: Shape>(
        baseShape: BaseShape,
        startColors: [UIColor],
        endColors: [UIColor],
        startPoint: UnitPoint = .topLeading,
        endPoint: UnitPoint = .bottomTrailing,
        completionPercentage: CGFloat
    ) -> some View {
      ...
    }
}
What you're using πŸ‘†

Color.clear
    .animatableLinearGradient(
            baseShape: RoundedRectangle(cornerRadius: 24),
            startColors: [.systemPurple, .systemBlue, .systemGreen, .white],
            endColors: [.systemGray, .systemPink, .systemOrange, .systemRed],
            completionPercentage: animationCompletion
    )
How you might use it πŸ‘†

πŸ“Έ Example

Animatable Radial Gradients

Usage on Shapes

extension Shape {

   public func animatableRadialGradient (
        startColors: [UIColor],
        endColors: [UIColor],
        centerPoint: UnitPoint = .center,
        startRadius: CGFloat? = nil,
        endRadius: CGFloat? = nil,
        completionPercentage: CGFloat
    ) -> some View {
        ...
    }
}
What you're using πŸ‘†

RoundedRectangle(cornerRadius: 24)
    .animatableRadialGradient(
        startColors: [.systemPurple, .systemBlue, .systemGreen, .white],
        endColors: [.systemGray, .systemPink, .systemOrange, .black],
        completionPercentage: animationCompletion
    )
How you might use it πŸ‘†

Usage on Views

extension View {

    public func animatableRadialGradient<BaseShape: Shape>(
        baseShape: BaseShape,
        startColors: [UIColor],
        endColors: [UIColor],
        centerPoint: UnitPoint = .center,
        startRadius: CGFloat? = nil,
        endRadius: CGFloat? = nil,
        completionPercentage: CGFloat
    ) -> some View {
        ...
    }
}
What you're using πŸ‘†

Color.clear
    .animatableRadialGradient(
        baseShape: RoundedRectangle(cornerRadius: 24),
        startColors: [.systemPurple, .systemBlue, .systemGreen, .white],
        endColors: [.systemGray, .systemPink, .systemOrange, .black],
        completionPercentage: animationCompletion
    )
How you might use it πŸ‘†

πŸ“Έ Example

Animatable Angular Gradients

Usage on Shapes

extension Shape {

    /// - Parameters:
    ///   - fullSpanStartAngle: Setting this property will cause the gradient to being at
    ///         the specified offset, and then span the entire circumference. (Default: `nil`)
    public func animatableAngularGradient (
        startColors: [UIColor],
        endColors: [UIColor],
        centerPoint: UnitPoint = .center,
        fullSpanStartAngle: Angle,
        completionPercentage: CGFloat
    ) -> some View {
        ...
    }


    public func animatableAngularGradient (
        startColors: [UIColor],
        endColors: [UIColor],
        centerPoint: UnitPoint = .center,
        startAngle: Angle = .zero,
        endAngle: Angle = .radians(2 * .pi),
        completionPercentage: CGFloat
    ) -> some View {
        ...
    }
}
What you're using πŸ‘†

RoundedRectangle(cornerRadius: 24)
    .animatableAngularGradient(
        startColors: [.systemPurple, .systemBlue, .systemGreen, .white],
        endColors: [.systemGray, .systemPink, .systemOrange, .systemRed],
        completionPercentage: animationCompletion
    )
How you might use it πŸ‘†

Usage on Views

extension View {

    /// - Parameters:
    ///   - fullSpanStartAngle: Setting this property will cause the gradient to being at
    ///         the specified offset, and then span the entire circumference. (Default: `nil`)
    public func animatableAngularGradient<BaseShape: Shape>(
        baseShape: BaseShape,
        startColors: [UIColor],
        endColors: [UIColor],
        centerPoint: UnitPoint = .center,
        fullSpanStartAngle: Angle,
        completionPercentage: CGFloat
    ) -> some View {
        ...
    }


    public func animatableAngularGradient<BaseShape: Shape>(
        baseShape: BaseShape,
        startColors: [UIColor],
        endColors: [UIColor],
        centerPoint: UnitPoint = .center,
        startAngle: Angle = .zero,
        endAngle: Angle = .radians(2 * .pi),
        completionPercentage: CGFloat
    ) -> some View {
        ...
    }
}
What you're using πŸ‘†

Color.clear
    .animatableAngularGradient(
        baseShape: RoundedRectangle(cornerRadius: 24),
        startColors: [.systemPurple, .systemBlue, .systemGreen, .white],
        endColors: [.systemGray, .systemPink, .systemOrange, .systemRed],
        completionPercentage: animationCompletion
    )
How you might use it πŸ‘†

πŸ“Έ Example

⚠️ Edge Cases

  • If you pass a completionPercentage value less than 0, or greater than 1, it will automatically be clamped to the closer endpoint.
  • Behind the scenes, the startColors and endColors arrays get zipped before the interpolated colors are computed. This means that if their sizes are different, the larger array will be trimmed down to the size of the smaller array, and the excess colors in the larger array won't be used.
    • As such, if either or both of the startColors and endColors arrays are empty, the gradient will have no colors passed to it and it will appear completely clear.

Contributing

Contributions to AnimatableGradients are most welcome. Check out some of the issue templates for more info.

Roadmap

  • Mac Catalyst Support (?)
  • watchOS Support (?)

License

AnimatableGradients is available under the MIT license. See the LICENSE file for more info.

animatablegradients's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

animatablegradients's Issues

[FEATURE] Single-color argument support

Is your feature request related to a problem? Please describe.

Currently each modifier is calling to SwiftUI's Gradient under the hood. Because Gradient needs to be called with an array of more than one color, using one "start" and one "end" color doesn't work:

RoundedRectangle(cornerRadius: 24)
    .animatableAngularGradient(
          startColors: [.systemRed],
          endColors: [.systemBlue],
           completionPercentage: animationCompletion
)

Describe the solution you'd like.

It would be nice to support this by just animating a single Color instead of a Gradient.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.