Skip to content

Commit a4a6af4

Browse files
committed
Add support for multiple glass shapes and new samples
Introduces a new GlassShape enum to support rounded rectangle, circle, and capsule shapes in the glass effect. Refactors GlassBackgroundModifier to handle shape selection and updates the glass() View extension accordingly. Adds new sample views for Capsule and Circle glass effects, updates advanced samples for better code reuse, and documents shape support in the README. Bumps project and marketing versions, and updates the Swift tools version to 5.9.
1 parent 04a4ced commit a4a6af4

File tree

9 files changed

+407
-106
lines changed

9 files changed

+407
-106
lines changed

Demo/Demo.xcodeproj/project.pbxproj

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@
653653
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
654654
CODE_SIGN_ENTITLEMENTS = Demo/Demo.entitlements;
655655
CODE_SIGN_STYLE = Automatic;
656-
CURRENT_PROJECT_VERSION = 11;
656+
CURRENT_PROJECT_VERSION = 12;
657657
DEVELOPMENT_TEAM = "";
658658
ENABLE_PREVIEWS = YES;
659659
GENERATE_INFOPLIST_FILE = YES;
@@ -673,7 +673,7 @@
673673
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
674674
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
675675
MACOSX_DEPLOYMENT_TARGET = 14.0;
676-
MARKETING_VERSION = 1.9.1;
676+
MARKETING_VERSION = 26.0;
677677
PRODUCT_BUNDLE_IDENTIFIER = media.1998.Demo;
678678
PRODUCT_NAME = "$(TARGET_NAME)";
679679
REGISTER_APP_GROUPS = YES;
@@ -695,7 +695,7 @@
695695
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
696696
CODE_SIGN_ENTITLEMENTS = Demo/Demo.entitlements;
697697
CODE_SIGN_STYLE = Automatic;
698-
CURRENT_PROJECT_VERSION = 11;
698+
CURRENT_PROJECT_VERSION = 12;
699699
DEVELOPMENT_TEAM = "";
700700
ENABLE_PREVIEWS = YES;
701701
GENERATE_INFOPLIST_FILE = YES;
@@ -715,7 +715,7 @@
715715
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
716716
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
717717
MACOSX_DEPLOYMENT_TARGET = 14.0;
718-
MARKETING_VERSION = 1.9.1;
718+
MARKETING_VERSION = 26.0;
719719
PRODUCT_BUNDLE_IDENTIFIER = media.1998.Demo;
720720
PRODUCT_NAME = "$(TARGET_NAME)";
721721
REGISTER_APP_GROUPS = YES;
@@ -822,7 +822,7 @@
822822
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
823823
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
824824
CODE_SIGN_STYLE = Automatic;
825-
CURRENT_PROJECT_VERSION = 10;
825+
CURRENT_PROJECT_VERSION = 12;
826826
DEVELOPMENT_TEAM = "";
827827
ENABLE_PREVIEWS = YES;
828828
GENERATE_INFOPLIST_FILE = YES;
@@ -833,7 +833,7 @@
833833
"$(inherited)",
834834
"@executable_path/Frameworks",
835835
);
836-
MARKETING_VERSION = 1.8.0;
836+
MARKETING_VERSION = 26.0;
837837
PRODUCT_BUNDLE_IDENTIFIER = media.1998.Demo.watchkitapp;
838838
PRODUCT_NAME = "$(TARGET_NAME)";
839839
SDKROOT = watchos;
@@ -851,7 +851,7 @@
851851
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
852852
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
853853
CODE_SIGN_STYLE = Automatic;
854-
CURRENT_PROJECT_VERSION = 10;
854+
CURRENT_PROJECT_VERSION = 12;
855855
DEVELOPMENT_TEAM = "";
856856
ENABLE_PREVIEWS = YES;
857857
GENERATE_INFOPLIST_FILE = YES;
@@ -862,7 +862,7 @@
862862
"$(inherited)",
863863
"@executable_path/Frameworks",
864864
);
865-
MARKETING_VERSION = 1.8.0;
865+
MARKETING_VERSION = 26.0;
866866
PRODUCT_BUNDLE_IDENTIFIER = media.1998.Demo.watchkitapp;
867867
PRODUCT_NAME = "$(TARGET_NAME)";
868868
SDKROOT = watchos;

