{"id":24527185,"url":"https://github.com/mttfntn/onefingerrotation","last_synced_at":"2025-12-11T23:01:32.760Z","repository":{"id":154898424,"uuid":"631314363","full_name":"mttfntn/OneFingerRotation","owner":"mttfntn","description":"One Finger Rotation of a SwiftUI element in a view, complete with Inertia functions and Auto Rotation functions","archived":false,"fork":false,"pushed_at":"2025-01-12T11:49:16.000Z","size":16660,"stargazers_count":54,"open_issues_count":1,"forks_count":10,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-01-30T23:23:06.770Z","etag":null,"topics":["auto-rotation","dj-turntable","fidget-spinner","inertia","knob","pinwheel","rotation","rotation-inertia","selector","spinning","swift","swiftpackageindex","swiftui"],"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/mttfntn.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-22T16:18:15.000Z","updated_at":"2025-01-28T20:21:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"51c59c73-f148-411b-b26f-35621e33a188","html_url":"https://github.com/mttfntn/OneFingerRotation","commit_stats":null,"previous_names":["mttfntn/onefingerrotation","matteofontana-app/onefingerrotation"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mttfntn%2FOneFingerRotation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mttfntn%2FOneFingerRotation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mttfntn%2FOneFingerRotation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mttfntn%2FOneFingerRotation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mttfntn","download_url":"https://codeload.github.com/mttfntn/OneFingerRotation/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244066189,"owners_count":20392406,"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":["auto-rotation","dj-turntable","fidget-spinner","inertia","knob","pinwheel","rotation","rotation-inertia","selector","spinning","swift","swiftpackageindex","swiftui"],"created_at":"2025-01-22T06:17:03.442Z","updated_at":"2025-12-11T23:01:32.360Z","avatar_url":"https://github.com/mttfntn.png","language":"Swift","funding_links":["https://www.buymeacoffee.com/matteofontana"],"categories":[],"sub_categories":[],"readme":"![](https://github.com/matteofontana-app/Assets/blob/main/OneFingerRotation/MainTitle.gif)\n\n![](https://img.shields.io/badge/Matteo%20Fontana-Framework-black.svg?style=flat-square\u0026logo=data:image/png;base64,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)\n![GitHub](https://img.shields.io/github/license/matteofontana-app/OneFingerRotation?label=License\u0026style=flat-square)\n![GitHub issues](https://img.shields.io/github/issues/matteofontana-app/OneFingerRotation?style=flat-square)\n![GitHub Repo stars](https://img.shields.io/github/stars/matteofontana-app/OneFingerRotation?style=flat-square)\n![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/matteofontana-app/OneFingerRotation?label=Package%20Size\u0026style=flat-square)\n![GitHub release (latest by date)](https://img.shields.io/github/v/release/matteofontana-app/OneFingerRotation?style=flat-square\u0026label=Last%20Release)\u003cbr\u003e\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fmatteofontana-app%2FOneFingerRotation%2Fbadge%3Ftype%3Dswift-versions\u0026style=flat-square)](https://swiftpackageindex.com/matteofontana-app/OneFingerRotation)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fmatteofontana-app%2FOneFingerRotation%2Fbadge%3Ftype%3Dplatforms\u0026style=flat-square)](https://swiftpackageindex.com/matteofontana-app/OneFingerRotation)\n\n\nOneFingerRotation is a lightweight **SwiftUI framework** that enables you to add a one-finger rotation gesture to any view with a single modifier. This library is perfect for developers who want to quickly and easily implement **rotation functionality** in their SwiftUI applications without the hassle of dealing with complex gesture recognizers.\n\nCurrent Version: **1.2.0**\n\n---\n\n\u003c!--Table of Content--\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n\n## Table of Content\n\n\u003c/summary\u003e\n\n- [Table of Content](#table-of-content)\n- [Presentation](#presentation)\n- [Usage](#usage)\n  - [Simple Rotation](#simple-rotation)\n  - [Simple Rotation with Inertia](#simple-rotation-with-inertia)\n  - [Value Rotation](#value-rotation)\n  - [Value Rotation with Inertia](#value-rotation-with-inertia)\n  - [Auto Rotation](#auto-rotation)\n  - [Value Auto Rotation](#value-auto-rotation)\n  - [Value Auto Rotation with Inertia](#value-auto-rotation-with-inertia)\n  - [Knob](#knob)\n  - [Knob with Inertia](#knob-with-inertia)\n- [Examples](#examples)\n- [Versions](#versions)\n- [Contributions](#contributions)\n- [Next to come:](#next-to-come)\n- [Donations / Support](#donations--support)\n- [Contact](#contact)\n- [License](#license)\n\u003c/details\u003e\n\n## Usage\n\nThe Framework is composed of a series of modifiers that you can apply to any view in your SwiftUI project.\nIt is recommended to use a frame modifier with equal width and height above the frameworks modifiers, this will ensure that the rotation will take place inside of the specific view. Example:\n\n```swift\n  .frame(width: 400, height: 400)\n```\nUse only one modifier of the framework at a time.\u003cbr\u003e\nHere's the list of the modifiers in the framework:\n\n\u003cdetails\u003e\n\u003csummary\u003e\n\n### Simple Rotation\n\n\u003c/summary\u003e\n\nThe Simple Rotation allows for a simple rotation using one finger.\n  \n\u003cimg align=\"right\" width=\"175\" src=\"https://github.com/matteofontana-app/Assets/blob/main/OneFingerRotation/Modifiers/SimpleRotation.gif\"/\u003e\n\n**Declaration:**\n\n```swift\n  .simpleRotation()\n```\n**Customization:**\n\n* rotationAngle: identifies the original angle of the element\u003cbr\u003e [Type: **Angle** - Stock value: **.degrees(0)**]\n\n* angleSnap: allows snapping using an angle factor which identifies the basic multiple of the angle\u003cbr\u003e [Type: **Binding\\\u003cDouble\\\u003e** - Stock Value: **Non declared**]\n  \n```swift\n  .simpleRotation(\n    rotationAngle: .degrees(20)\n    angleSnap: .constant(60)\n  )\n```\n\u003c/details\u003e\n\n\u003c!--Simple Rotation with Inertia--\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n\n### Simple Rotation with Inertia\n\n\u003c/summary\u003e\n\nThe Simple Inertia Rotation allows the view for a simple rotation with consequent inertia effect.\n\n\u003cimg align=\"right\" width=\"175\" src=\"https://github.com/matteofontana-app/Assets/blob/main/OneFingerRotation/Modifiers/SimpleRotationInertia.gif\"/\u003e\n  \n**Declaration:**\n\nDeclaration should be like this:\n\n```swift\n  .simpleRotationInertia()\n```\n\n**Customization:**\n\nThese are the customization possibilities:\n* friction: the inertia factor of slowdown.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **0.005**] \n* velocityMultiplier: the speed multiplier of the inertia function related to the speed of the gesture on screen.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **0.1**]\n* decelerationFactor: the deceleration factor multiplier, big value indicates a longer inertia.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **0.4**]\n* rotationAngle: identifies the original angle of the element\u003cbr\u003e [Type: **Angle** - Stock value: **.degrees(0)**]\n* angleSnap: allows snapping using an angle factor which identifies the basic multiple of the angle\u003cbr\u003e [Type: **Binding\\\u003cDouble\\\u003e** - Stock Value: **Non declared**]\n* angleSnapShowFactor: this variable controls the visibility during the inertia of angles not belonging to the angleSnap range.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **0.1**]\n  \n```swift\n  .simpleRotationInertia(\n    friction: .constant(0.005),\n    velocityMultiplier: .constant(0.1),\n    decelerationFactor: .constant(0.4),\n    rotationAngle: .degrees(0.0),\n    angleSnap: .constant(20),\n    angleSnapShowFactor: .constant(0.1)\n  )\n```\n\n\u003c/details\u003e\n\n\u003c!--Value Rotation--\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n\n### Value Rotation\n\n\u003c/summary\u003e\nThe Value Rotation allows for a simple rotation using one finger with a linked value related to the total angle of rotation.\n  \n\u003cimg align=\"right\" width=\"175\" src=\"https://github.com/matteofontana-app/Assets/blob/main/OneFingerRotation/Modifiers/ValueRotation.gif\"/\u003e\n\n**Setup**\n\nTo use the modifier it's necessary to create a variable of type double that will indicate the starting point of the element. Example:\n\n```swift\n  @State private var totalAngle: Double = 0.0\n```\n\n**Declaration:**\n\nTo declare the modifier it is mandatory to link the variable and also the onAngleChanged, inside of this there must be the linked variable.\n\n```swift\n  .valueRotation(\n    totalAngle: $totalAngle2,\n    onAngleChanged: { newAngle in\n    totalAngle2 = newAngle\n    }\n  )\n```\n\n**Customization:**\n\n*  animation: this parameter controls the animation during a change of totalAngle from outside the modifier.\u003cbr\u003e[Type: **Animation** - Stock value: **Missing value**]\n\n```swift\n  .valueRotation(\n    totalAngle: $totalAngle,\n    onAngleChanged: { newAngle in\n    totalAngle = newAngle\n    },\n    animation: .spring()\n  )\n```\n\n\n\u003c/details\u003e\n\n\u003c!--Value Rotation with Inertia--\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n\n### Value Rotation with Inertia\n\n\u003c/summary\u003e\n\nThe Value Rotation with Inertia allows for a rotation with value linked and inertia effect at the end of the gesture.\n  \n\u003cimg align=\"right\" width=\"175\" src=\"https://github.com/matteofontana-app/Assets/blob/main/OneFingerRotation/Modifiers/ValueRotationInertia.gif\"/\u003e\n\n**Setup**\n\nTo use the modifier it's necessary to create a variable of type double that will indicate the starting point of the element. Example:\n\n```swift\n  @State private var totalAngle: Double = 0.0\n```\n\n**Declaration:**\n\nTo declare the modifier it is mandatory to link the variable and also the onAngleChanged, inside of this there must be the linked variable.\n\n```swift\n  .valueRotationInertia(\n      totalAngle: $totalAngle,\n      onAngleChanged: { newAngle in\n      totalAngle = newAngle\n    }\n  )\n```\n\n\n**Customization:**\n\nThese are the customization possibilities:\n* friction: the inertia factor of slowdown.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **0.005**] \n* velocityMultiplier: the speed multiplier of the inertia function related to the speed of the gesture on screen.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **0.1**]\n*  animation: this parameter controls the animation during a change of totalAngle from outside the modifier.\u003cbr\u003e[Type: **Animation** - Stock value: **Missing**]\n* stoppingAnimation: this variable controls if the rotation stops after the value of knobValue changes outside the modifier. It is suggested to use a variable as it will be needed in case of this application.\u003cbr\u003e[Type: **Binding\\\u003cBool\\\u003e** - Stock value: **false**]\n\n```swift\n  .valueRotationInertia(\n    totalAngle: $totalAngle,\n    friction: .constant(0.005),\n    onAngleChanged: { newAngle in\n      totalAngle3 = newAngle\n    },\n    velocityMultiplier: .constant(0.1),\n    animation: .spring(),\n    stoppingAnimation: $valueChange\n)\n```\n\n\u003c/details\u003e\n\n\u003c!--Auto Rotation--\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n\n### Auto Rotation\n\n\u003c/summary\u003e\n\nThe Auto Rotation applies an automatic rotation to a simple rotation.\n  \n\u003cimg align=\"right\" width=\"175\" src=\"https://github.com/matteofontana-app/Assets/blob/main/OneFingerRotation/Modifiers/AutoRotation.gif\"/\u003e\n\n**Declaration:**\n\n```swift\n  .autoRotation()\n```\n**Customization:**\n\n* rotationAngle: Identifies the original angle of the element\u003cbr\u003e [Type: **Angle** - Stock value: **.degrees(0)**]\n\n* autoRotationSpeed: Indicates the speed of the rotation of the content during motion.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **20**]\n\n* autoRotationActive: Indicates if the content has to rotate or not, allowing for pause of the rotation.\u003cbr\u003e[Type: **Binding\\\u003cBool\\\u003e** - Stock value: **true**]\n  \n```swift\n  .autoRotation(\n    rotationAngle: .degrees(20)\n    autoRotationSpeed: .constant(20),\n    autoRotationActive: .constant(true)\n  )\n```\n\nIn case there have been use of variables for the last two parameters it is possible to modify them using binding variables:\n\n```swift\n  .autoRotation(\n    rotationAngle: .degrees(20),\n    autoRotationSpeed: $autoRotationSpeed,\n    autoRotationActive: $autoRotationActive\n  )\n```\n\nUsing this method will make able to modify the variables during the use of the modifier:\n\n```swift\n  Button(action: {\n    autoRotationActive.toggle()\n  }, label: {\n    Text(\"Pause the Rotation\")\n  })\n\n  Button(action: {\n    autoRotationSpeed = [Insert double value here]\n  }, label: {\n    Text(\"Modify the speed\")\n  })\n```\n\n\u003c/details\u003e\n\n\u003c!--Value Auto Rotation--\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n\n### Value Auto Rotation\n\n\u003c/summary\u003e\n\nThe Value Auto Rotation links a value related to the angle of an Auto Rotation\n  \n\u003cimg align=\"right\" width=\"175\" src=\"https://github.com/matteofontana-app/Assets/blob/main/OneFingerRotation/Modifiers/ValueAutoRotation.gif\"/\u003e\n\n**Setup**\n\nTo use the modifier it's necessary to create a variable of type double that will indicate the starting point of the element. Example:\n\n```swift\n  @State private var totalAngle: Double = 0.0\n```\n\n**Declaration:**\n\nTo declare the modifier it is mandatory to link the variable and also the onAngleChanged, inside of this there must be the linked variable.\n\n```swift\n  .valueAutoRotation(\n    totalAngle: $totalAngle,\n    onAngleChanged: { newAngle in\n        totalAngle = newAngle\n    }\n  )\n```\n\n**Customization:**\n\n*  animation: this parameter controls the animation during a change of totalAngle from outside the modifier.\u003cbr\u003e[Type: **Animation** - Stock value: **Missing value**]\n\n* autoRotationSpeed: Indicates the speed of the rotation of the content during motion.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **20**]\n\n* autoRotationActive: Indicates if the content has to rotate or not, allowing for pause of the rotation.\u003cbr\u003e[Type: **Binding\\\u003cBool\\\u003e** - Stock value: **true**]\n\n```swift\n  .valueAutoRotation(\n    totalAngle: $totalAngle,\n    onAngleChanged: { newAngle in\n        totalAngle = newAngle\n    },\n    animation: .spring(),\n    autoRotationSpeed: .constant(20),\n    autoRotationEnabled: .constant(true)\n  )\n```\n\nAt this point is also possible to add the reading of the totalAngle:\n```swift\n  Text(\"The value is: \\(totalAngle)\")\n```\n\nIn case there have been use of variables for the last two parameters it is possible to modify them using binding variables:\n\n```swift\n  .valueAutoRotation(\n    totalAngle: $totalAngle,\n    onAngleChanged: { newAngle in\n        totalAngle = newAngle\n    },\n    animation: .spring(),\n    autoRotationSpeed: $autoRotationSpeed,\n    autoRotationActive: $autoRotationActive\n  )\n```\n\nUsing this method will make able to modify the variables during the use of the modifier:\n\n```swift\n  Button(action: {\n    autoRotationActive.toggle()\n  }, label: {\n    Text(\"Pause the Rotation\")\n  })\n\n  Button(action: {\n    autoRotationSpeed = [Insert double value here]\n  }, label: {\n    Text(\"Modify the speed\")\n  })\n```\n\n\ncontent\n\u003c/details\u003e\n\n\u003c!--Value Auto Rotation with Inertia--\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n\n### Value Auto Rotation with Inertia\n\n\u003c/summary\u003e\n\nAn Automatic rotation with finger rotation gesture and inertia effect. All in one.\n  \n\u003cimg align=\"right\" width=\"175\" src=\"https://github.com/matteofontana-app/Assets/blob/main/OneFingerRotation/Modifiers/ValueAutoRotationInertia.gif\"/\u003e\n\n**Setup**\n\nTo use the modifier it's necessary to create a variable of type double that will indicate the starting point of the element. Example:\n\n```swift\n  @State private var totalAngle: Double = 0.0\n```\n\n**Declaration:**\n\nTo declare the modifier it is mandatory to link the variable and also the onAngleChanged, inside of this there must be the linked variable.\n\n```swift\n  .valueAutoRotationInertia(\n    totalAngle: $totalAngle,\n    onAngleChanged: { newAngle in\n    totalAngle = newAngle\n    }\n  )\n```\n\n**Customization**\n\nThese are the customization possibilities:\n\n* friction: the inertia factor of slowdown.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **0.005**] \n* velocityMultiplier: the speed multiplier of the inertia function related to the speed of the gesture on screen.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **0.1**]\n*  animation: this parameter controls the animation during a change of totalAngle from outside the modifier.\u003cbr\u003e[Type: **Animation** - Stock value: **Missing value**]\n* stoppingAnimation: this variable controls if the rotation stops after the value of knobValue changes outside the modifier. It is suggested to use a variable as it will be needed in case of this application.\u003cbr\u003e[Type: **Binding\\\u003cBool\\\u003e** - Stock value: false]\n* autoRotationSpeed: Indicates the speed of the rotation of the content during motion.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **20**]\n* autoRotationActive: Indicates if the content has to rotate or not, allowing for pause of the rotation.\u003cbr\u003e[Type: **Binding\\\u003cBool\\\u003e** - Stock value: **true**]\n\n```swift\n  .valueAutoRotationInertia(\n    totalAngle: $totalAngle,\n    friction: .constant(0.1)\n    onAngleChanged: { newAngle in\n      totalAngle = newAngle\n    },\n    velocityMultiplier: .constant(0.1),\n    animation: .spring(),\n    stoppingAnimation: $valueChange,\n    autoRotationSpeed: .constant(90),\n    autoRotationEnabled: .constant(true)\n  )\n```\n\n\u003c/details\u003e\n\n\u003c!--Knob--\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n\n### Knob\n\n\u003c/summary\u003e\n\nThe Knob applies a range value from 0 to 1 to a certain angle interval.\n  \n\u003cimg align=\"right\" width=\"175\" src=\"https://github.com/matteofontana-app/Assets/blob/main/OneFingerRotation/Modifiers/KnobRotation.gif\"/\u003e\n\n**Setup:**\n\nTo use the modifier it's necessary to create a variable of type double between the range 0.0-1.0, this variable will indicate the starting point of the knob. For example in this next implementation, the knob will start from the middle point:\n\n```swift\n  @State private var knobValue: Double = 0.5\n```\n\n**Declaration:**\n\nTo declare the modifier it is mandatory to link the variable and also the onKnobValueChanged, inside of this there must be the linked variable.\n\n```swift\n  .knobRotation(\n    knobValue: $knobValue,\n    onKnobValueChanged: { newValue in\n      knobValue = newValue\n    }\n  )\n```\n\n**Customization:**\n\n* minAngle: the minimum angle of the knob.\u003cbr\u003e[Type: **Double** - Stock value: **-90**]\n* maxAngle: the maximum angle of the knob.\u003cbr\u003e[Type: **Double** - Stock value: **+90**]\n* animation: this parameter controls the animation during a change of knobValue from outside the modifier.\u003cbr\u003e[Type: **Animation** - Stock value: **Missing value**]\n\n\n```swift\n  .knobRotation(\n    knobValue: $knobValue,\n    minAngle: -180,\n    maxAngle: +180,\n    onKnobValueChanged: { newValue in\n      knobValue = newValue\n    },\n    animation: .spring()\n  )\n```\nAt this point is also possible to add the reading of the knobValue:\n```swift\n  Text(\"The value is: \\(knobValue)\")\n```\nIn case there is need to change the value from outside this is the procedure ot call it:\n```swift\n  Button(action: {\n    knobValue = 0.6\n  }, label: {\n    Text(\"Button\")\n  })\n```\n\n\u003c/details\u003e\n\n\u003c!--Knob Inertia--\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n\n### Knob with Inertia\n\n\u003c/summary\u003e\n\nThe Knob Inertia applies inertia effect to a simple knob.\n  \n\u003cimg align=\"right\" width=\"175\" src=\"https://github.com/matteofontana-app/Assets/blob/main/OneFingerRotation/Modifiers/KnobInertia.gif\"/\u003e\n\n**Setup:**\n\nTo use the modifier it's necessary to create a variable of type double between the range 0.0-1.0, this variable will indicate the starting point of the knob. For example in this next implementation, the knob will start from the middle point:\n\n```swift\n  @State private var knobValue: Double = 0.5\n```\n\n**Declaration:**\n\nTo declare the modifier it is mandatory to link the variable and also the onKnobValueChanged, inside of this there must be the linked variable.\n\n```swift\n  .knobInertia(\n    knobValue: $knobValue,\n    onKnobValueChanged: { newValue in\n      knobValue = newValue\n    }\n  )\n```\n\n**Customization:**\n\nYou can customize these parameters:\u003cbr\u003e\n* minAngle: the minimum angle of the knob.\u003cbr\u003e[Type: **Double** - Stock value: **-90**]\n* maxAngle: the maximum angle of the knob.\u003cbr\u003e[Type: **Double** - Stock value: **+90**]\n* friction: the inertia factor of slowdown.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **0.2**]\n* velocityMultiplier: the speed multiplier of the inertia function related to the speed of the gesture on screen.\u003cbr\u003e[Type: **Binding\\\u003cDouble\\\u003e** - Stock value: **0.1**]\n* animation: this parameter controls the animation during a change of knobValue from outside the modifier.\u003cbr\u003e[Type: **Animation** - Stock value: **Missing value**]\n* stoppingAnimation: this variable controls if the rotation stops after the value of knobValue changes outside the modifier. It is suggested to use a variable as it will be needed in case of this application.\u003cbr\u003e[Type: **Binding\\\u003cBool\\\u003e** - Stock value: **false**]\n\n\n```swift\n@State var valueChange: Bool = false\n///Other code sections\n  .knobInertia(\n    knobValue: $knobValue,\n    minangle: -180,\n    maxAngle: +180,\n    friction: .constant(0.1),\n    onKnobValueChanged: { newValue in\n      knobValue = newValue\n    },\n    velocityMultiplier: .constant(0.1),\n    animation: .spring(),\n    stoppingAnimation: $valueChange\n  )\n```\n\nAt this point is also possible to add the reading of the knobValue:\n```swift\n  Text(\"The value is: \\(knobValue)\")\n```\nIn case there is need to change the value from outside this is the procedure ot call it:\u003cbr\u003eOther than sending the new value it is necessary to switch the value of valueChange like this:\n```swift\n  Button(action: {\n    knobValue = 0.6\n    valueChange = true\n  }, label: {\n    Text(\"Button\")\n  })\n```\n\n\u003c/details\u003e\n\n## Versions\n* 1.2.1: Refinements to the content of the README file, adjustments to the Simple Rotation function, video examples in the README file.\n* 1.2.0: Implementation of functions of snapping for Simple Rotation, Simple Rotation with Inertia\n* 1.0.0: Implementation of the modifiers: Simple Rotation, Simple Rotation with Inertia, Value Rotation, Value Rotation with Inertia, Auto Rotation, Value Auto Rotation, Value Auto Rotation with Inertia, Knob, Knob with Inertia.\n\n---\n## Contributions\n\nFeel free to file a new issue with a respective title and description in the specific issue form. If you want you can also fill a pull request to speed up on the improvement of the framework. As the code is open source, feel free to work on the code as you like. Remember that a citation to this page and to the profile will be appreciated. Thank you!\n\n---\n\n## Next to come:\n\nThe angleSnap functions can be added to all the modifiers. So this will be the purpose of future updates.\n\n---\n## Donations / Support\n\nYou can support me and my work through buymeacoffee. Any help would be really appreciated!\n\n\u003ca href=\"https://www.buymeacoffee.com/matteofontana\" target=\"_blank\"\u003e\u003cimg src=\"https://cdn.buymeacoffee.com/buttons/v2/arial-yellow.png\" alt=\"Buy Me A Coffee\" style=\"height: 60px !important;width: 217px !important;\" \u003e\u003c/a\u003e\n\n---\n## Contact\n\nIn case you are interested in collaborations or commisions, you can contact me through these channels:\n\nMail: matteofontana@matteofontana.app\u003cbr\u003e\nWebsite: matteofontana.app\n\n---\n## License\n\nMIT License\n\nCopyright © 2023 Matteo Fontana\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nCopyright © 2023 Matteo Fontana\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmttfntn%2Fonefingerrotation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmttfntn%2Fonefingerrotation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmttfntn%2Fonefingerrotation/lists"}