{"id":2347,"url":"https://github.com/SteveBarnegren/TweenKit","last_synced_at":"2025-08-02T23:33:09.000Z","repository":{"id":37484407,"uuid":"85353174","full_name":"SteveBarnegren/TweenKit","owner":"SteveBarnegren","description":"Animation library for iOS in Swift","archived":false,"fork":false,"pushed_at":"2020-09-28T21:35:44.000Z","size":440,"stargazers_count":1347,"open_issues_count":0,"forks_count":77,"subscribers_count":36,"default_branch":"master","last_synced_at":"2024-10-29T17:42:37.869Z","etag":null,"topics":["animation","bezier","ios","onboarding","swift","tween","tweening","uiview"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SteveBarnegren.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-17T20:44:25.000Z","updated_at":"2024-10-25T01:48:30.000Z","dependencies_parsed_at":"2022-09-15T04:10:50.740Z","dependency_job_id":null,"html_url":"https://github.com/SteveBarnegren/TweenKit","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SteveBarnegren%2FTweenKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SteveBarnegren%2FTweenKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SteveBarnegren%2FTweenKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SteveBarnegren%2FTweenKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SteveBarnegren","download_url":"https://codeload.github.com/SteveBarnegren/TweenKit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228503192,"owners_count":17930533,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","bezier","ios","onboarding","swift","tween","tweening","uiview"],"created_at":"2024-01-05T20:16:11.476Z","updated_at":"2024-12-06T17:31:00.938Z","avatar_url":"https://github.com/SteveBarnegren.png","language":"Swift","funding_links":[],"categories":["UI","Content"],"sub_categories":["Animation","Other free courses"],"readme":"# TweenKit\n\n[![CI Status](https://api.travis-ci.org/SteveBarnegren/TweenKit.svg?branch=master)](https://travis-ci.org/SteveBarnegren/TweenKit)\n[![Version](https://img.shields.io/cocoapods/v/TweenKit.svg?style=flat)](http://cocoapods.org/pods/TweenKit)\n[![License](https://img.shields.io/cocoapods/l/TweenKit.svg?style=flat)](http://cocoapods.org/pods/TweenKit)\n[![Platform](https://img.shields.io/cocoapods/p/TweenKit.svg?style=flat)](http://cocoapods.org/pods/TweenKit)\n[![Twitter](https://img.shields.io/badge/contact-@stevebarnegren-blue.svg?style=flat)](https://twitter.com/stevebarnegren)\n\nTweenKit is a powerful animation library that allows you to animate (or 'tween') anything. TweenKit's animations are also scrubbable, perfect for building awesome onboarding experiences!\n\n![tweenkit](https://cloud.githubusercontent.com/assets/6288713/25148841/31245f10-2474-11e7-927d-4045fb88ad52.gif)\n\nDownload the example project to see how these animations were created\n\nTweenKit's animations are:\n\n* Reversible\n* Repeatable\n* Groupable\n* Sequenceable\n* Scrubbable\n* Quick and easy to use!\n\n## Example\n\nThe example project contains a collection of examples of how to use TweenKit. Run `Example.xcodeproj`\n\n## Installation\n\nTweenKit is available through [CocoaPods](http://cocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\npod \"TweenKit\"\n```\n\n## Importing TweenKit\n\n\n\nAdd `import TweenKit` to the top of the files you want to use TweenKit from\n\n## Creating an ActionScheduler\n\nCreate an instance of `ActionScheduler` to run your animations. You should retain the scheduler, so it's best made as a property on your View Controller.\n\n```\nlet scheduler = ActionScheduler()\n```\n\n## Actions\n\nTweenKit's animations are composed of 'Actions'. These are small animation units that can be chained or grouped to build complex animations. Once you have created an action, you can tell the scheduler to run it.\n\n```\nscheduler.run(action: myAction)\n```\n\n## Animating a view's frame\n\nAnything that conforms to the 'Tweenable' protocol, can be animated.\n\nCGRect, CGFloat, Double, Float, UIColor, and other common objects already adopt the 'Tweenable' out of the box.\n\nWe can use TweenKit's `InterpolationAction` to animate a view's frame:\n\n```\nlet fromRect = CGRect(x: 50, y: 50, width: 40, height: 40)\nlet toRect = CGRect(x: 100, y: 100, width: 200, height: 100)\n        \nlet action = InterpolationAction(from: fromRect,\n                                 to: toRect,\n                                 duration: 1.0,\n                                 easing: .exponentialInOut) {\n                                    [unowned self] in self.redView.frame = $0\n}\n        \nscheduler.run(action: action)\n```\n![basictween](https://cloud.githubusercontent.com/assets/6288713/24793903/a4d1b0b8-1b7b-11e7-925d-42deea17faeb.gif)\n\n## Grouping actions\n\nUsing an `ActionGroup`, several animations can be run at once. For instance, we can change a view's frame and it's background color:\n\n```\n// Create a move action\nlet fromRect = CGRect(x: 50, y: 50, width: 40, height: 40)\nlet toRect = CGRect(x: 100, y: 100, width: 200, height: 100)\n        \nlet move = InterpolationAction(from: fromRect,\n                                 to: toRect,\n                                 duration: 2.0,\n                                 easing: .elasticOut) {\n                        [unowned self] in self.squareView.frame = $0\n}\n        \n// Create a color change action\nlet changeColor = InterpolationAction(from: UIColor.red,\n                                      to: UIColor.orange,\n                                      duration: 2.0,\n                                      easing: .exponentialOut) {\n                        [unowned self] in self.squareView.backgroundColor = $0\n}\n        \n// Make a group to run them at the same time\nlet moveAndChangeColor = ActionGroup(actions: move, changeColor)\nscheduler.run(action: moveAndChangeColor)\n```\n\n![grouptween](https://cloud.githubusercontent.com/assets/6288713/24795622/d9c06778-1b81-11e7-9c8b-c44c614e7528.gif)\n\n## Running actions in sequence\n\nUsing an `ActionSequence`, several animations can be run in order. This time, we can use supply a closure as the 'from' parameter, to animate the view from it's current frame:\n\n```\nlet moveOne = InterpolationAction(from: { [unowned self] in self.squareView.frame },\n                                  to: CGRect(x: 120, y: 80, width: 50, height: 50),\n                                  duration: 1,\n                                  easing: .exponentialInOut) {\n                                   [unowned self] in self.squareView.frame = $0\n}\n        \nlet moveTwo = InterpolationAction(from: { [unowned self] in self.squareView.frame },\n                                  to: CGRect(x: 70, y: 120, width: 130, height: 130),\n                                  duration: 1,\n                                  easing: .exponentialInOut) {\n                                    [unowned self] in self.squareView.frame = $0\n}\n        \nlet moveTwice = ActionSequence(actions: moveOne, moveTwo)\nscheduler.run(action: moveTwice)\n```\n\n![sequencetween](https://cloud.githubusercontent.com/assets/6288713/24795989/3486bcba-1b83-11e7-8e2d-cdce94c451ad.gif)\n\n## Repeating actions\n\nUse `RepeatAction` to repeat your actions, or `RepeatForeverAction` to repeat an action forever. You can easily contruct these using the `repeated(times:)` and `repeatedForever` methods on any action:\n\n```\nlet repeatedForever = myAction.repeatedForever()\nscheduler.run(action: repeatedForever)\n```\n\n## Yoyo\n\nIf you want your action to go back and forth, you can use a `YoyoAction`. These can be easily constructed by calling the `yoyo()` method on any action:\n\n```\nlet move = InterpolationAction(from: { [unowned self] in self.squareView.frame },\n                               to: CGRect(x: 250, y: 100, width: 100, height: 100),\n                               duration: 1,\n                               easing: .exponentialInOut) {\n                                [unowned self] in self.squareView.frame = $0\n}\n        \nscheduler.run(action: move.yoyo().repeatedForever() )\n```\n![yoyotween](https://cloud.githubusercontent.com/assets/6288713/24805340/49231f76-1ba9-11e7-9832-2ce5da836947.gif)\n\n## Arc Actions\n\n`ArcAction` can animate any object that conforms to `Tweenable2DCoordinate` in a circular motion.\n\nBy creating some `ArcAction`s  in a staggared `Group`, we can easily create an activity indicator:\n\n```\n// Create an ArcAction for each circle layer\nlet actions = circleLayers.map{\n    layer -\u003e ArcAction\u003cCGPoint\u003e in\n            \n    let action = ArcAction(center: self.view.center,\n                           radius: radius,\n                           startDegrees: 0,\n                           endDegrees: 360,\n                           duration: 1.3) {\n                            [unowned layer] in layer.center = $0\n    }\n    action.easing = .sineInOut\n    return action\n}\n        \n// Run the actions in a staggered group\nlet group = ActionGroup(staggered: actions, offset: 0.125)\n        \n// Repeat forever\nlet repeatForever = group.repeatedForever()\n        \n// Run the action\nscheduler.run(action: repeatForever)\n```\n\n![activityindicator](https://cloud.githubusercontent.com/assets/6288713/24805875/f4b39e0a-1baa-11e7-9e3d-ba8116ec27c5.gif)\n\n## Bezier Actions\n\nObjects can be animated along a bezier path using `BezierAction`. The callback supplies both position and rotation.\n\nBezierAction can animate any value that conforms to the `Tweenable2DCoordinate` protocol.\n\n```        \nlet action = BezierAction(path: bezierPath, duration: 4.0) {\n    [unowned self] (postion, rotation) in\n            \n    self.rocketImageView.center = postion\n            \n    let rocketRotation = CGFloat(rotation.value)\n    self.rocketImageView.transform = CGAffineTransform(rotationAngle: rocketRotation)\n}\n    \naction.easing = .exponentialInOut\n        \nscheduler.run(action: action)\n```\n\n![rocket](https://cloud.githubusercontent.com/assets/6288713/24763091/43de5858-1ae8-11e7-9e70-3e5d4dc182eb.gif)\n\n## Scrubbable actions\n\nScrubbable Actions are great for building unique onboarding experiences.\n\nInstead of adding the action to a scheduler, create an `ActionScrubber` instance:\n\n```     \nlet move = InterpolationAction(from: { [unowned self] in self.squareView.frame },\n                               to: CGRect(x: 130, y: 100, width: 100, height: 100),\n                               duration: 1,\n                               easing: .elasticOut) {\n                                [unowned self] in self.squareView.frame = $0\n}\n        \nself.actionScrubber = ActionScrubber(action: move)\n\n// Scrub the action in a UISlider callback\nfunc sliderChanged(slider: UISlider) {\n    actionScrubber.update(t: Double(slider.value))\n}\n```\n\n![scrubbabletween](https://cloud.githubusercontent.com/assets/6288713/24806390/9955ef7a-1bac-11e7-901c-625e8283487f.gif)\n\n## Animating your own objects\n\nBy adding conformance to the `Tweenable` protocol, anything can be animated. You decide what it means to 'tween' your object, making this a flexible approach.\n\nFor instance, by conforming `String` to `Tweenable` we can turn a **bat** into a **cat**:\n\n```\nInterpolationAction(from: \"bat\",\n                    to: \"cat\",\n                    duration: 4,\n                    easing: .exponentialInOut) {\n                     [unowned self] in self.label.text = $0\n}\n```\n\n![battocat](https://cloud.githubusercontent.com/assets/6288713/24763350/04d6c82e-1ae9-11e7-9aa8-d0ec97cdd8f1.gif)\n\n## Other Stuff\n\nUse `DelayAction` to add a delay in to a sequence\n\nUse `CallBlockAction` to trigger a callback at any point in a sequence\n\n## Author\n\nSteve Barnegren\n\nsteve.barnegren@gmail.com\n\n@stevebarnegren\n\n## License\n\nTweenKit is available under the MIT license. See the LICENSE file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSteveBarnegren%2FTweenKit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSteveBarnegren%2FTweenKit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSteveBarnegren%2FTweenKit/lists"}