Demo/Demo/Samples/Advanced/GlassFlower/GlassFlower.swift

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,32 +32,7 @@ struct GlassFlower: View {
3232
// Flower petals: Eight capsules arranged in a circle pattern
3333
// Each petal is a gradient-filled capsule with glass effect applied
3434
ForEach(0..<8, id: \.self) { index in
35-
Capsule()
36-
.fill(
37-
LinearGradient(
38-
gradient: Gradient(stops: [
39-
.init(color: colors[index % colors.count], location: 0),
40-
.init(color: colors[index % colors.count].opacity(0.5), location: 1)
41-
]),
42-
startPoint: .bottom,
43-
endPoint: .top
44-
)
45-
)
46-
47-
// Apply glass effect from SwiftGlass library to create translucent look
48-
.glass(color: colors[index % colors.count], colorOpacity: 1, shadowColor: .white)
49-
50-
.frame(width: 55, height: 100) // Petal dimensions
51-
.offset(x: 0, y: 0) // Position petals away from center
52-
.rotationEffect(.degrees(Double(index) * 45), anchor: .bottom) // Distribute evenly in 360° (8×45°)
53-
.offset(y: -50) // Adjust vertical position of entire flower
54-
.scaleEffect(isPulsing ? 0.97 : 1.05) // Size animation range
55-
.animation(
56-
Animation.easeInOut(duration: 2.0)
57-
.delay(Double(index) * 0.1) // Staggered animation for flowing effect
58-
.repeatForever(autoreverses: true),
59-
value: isPulsing
60-
)
35+
petalView(for: index)
6136
}
6237
}
6338
.frame(width: 300, height: 300)
@@ -66,6 +41,33 @@ struct GlassFlower: View {
6641
isPulsing.toggle()
6742
}
6843
}
44+
45+
@ViewBuilder
46+
private func petalView(for index: Int) -> some View {
47+
let color = colors[index % colors.count]
48+
let gradient = LinearGradient(
49+
gradient: Gradient(stops: [
50+
.init(color: color, location: 0),
51+
.init(color: color.opacity(0.5), location: 1)
52+
]),
53+
startPoint: .bottom,
54+
endPoint: .top
55+
)
56+
let rotation = Double(index) * 45
57+
let animation = Animation.easeInOut(duration: 2.0)
58+
.delay(Double(index) * 0.1)
59+
.repeatForever(autoreverses: true)
60+
61+
Capsule()
62+
.fill(gradient)
63+
.glass(color: color, colorOpacity: 1, shadowColor: .white)
64+
.frame(width: 55, height: 100)
65+
.offset(x: 0, y: 0)
66+
.rotationEffect(.degrees(rotation), anchor: .bottom)
67+
.offset(y: -50)
68+
.scaleEffect(isPulsing ? 0.97 : 1.05)
69+
.animation(animation, value: isPulsing)
70+
}
6971
}
7072

7173
// MARK: - Previews

Demo/Demo/Samples/Advanced/GlassFlower/GlassFlowerRotate.swift

