{"id":2331,"url":"https://github.com/RobinFalko/Ubergang","last_synced_at":"2025-08-03T00:30:52.763Z","repository":{"id":56925335,"uuid":"54273608","full_name":"RobinFalko/Ubergang","owner":"RobinFalko","description":"Ubergang is a tweening engine for iOS written in Swift.","archived":false,"fork":false,"pushed_at":"2019-07-14T12:05:33.000Z","size":27579,"stargazers_count":54,"open_issues_count":0,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-11T08:52:12.122Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RobinFalko.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":"2016-03-19T15:46:01.000Z","updated_at":"2022-04-15T05:45:52.000Z","dependencies_parsed_at":"2022-08-21T06:20:10.462Z","dependency_job_id":null,"html_url":"https://github.com/RobinFalko/Ubergang","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobinFalko%2FUbergang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobinFalko%2FUbergang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobinFalko%2FUbergang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobinFalko%2FUbergang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RobinFalko","download_url":"https://codeload.github.com/RobinFalko/Ubergang/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228503214,"owners_count":17930539,"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":[],"created_at":"2024-01-05T20:16:11.068Z","updated_at":"2024-12-06T17:31:05.565Z","avatar_url":"https://github.com/RobinFalko.png","language":"Swift","funding_links":[],"categories":["UI","Animation"],"sub_categories":["Animation","Other free courses"],"readme":"![Ubergang - a tweening engine for iOS](https://raw.githubusercontent.com/RobinFalko/Ubergang/master/Ubergang.png)\n\n[![Platform iOS](https://img.shields.io/badge/platform-ios-lightgrey.svg?style=flat-square)](https://img.shields.io/badge/platform-ios-lightgrey.svg?style=flat-square)\n[![CocoaPods Compatible](https://img.shields.io/badge/pod-1.0-blue.svg?style=flat-square)](https://img.shields.io/badge/pod-1.0-blue.svg?style=flat-square)\n[![License Apache2 iOS](https://img.shields.io/badge/license-Apache%202-blue.svg?style=flat-square)](https://img.shields.io/badge/license-Apache%202-blue.svg?style=flat-square)\n\nUbergang is a tweening engine for iOS written in Swift.\n\n\n\n## Features\n\n- [x] Tween numeric values, UIColors and CGAffineTransforms\n- [x] Tween along UIBezierPaths\n- [x] Tween through points\n- [x] Linear, Expo, Cubic, Quad, Circ, Quart, Quint, Sine, Back, Bounce and Elastic easings\n- [x] Generic tween setup\n- [x] Repeat and Yoyo tween options\n- [x] Memory management for strong and weak tween object references\n- [x] Tween Timelines\n- [x] Bezier tween align to path\n- [x] Logging and log levels\n\n## Previews\n\n![Example - Timeline](https://raw.githubusercontent.com/RobinFalko/Ubergang/develop/Movies/exampleTimeline.gif) ![Example - Timeline](https://raw.githubusercontent.com/RobinFalko/Ubergang/develop/Movies/examplePath.gif)\n\n\n## Installation\n\n### [CocoaPods](http://cocoapods.org)\n\n```ruby\n    platform :ios, '8.0'\n    use_frameworks!\n    pod 'Ubergang'\n```\n\n## Setup\n\n```swift\n    UTweenSetup.instance.enableLogging(true)\n    UTweenSetup.instance.enableLogging(true, withLogger: loggerProxy)\n```\n\n\u003e Ubergang provides some logs for basic operations like start, stop, pause, ...\nThere is a dependency to XCGLogger which is used by default, but you can pass any Logger you prefer by creating a custom logger proxy implementing `UTweenLoggable`.\n\n## Tween Configuration\n\n```swift\n    .options(.repeat(n))\n    .options(.yoyo)\n    .options(.repeat(n), .yoyo)\n```\n\n\u003e Using `options` you can let the Tween repeat n (Int) times, let it yoyo or combine both options.\n- Repeat will restart the Tween n times where `repeatCycleChange` will be called with every cycle.\n- Yoyo will reverse the Tween after it reaches the end value.\n\n```swift\n    .reference(.strong)` //(default)\n    .reference(.weak)\n```\n\n\u003e `reference` determines how to handle the reference count for the tween. Ubergang will increase the retain count if the option is set to `.strong` or won't increase it if it's set to `.weak`. These two rules are valid for most cases:\n- The Tween is not stored in a field variable -\u003e `.strong`\n- The Tween is stored in a field variable -\u003e `.weak`\n\n## Usage\n\n### Start a simple numeric Tween (Double)\n\n```swift\n    0.tween(to:10).update({ (value:Int) in print(\"\\(value)\") }).start()\n```\n\u003e This Tween goes from 0 to 10 over 0.5 by default seconds using a linear easing by default. The current value will be printed with every update.\n\n### 'to' and 'from' using closures\n\n```swift\n    NumericTween(id: \"doubleTween\")\n            .from({ [unowned self] in return self.position2.x }, to: { [unowned self] in return self.position1.x })\n            .update({ value, progress in print(\"update: \\(value), progress: \\(progress) \") })\n            .duration(5)\n            .start()\n```\n\u003e Passing closures to 'to' and 'from' will always compute all results using the current values returned by the closures.\n\n\n\n### Start a weak numeric Tween (Int)\n\n```swift\n    var tween: NumericTween\u003cInt\u003e?\n\n    func run() {\n        tween = 0.tween(to: 10)\n            .id(\"intTween\")\n            .duration(5)\n            .update({ value in print(\"update: \\(value)\") })\n            .ease(.elastic(.out))\n            .reference(.weak)\n            .start()\n    }\n```\n\u003e This Tween with id 'intTween' goes from 0 to 10 over 5 seconds using an elastic easing. The current value will be printed with every update.\n.reference(.weak) will store this tween weakly, Ubergang won't increment the reference count. It's up to you to keep the Tween alive.\n\n### Start a numeric Tween repeating 5 times with yoyo\n\n```swift\n    var tween: NumericTween\u003cInt\u003e?\n\n    func run() {\n    \n        tween = 0.tween(to: 10)\n            .id(\"intTween\")\n            .duration(5)\n            .update({ value in print(\"update: \\(value)\") })\n            .ease(.elastic(.out))\n            .reference(.weak)\n            .options(.repeat(5), .yoyo)\n            .start()\n    }\n```\n\n### Start a weak numeric Tween (CGAffineTransform)\n\n```swift\n    @IBOutlet var testView: UIView!\n    var tween: TransformTween?\n\n    func run() {\n        //declare the target values\n        var to = testView.transform\n        to.ty = 200.0\n    \n        tween = testView.transform.tween(to: transform)\n            .id(\"testView\")\n            .duration(2.5)\n            .reference(.weak)\n            .update({ [unowned self] value in self.testView.transform = value })\n    \t    .start()\n    }\n```\n\u003e This Tween with id 'testView' tweens a transform over 2.5 seconds. The resulting tranform will be assigned to the testView with every update 'welf.testView.transform = value'.\n\n\n\n### Start a Timeline containing three Tweens\n\n```swift\n    var timeline: UTimeline = UTimeline(id: \"timeline\")\n\n    func run() {\n        timeline.options(.yoyo).reference(.weak)\n        \n        timeline.append(\n            0.tween(to: 10).id(\"intTween\").duration(5).update({ value, _ in print(\"0-10 value: \\(value)\") })\n        )\n        \n        timeline.append(\n            0.0.tween(to: 10.0).id(\"floatTween1\").duration(5).update({ value, _ in print(\"0.0-10.0 value: \\(value)\") })\n        )\n        \n        timeline.insert(\n            10.0.tween(to: 0.0).id(\"floatTween2\").duration(5).update({ value, _ in print(\"10.0-0.0 value: \\(value)\") }), at: 2.5\n        )\n  \n        timeline.start()\n    }\n```\n\u003e This Timeline controls one Tween starting at time 0.0 seconds, one Tween starting at time 5.0 seconds and the last one starting at 2.5 seconds. All Tweens are controlled by the timeline with the given options - In this case the tween option `.yoyo`\n\n\n\n\n### Tween along a UIBezierPath\n\n```swift\n    var tween: BezierPathTween!\n\n    func run() {\n    tween = BezierPathTween().along(path)\n            .id(\"bezierTween\")\n            .duration(5)\n            .ease(.linear)\n            .reference(.weak)\n            .update({ [unowned self] (value: CGPoint, progress: Double) in\n                //update\n            })\n            .start()\n    }\n```\n\n\n\n\n### Tween through points\n\n```swift\n    var tween: BezierPathTween!\n\n    func run() {\n        let points = [CGPoint]()\n        points.append(...)\n\n        tween = BezierPathTween().along(points)\n            .id(\"bezierTween\")\n            .duration(5)\n            .ease(.linear)\n            .reference(.weak)\n            .update({ [unowned self] (value: CGPoint, progress: Double) in\n                //update\n            })\n            .start()\n    }    \n```\n\n\n\n\n### Tween through points and use orientation to align the object on update\n\n```swift\n    var tween: BezierPathTween!\n\n    func run() {\n        let points = [CGPoint]()\n        points.append(...)\n\n        tween = BezierPathTween().along(points)\n            .id(\"bezierTween\")\n            .duration(5)\n            .ease(.linear)\n            .reference(.weak)\n            .update({ [unowned self] (value:CGPoint, progress: Double, orientation: CGPoint) in\n                self.targetView.center = value\n\n                let angle = atan2(orientation.y, orientation.x)\n                let transform = CGAffineTransformRotate(CGAffineTransformIdentity, angle)\n                self.targetView.transform = transform\n            })\n            .start()\n    }      \n```\n\n\n## Changelog Verion 1.2.0\n\n- The Ease type changed to an Enum instead of passing the function type directly e.g. \n```swift\n\t.ease(Linear.ease) becomes .ease(.linear)\n\t.ease(Elastic.easeOut) becomes .ease(.elastic(.out))\n```\n- When starting a tween which is already playing, it will now only log a warning via the logger proxy instead of guarding a restart\n- The new tween direction 'backward' will inverse easings and tween start times within a timeline\n\n```swift\n/*\n    forward --\u003e\nt0: |-----------------------|\nt1:     |----------------------|\nt2: |--------|\n*/\n\n/*\n                     \u003c-- reverse\nt0: |-----------------------|\nt1:     |----------------------|\nt2: |--------|\n*/\n\n/*\n                    \u003c-- backward\nt0:    |-----------------------|\nt1: |----------------------|\nt2:                   |--------|\n*/\n```\n\n\n## Changelog Verion 1.1.0\n\n- Swift 5 migration\n\n\n## Changelog Verion 1.0\n\n- Swift 4 migration\n- Change tween creation pattern (UTweenBuilder removed - Instead instantiate the tween object directly or use the appropriate extension like `0.tween(to: 10)`)\n- Add @discardableResult to specific methods\n- Fix issue where timelines didn't work if there was a delay between tweens\n\nFeedback is always appreciated\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRobinFalko%2FUbergang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FRobinFalko%2FUbergang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRobinFalko%2FUbergang/lists"}