相干波 swift
时间: 2025-07-13 08:13:54
I'll help you restructure your code to separate the controls from the GeometryReader and create a cleaner architecture. Here's the improved version:
struct WaveInterference2View: View {
@State private var isAnimating = false
@State private var elapsedTime: Double = 0
@State private var showLeftWave = true
@State private var showRightWave = true
@State private var showCombinedWave = true
@State private var showMarkers = true
// Wave parameters
private let amplitude: CGFloat = 40
private let frequency: CGFloat = 0.05
private let waveSpeed: CGFloat = 100
private let unit: CGFloat = 100
// Timer for animation
private let timer = Timer.publish(every: 0.016, on: .main, in: .common).autoconnect()
var body: some View {
VStack {
// Wave display view - now self-contained
WaveDisplayView(
isAnimating: $isAnimating,
elapsedTime: $elapsedTime,
showLeftWave: $showLeftWave,
showRightWave: $showRightWave,
showCombinedWave: $showCombinedWave,
showMarkers: $showMarkers,
amplitude: amplitude,
frequency: frequency,
waveSpeed: waveSpeed,
unit: unit
)
.aspectRatio(1.5, contentMode: .fit)
.padding()
// Controls view - now separate component
ControlsView(
isAnimating: $isAnimating,
elapsedTime: $elapsedTime,
showLeftWave: $showLeftWave,
showRightWave: $showRightWave,
showCombinedWave: $showCombinedWave,
showMarkers: $showMarkers
)
.padding()
}
.navigationTitle("Wave Interference 2")
.onReceive(timer) { _ in
if isAnimating {
elapsedTime += 0.016
}
}
}
}
// MARK: - Subviews
struct WaveDisplayView: View {
@Binding var isAnimating: Bool
@Binding var elapsedTime: Double
@Binding var showLeftWave: Bool
@Binding var showRightWave: Bool
@Binding var showCombinedWave: Bool
@Binding var showMarkers: Bool
let amplitude: CGFloat
let frequency: CGFloat
let waveSpeed: CGFloat
let unit: CGFloat
var body: some View {
GeometryReader { geometry in
let width = geometry.size.width
let height = geometry.size.height
let centerY = height / 2
let yAxis = width / 8
ZStack {
// Draw axes and grid
drawAxes(width: width, height: height, yAxis: yAxis)
if showLeftWave {
drawWave(
startX: 0,
endX: width,
amplitude: amplitude,
frequency: frequency,
phase: elapsedTime * Double(waveSpeed),
offset: 0,
color: .blue,
direction: .right,
width: width,
centerY: centerY
)
}
if showRightWave {
drawWave(
startX: 0,
endX: width,
amplitude: amplitude,
frequency: frequency,
phase: elapsedTime * Double(waveSpeed),
offset: 0,
color: .green,
direction: .left,
width: width,
centerY: centerY
)
}
if showCombinedWave {
drawCombinedWave(
width: width,
height: height,
amplitude: amplitude,
frequency: frequency,
phase: elapsedTime * Double(waveSpeed),
centerY: centerY
)
}
if showMarkers {
drawMarkers(width: width, height: height, yAxis: yAxis)
}
}
}
}
// All the drawing methods remain the same as in your original code
// (drawAxes, drawWave, drawCombinedWave, drawMarkers)
}
struct ControlsView: View {
@Binding var isAnimating: Bool
@Binding var elapsedTime: Double
@Binding var showLeftWave: Bool
@Binding var showRightWave: Bool
@Binding var showCombinedWave: Bool
@Binding var showMarkers: Bool
var body: some View {
VStack(spacing: 15) {
HStack(spacing: 20) {
Button(action: {
isAnimating = true
elapsedTime = 0
}) {
Text("Start")
.frame(width: 100)
.padding()
.background(isAnimating ? Color.gray : Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
.disabled(isAnimating)
Button(action: {
isAnimating = false
}) {
Text("Stop")
.frame(width: 100)
.padding()
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(8)
}
Button(action: {
isAnimating = false
elapsedTime = 0
}) {
Text("Reset")
.frame(width: 100)
.padding()
.background(Color.orange)
.foregroundColor(.white)
.cornerRadius(8)
}
}
VStack(spacing: 10) {
Toggle("Left Wave (Blue)", isOn: $showLeftWave)
Toggle("Right Wave (Green)", isOn: $showRightWave)
Toggle("Combined Wave (Red)", isOn: $showCombinedWave)
Toggle("Show Markers", isOn: $showMarkers)
}
.padding(.horizontal)
}
}
}
// Keep the WaveDirection enum and preview providerKey improvements:
1. Separated Concerns:
- WaveDisplayView handles all the wave rendering
- ControlsView handles all the user controls
- Main view just coordinates between them
2. Better Architecture:
- Each component has a single responsibility
- Clear data flow through bindings
- Easier to maintain and modify
3. Reusability:
- Components can now be reused in other parts of your app
- Easier to test components independently
4. Readability:
- Shorter, more focused files
- Clear separation of concerns
The drawing methods (drawAxes, drawWave, etc.) would remain exactly the same as in your original code, just moved into the WaveDisplayView struct.
This structure makes your code:
- More maintainable
- Easier to debug
- More flexible for future changes
- More testable
- More reusable
You can further break it down if needed (like extracting the button styles into their own views), but this is a good starting point for separation of concerns.