Lines changed: 49 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -34,62 +34,65 @@ struct GlassFlowerRotate: View {
3434
// Flower petals: Eight capsules arranged in a circle pattern
3535
// Each petal is a gradient-filled capsule with glass effect applied
3636
ForEach(0..<8, id: \.self) { index in
37-
Capsule()
38-
.fill(
39-
LinearGradient(
40-
gradient: Gradient(stops: [
41-
.init(color: colors[index % colors.count], location: 0),
42-
.init(color: colors[index % colors.count].opacity(0.5), location: 1)
43-
]),
44-
startPoint: .bottom,
45-
endPoint: .top
46-
)
47-
)
48-
49-
// Apply glass effect from SwiftGlass library to create translucent look
50-
.glass(color: colors[index % colors.count], colorOpacity: 1, shadowColor: .white)
51-
52-
.frame(width: 55, height: 100) // Petal dimensions
53-
.offset(x: 0, y: 0) // Position petals away from center
54-
.rotationEffect(.degrees(Double(index) * 45), anchor: .bottom) // Distribute evenly in 360° (8×45°)
55-
.rotationEffect(rotateToCenter ? .degrees(720) : .degrees(0), anchor: .bottom) // Rotate petals to face center when activated
56-
.offset(y: -50) // Adjust vertical position of entire flower
57-
.scaleEffect(isPulsing ? 0.97 : 1.05) // Size animation range
58-
.animation(
59-
Animation.easeInOut(duration: 2.0)
60-
.delay(Double(index) * 0.1) // Staggered animation for flowing effect
61-
.repeatForever(autoreverses: true),
62-
value: isPulsing
63-
)
64-
.animation(
65-
Animation.easeInOut(duration: 3.5)
66-
.delay(Double(index) * 0.15), // Slightly staggered rotation
67-
value: rotateToCenter
68-
)
37+
petalView(for: index)
6938
}
7039

7140
// Button to toggle rotation to center
72-
Button(action: {
73-
withAnimation {
74-
rotateToCenter.toggle()
75-
}
76-
}) {
77-
Text(rotateToCenter ? "Reset Rotation" : "Rotate to Center")
78-
.foregroundColor(.white)
79-
.padding(15)
80-
}
81-
.cornerRadius(8)
82-
83-
.glass(color: .blue, shadowColor: .blue)
84-
85-
.offset(y: 240) // Position button below the flower
41+
rotationButton
8642
}
8743
.frame(width: 300, height: 300)
8844
// Start the pulsing animation when view appears
8945
.onAppear {
9046
isPulsing.toggle()
9147
}
9248
}
49+
50+
@ViewBuilder
51+
private func petalView(for index: Int) -> some View {
52+
let color = colors[index % colors.count]
53+
let gradient = LinearGradient(
54+
gradient: Gradient(stops: [
55+
.init(color: color, location: 0),
56+
.init(color: color.opacity(0.5), location: 1)
57+
]),
58+
startPoint: .bottom,
59+
endPoint: .top
60+
)
61+
let baseRotation = Double(index) * 45
62+
let centerRotation = rotateToCenter ? 720.0 : 0.0
63+
let pulseAnimation = Animation.easeInOut(duration: 2.0)
64+
.delay(Double(index) * 0.1)
65+
.repeatForever(autoreverses: true)
66+
let rotateAnimation = Animation.easeInOut(duration: 3.5)
67+
.delay(Double(index) * 0.15)
68+
69+
Capsule()
70+
.fill(gradient)
71+
.glass(color: color, colorOpacity: 1, shadowColor: .white)
72+
.frame(width: 55, height: 100)
73+
.offset(x: 0, y: 0)
74+
.rotationEffect(.degrees(baseRotation), anchor: .bottom)
75+
.rotationEffect(.degrees(centerRotation), anchor: .bottom)
76+
.offset(y: -50)
77+
.scaleEffect(isPulsing ? 0.97 : 1.05)
78+
.animation(pulseAnimation, value: isPulsing)
79+
.animation(rotateAnimation, value: rotateToCenter)
80+
}
81+
82+
private var rotationButton: some View {
83+
Button(action: {
84+
withAnimation {
85+
rotateToCenter.toggle()
86+
}
87+
}) {
88+
Text(rotateToCenter ? "Reset Rotation" : "Rotate to Center")
89+
.foregroundColor(.white)
90+
.padding(15)
91+
}
92+
.cornerRadius(8)
93+
.glass(color: .blue, shadowColor: .blue)
94+
.offset(y: 240)
95+
}
9396
}
9497

