Skip to content

Instantly share code, notes, and snippets.

@coughski
Created June 17, 2024 02:36
Show Gist options
  • Save coughski/2c7f437bb5aac73c38de810ad7a13008 to your computer and use it in GitHub Desktop.
Save coughski/2c7f437bb5aac73c38de810ad7a13008 to your computer and use it in GitHub Desktop.
SwiftUI Mesh Gradient Editor
import SwiftUI
import UniformTypeIdentifiers
struct MeshGradientPoint: Identifiable {
let id = UUID()
var point: SIMD2<Float>
var color: Color
}
struct ContentView: View {
private static let initialPoints: [SIMD2<Float>] = [
[0.0, 0.0], [0.5, 0.0], [1.0, 0.0],
[0.0, 0.5], [0.8, 0.2], [1.0, 0.5],
[0.0, 1.0], [0.5, 1.0], [1.0, 1.0]
]
private static let initialColors: [Color] = [
.black, .black, .black,
.blue, .blue, .blue,
.green, .green, .green
]
@State private var meshPoints = Self.initialPoints.enumerated().map {
MeshGradientPoint(point: $0.1, color: Self.initialColors[$0.0])
}
private let size = CGSize(width: 500, height: 500)
var body: some View {
if #available(iOS 18.0, *) {
VStack(spacing: 64) {
MeshGradient(
width: 3,
height: 3,
points: meshPoints.map(\.point),
colors: meshPoints.map(\.color)
)
.overlay {
ForEach($meshPoints, id: \.id) { meshPoint in
ColorPicker("", selection: meshPoint.color)
.labelsHidden()
.opacity(0.01)
.overlay {
Circle()
.fill(meshPoint.color.wrappedValue.gradient)
.padding(4)
.background {
Circle()
.fill(.white)
}
.allowsHitTesting(false)
}
.shadow(radius: 2, y: 2)
.position(x: CGFloat(meshPoint.point.x.wrappedValue) * size.width, y: CGFloat(meshPoint.point.y.wrappedValue) * size.height)
.gesture(
DragGesture()
.onChanged { gesture in
meshPoint.point.x.wrappedValue = Float(min(max(gesture.location.x, 0.0), size.width) / size.width)
meshPoint.point.y.wrappedValue = Float(min(max(gesture.location.y, 0.0), size.height) / size.height)
}
)
}
}
.frame(width: size.width, height: size.height)
}
} else {
// Fallback on earlier versions
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment