Skip to content

Commit 8a3423f

Browse files
committed
Add README and documentation
1 parent ef2e87c commit 8a3423f

16 files changed

Lines changed: 331 additions & 50 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
/Packages
44
/*.xcodeproj
55
xcuserdata/
6+
.swiftpm

.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Lines changed: 0 additions & 7 deletions
This file was deleted.

Example/CircularControlExample.xcodeproj/project.pbxproj

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,11 @@
254254
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
255255
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
256256
CODE_SIGN_ENTITLEMENTS = CircularControlExample/CircularControlExample.entitlements;
257+
CODE_SIGN_IDENTITY = "Apple Development";
257258
CODE_SIGN_STYLE = Automatic;
258259
CURRENT_PROJECT_VERSION = 1;
259260
DEVELOPMENT_ASSET_PATHS = "\"CircularControlExample/Preview Content\"";
260-
DEVELOPMENT_TEAM = CN5H83SSGJ;
261+
DEVELOPMENT_TEAM = D7DS2U3H59;
261262
ENABLE_HARDENED_RUNTIME = YES;
262263
ENABLE_PREVIEWS = YES;
263264
GENERATE_INFOPLIST_FILE = YES;
@@ -276,8 +277,9 @@
276277
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
277278
MACOSX_DEPLOYMENT_TARGET = 15.2;
278279
MARKETING_VERSION = 1.0;
279-
PRODUCT_BUNDLE_IDENTIFIER = work.philz.CircularControlExample;
280+
PRODUCT_BUNDLE_IDENTIFIER = work.philz.CircularControl;
280281
PRODUCT_NAME = "$(TARGET_NAME)";
282+
PROVISIONING_PROFILE_SPECIFIER = "";
281283
SDKROOT = auto;
282284
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
283285
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -293,10 +295,11 @@
293295
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
294296
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
295297
CODE_SIGN_ENTITLEMENTS = CircularControlExample/CircularControlExample.entitlements;
298+
CODE_SIGN_IDENTITY = "Apple Development";
296299
CODE_SIGN_STYLE = Automatic;
297300
CURRENT_PROJECT_VERSION = 1;
298301
DEVELOPMENT_ASSET_PATHS = "\"CircularControlExample/Preview Content\"";
299-
DEVELOPMENT_TEAM = CN5H83SSGJ;
302+
DEVELOPMENT_TEAM = D7DS2U3H59;
300303
ENABLE_HARDENED_RUNTIME = YES;
301304
ENABLE_PREVIEWS = YES;
302305
GENERATE_INFOPLIST_FILE = YES;
@@ -315,8 +318,9 @@
315318
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
316319
MACOSX_DEPLOYMENT_TARGET = 15.2;
317320
MARKETING_VERSION = 1.0;
318-
PRODUCT_BUNDLE_IDENTIFIER = work.philz.CircularControlExample;
321+
PRODUCT_BUNDLE_IDENTIFIER = work.philz.CircularControl;
319322
PRODUCT_NAME = "$(TARGET_NAME)";
323+
PROVISIONING_PROFILE_SPECIFIER = "";
320324
SDKROOT = auto;
321325
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
322326
SWIFT_EMIT_LOC_STRINGS = YES;

Example/CircularControlExample/SimpleDemoView.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ struct SimpleDemoView: View {
2929
),
3030
shadow: .init(color: .teal.opacity(0.6), radius: 12)
3131
), format: .fraction)
32+
.circularControlProgressAnimation(.bouncy)
3233
.fontDesign(.serif)
3334
.padding()
3435

@@ -44,6 +45,7 @@ struct SimpleDemoView: View {
4445
.font(.largeTitle)
4546
.foregroundStyle(.orange)
4647
}
48+
.circularControlProgressAnimation(.bouncy(duration: 2.4))
4749
.padding()
4850
}
4951
}

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import PackageDescription
66
let package = Package(
77
name: "PZCircularControl",
88
platforms: [
9-
.iOS(.v17), .macOS(.v14), .watchOS(.v10), .tvOS(.v17)
9+
.iOS(.v17), .macOS(.v14), .watchOS(.v10), .tvOS(.v17), .visionOS(.v1)
1010
],
1111
products: [
1212
// Products define the executables and libraries produced by a package, and make them visible to other packages.

README.md

Lines changed: 166 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,170 @@
1-
![Circular Control](https://github.com/philzet/PZCircularControl/blob/master/Resources/CircularControl.png)
1+
![Circular Control](./Resources/CircularControl.png)
22

33
# SwiftUI Circular Control
44

5-
A custom circular progress bar made in SwiftUI.
5+
A cross-platform, highly customizable circular progress control for SwiftUI.
6+
7+
[![Swift Package Manager](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat-square)](https://swift.org/package-manager)
8+
[![Platforms](https://img.shields.io/badge/Platforms-iOS_17.0+_macOS_14.0+_visionOS_1+-blue?style=flat-square)](https://developer.apple.com/swift)
9+
[![Swift](https://img.shields.io/badge/Swift-6.0+-orange?style=flat-square)](https://swift.org)
610

711
## Features
812

9-
* Highly customizable
10-
* Animatable
11-
* Updated to the latest syntax
13+
- Use as an editable control or a progress indicator
14+
- Rich customization options with built-in and custom styles
15+
- Built-in animation and transition support
16+
17+
## Installation
18+
19+
### Swift Package Manager
20+
21+
Add PZCircularControl to your project through Xcode's package manager:
22+
23+
1. File > Add Package Dependencies
24+
2. Add https://github.com/philptr/PZCircularControl.git
25+
26+
Or add it to your `Package.swift`:
27+
28+
```swift
29+
dependencies: [
30+
.package(url: "https://github.com/philptr/PZCircularControl.git", from: "1.0.0")
31+
]
32+
```
33+
34+
## Quick Start
35+
36+
### Static Progress
37+
38+
![Basic Usage](./Resources/static-progress.gif)
39+
40+
You can add a simple yet customizable progress indicator to your view in a single line of code.
41+
42+
```swift
43+
// Basic usage:
44+
CircularControl(progress: 0.4)
45+
46+
// Customized style:
47+
CircularControl(
48+
progress: 0.75,
49+
strokeWidth: 15,
50+
style: .init(
51+
track: Color.secondary.opacity(0.25),
52+
progress: LinearGradient(
53+
colors: [.teal, .mint],
54+
startPoint: .topLeading,
55+
endPoint: .bottomTrailing
56+
)
57+
)
58+
)
59+
```
60+
61+
### Interactive Control
62+
63+
![Interactive Control](./Resources/interactive-control.gif)
64+
65+
```swift
66+
import CircularControl
67+
68+
struct ContentView: View {
69+
@State private var progress = 0.7
70+
71+
var body: some View {
72+
// A basic interactive control usage with the default style:
73+
CircularControl(progress: $progress)
74+
75+
// A customized interactive control with a custom style:
76+
CircularControl(
77+
progress: $progress,
78+
strokeWidth: 15,
79+
style: .init(
80+
track: Color.secondary.opacity(0.2),
81+
progress: LinearGradient(
82+
colors: [.blue, .purple],
83+
startPoint: .topLeading,
84+
endPoint: .bottomTrailing
85+
)
86+
)
87+
)
88+
}
89+
}
90+
```
91+
92+
Check out the example project for more usage examples.
93+
94+
## Customization
95+
96+
### Styles
97+
98+
PZCircularControl supports custom styles for the track, the progress bar, and the interactive knob:
99+
100+
```swift
101+
let style = CircularControlStyle(
102+
track: Color.gray.opacity(0.2),
103+
progress: LinearGradient(colors: [.blue, .purple]),
104+
knob: Color.white
105+
)
106+
107+
CircularControl(
108+
progress: progress,
109+
style: style
110+
) {
111+
Text("\(Int(progress * 100))%")
112+
}
113+
```
114+
115+
### Custom Labels
116+
117+
You can provide any SwiftUI view as a label:
118+
119+
```swift
120+
CircularControl(progress: progress) {
121+
VStack {
122+
Image(systemName: "star.fill")
123+
Text("\(Int(progress * 100))%")
124+
}
125+
}
126+
```
127+
128+
To simplify your custom label implementation, you can read `circularControlProgress` from environment.
129+
130+
### Environment Configuration
131+
132+
Configure behavior through environment values:
133+
134+
```swift
135+
CircularControl(progress: $progress)
136+
// Enable continuous wrapping (off by default).
137+
.circularControlAllowsWrapping(true)
138+
// Adjust the scale of the interactive knob.
139+
.circularControlKnobScale(2.0)
140+
```
141+
142+
### Progress Updates
143+
144+
You don't have to use the Binding-based initializer to support user interaction. Instead, you may provide an initial value, specify the `isEditable` parameter, and track changes via a closure.
145+
146+
```swift
147+
CircularControl(
148+
progress: progress,
149+
isEditable: true
150+
) { newValue in
151+
print("Progress updated to \(newValue).")
152+
}
153+
```
154+
155+
## Migration
156+
157+
The API surface of PZCircularControl has been completely reworked in 1.0.0 to better match the latest Swift and SwiftUI conventions, support editing, and provide more opportunities for client customization. For details about the legacy API and support for older OS versions, view the section below.
158+
159+
Migration guide:
160+
1. Replace `PZCircularControl` with `CircularControl`.
161+
2. Convert `PZCircularControlParams` to the new style system.
162+
3. Move any overlay views to the new label view builder.
163+
4. Update progress handling to use the new binding-based API.
164+
165+
<details>
166+
167+
<summary>Versions 0.x</summary>
12168

13169
## Usage
14170

@@ -30,7 +186,7 @@ PZCircularControl(
30186

31187
This produces the following output:
32188

33-
![Output Image](https://github.com/philzet/PZCircularControl/blob/master/Resources/Example1.png)
189+
![Output Image](./Resources/old-example-1.png)
34190

35191
The params object's instance data can be modified and animated. For example, the following code animates the control to the 35% state when the button is tapped:
36192

@@ -76,7 +232,7 @@ PZCircularControl(
76232
)
77233
```
78234

79-
![Output Image](https://github.com/philzet/PZCircularControl/blob/master/Resources/Example2.png)
235+
![Output Image](./Resources/old-example-2.png)
80236

81237
## Customization
82238

@@ -93,11 +249,13 @@ Some customization options include:
93249
* `tintColor` – the tint color of the active area of your control. Has to conform to `ShapeStyle` (ie. anything from `Color` to `Gradient`).
94250
* `textFormatter` – an optional closure that takes in a CGFloat value of the current progress between 0.0 and 1.0 and returns formatted text that will be displayed in the center of the progress bar.
95251

252+
</details>
253+
96254
## License
97255

98256
MIT License
99257

100-
Copyright (c) 2019-2021 Phil Zet (a.k.a. Phil Zakharchenko)
258+
Copyright (c) 2019-2024 Phil Zakharchenko
101259

102260
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
103261

Resources/interactive-control.gif

2.34 MB
Loading

Resources/static-progress.gif

685 KB
Loading

0 commit comments

Comments
 (0)