9598
// MARK: - Previews
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//
2+
// Capsule.swift
3+
// Demo
4+
//
5+
// Created by Ming on 22/4/2025.
6+
//
7+
8+
import SwiftUI
9+
import SwiftGlass
10+
11+
struct CapsuleGlass: View {
12+
var body: some View {
13+
ZStack {
14+
#if !os(visionOS) && !os(watchOS) && !os(macOS)
15+
background
16+
#endif
17+
18+
VStack(spacing: 30) {
19+
// Capsule shape example
20+
HStack {
21+
Image(systemName: "capsule.fill")
22+
.font(.title2)
23+
Text("Capsule Glass")
24+
.font(.headline)
25+
}
26+
.foregroundStyle(.white)
27+
.padding(.horizontal, 30)
28+
.padding(.vertical, 15)
29+
.glass(shape: .capsule, color: .purple, shadowColor: .purple)
30+
31+
// Multiple capsules with different styles
32+
VStack(spacing: 20) {
33+
Button(action: {}) {
34+
HStack {
35+
Image(systemName: "play.fill")
36+
Text("Play Music")
37+
}
38+
.foregroundStyle(.white)
39+
.padding(.horizontal, 25)
40+
.padding(.vertical, 12)
41+
}
42+
.glass(shape: .capsule, color: .blue, shadowColor: .blue)
43+
44+
Button(action: {}) {
45+
HStack {
46+
Image(systemName: "pause.fill")
47+
Text("Pause")
48+
}
49+
.foregroundStyle(.white)
50+
.padding(.horizontal, 25)
51+
.padding(.vertical, 12)
52+
}
53+
.glass(shape: .capsule, color: .orange, shadowColor: .orange)
54+
55+
Button(action: {}) {
56+
HStack {
57+
Image(systemName: "stop.fill")
58+
Text("Stop")
59+
}
60+
.foregroundStyle(.white)
61+
.padding(.horizontal, 25)
62+
.padding(.vertical, 12)
63+
}
64+
.glass(shape: .capsule, color: .red, shadowColor: .red)
65+
}
66+
67+
// Horizontal capsule badges
68+
HStack(spacing: 15) {
69+
Text("New")
70+
.font(.caption.bold())
71+
.foregroundStyle(.white)
72+
.padding(.horizontal, 12)
73+
.padding(.vertical, 6)
74+
.glass(shape: .capsule, color: .green, shadowColor: .green)
75+
76+
Text("Hot")
77+
.font(.caption.bold())
78+
.foregroundStyle(.white)
79+
.padding(.horizontal, 12)
80+
.padding(.vertical, 6)
81+
.glass(shape: .capsule, color: .red, shadowColor: .red)
82+
83+
Text("Sale")
84+
.font(.caption.bold())
85+
.foregroundStyle(.white)
86+
.padding(.horizontal, 12)
87+
.padding(.vertical, 6)
88+
.glass(shape: .capsule, color: .yellow, shadowColor: .yellow)
89+
}
90+
}
91+
#if !os(watchOS)
92+
.padding(25)
93+
#else
94+
.padding(15)
95+
#endif
96+
}
97+
}
98+
99+
// Add a background for better looking
100+
var background: some View {
101+
Group {
102+
Color.black
103+
.ignoresSafeArea()
104+
105+
AsyncImage(url: URL(string: "https://shareby.vercel.app/3vj7gk")) { image in
106+
image
107+
.resizable()
108+
.scaledToFill()
109+
} placeholder: {
110+
ProgressView()
111+
}.opacity(0.3)
112+
.ignoresSafeArea()
113+
}
114+
}
115+
}
116+
117+
#Preview("Light") {
118+
CapsuleGlass()
119+
}
120+
121+
#Preview("Dark") {
122+
CapsuleGlass()
123+
.preferredColorScheme(.dark)
124+
}
125+

0 commit comments

Comments
 (0)