Created
June 29, 2024 11:13
-
-
Save Koshimizu-Takehito/2253fcba7a2c817131969fd69ba4bb12 to your computer and use it in GitHub Desktop.
MeshGradient サンプル
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct ContentView: View { | |
@State var id = UUID() | |
@State var offset = CGSize.zero | |
@State var control = SIMD2<Float>(0, 0) | |
var body: some View { | |
GeometryReader { geometry in | |
let size = geometry.size | |
let offset = SIMD2(offset/size) | |
ZStack { | |
MeshGradient( | |
width: 3, | |
height: 3, | |
points: [ | |
[0.0, 0.0], [0.5, 0.0], [1.0, 0.0], | |
[0.0, 0.5], [0.5, 0.5] + control + offset, [1.0, 0.5], | |
[0.0, 1.0], [0.5, 1.0], [1.0, 1.0] | |
], | |
colors: [ | |
.black, .black, .black, | |
.blue, .blue, .blue, | |
.green, .green, .green, | |
] | |
) | |
Dot( | |
id: id, | |
radius: min(size.width, size.height)/10, | |
currentOffset: $offset | |
) | |
.offset(x: Double(control.x) * size.width, y: Double(control.y) * size.height) | |
VStack { | |
HStack { | |
Spacer() | |
Button("Reset") { | |
withAnimation { | |
self.id = .init() | |
self.control = .zero | |
self.offset = .zero | |
} | |
} | |
.foregroundStyle(.white) | |
.fontWeight(.semibold) | |
} | |
Spacer() | |
Slider(value: $control.x, in: (-(0.5 + offset.x)...(0.5 - offset.x))) | |
Slider(value: $control.y, in: (-(0.5 + offset.y)...(0.5 - offset.y))) | |
} | |
.padding() | |
.padding() | |
} | |
.ignoresSafeArea() | |
} | |
} | |
} | |
struct Dot: View { | |
let id: UUID | |
let radius: Double | |
@State private var offsets = (dragging: CGSize.zero, last: CGSize.zero) | |
@Binding var currentOffset: CGSize | |
var body: some View { | |
Circle() | |
.frame(width: radius) | |
.foregroundStyle(.white.opacity(1/1024)) | |
.gesture( | |
DragGesture() | |
.onChanged { | |
offsets.dragging = $0.translation | |
currentOffset = offsets.last + offsets.dragging | |
} | |
.onEnded { _ in | |
offsets.last += offsets.dragging | |
offsets.dragging = .zero | |
currentOffset = offsets.last + offsets.dragging | |
} | |
) | |
.offset(offsets.last) | |
.background { | |
Circle() | |
.frame(width: radius) | |
.foregroundStyle(.orange.mix(with: .pink, by: 0.45)) | |
.offset(currentOffset) | |
} | |
.onChange(of: id) { _, _ in | |
offsets = (.zero, .zero) | |
} | |
} | |
} | |
extension CGSize { | |
static func+(_ lhs: Self, _ rhs: Self) -> Self { | |
self.init(width: lhs.width + rhs.width, height: lhs.height + rhs.height) | |
} | |
static func-(_ lhs: Self, _ rhs: Self) -> Self { | |
self.init(width: lhs.width - rhs.width, height: lhs.height - rhs.height) | |
} | |
static func/(_ lhs: Self, _ rhs: Self) -> Self { | |
self.init(width: lhs.width / rhs.width, height: lhs.height / rhs.height) | |
} | |
static func*(_ lhs: CGFloat, _ rhs: Self) -> Self { | |
self.init(width: lhs * rhs.width, height: lhs * rhs.height) | |
} | |
static func+=(lhs: inout Self, rhs: Self) { | |
lhs = lhs + rhs | |
} | |
} | |
extension SIMD2<Float> { | |
init(_ v: CGSize) { | |
self.init(x: Float(v.width), y: Float(v.height)) | |
} | |
} | |
#Preview { | |
ContentView() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment