swift - 将先前的视图变量附加到滑块视图?
问题描述
我希望当用户在字段中输入一个值时,滑块然后由该值初始化,每个端都有一个单独的输入:
你会看到我试了一下,在 NozzleNodeView 结构被注释掉之后,滑块 Content2View 结构部分进一步向下有注释:
struct NozzleNodeView: View {
//@State private var mhzValueminus
//@State private var mhzValueplus
@State var diameter = Double()
@State var radicalsize = Double()//Input
@State var radicalcircumference = Double()//Input
@State var radicalarea = Double()//Input
@State var radicalvolume = Double()//Input
@State var circumferencearea = Double()//Input
@State var quartervolume = Double()//Input
@State var circumference = Double()
@State var circlearea = Double()
@State var volume = Double()
@State var spheresurface = Double()
@State var diameterpropagation = Double()
@State var radicalvectordia = Double()//Input
@State var circumferencepropagation = Double()
@State var radicalvectorcir = Double()//Input
@State var circleareapropagation = Double()
@State var radicalvectorareacir = Double()//Input
@State var volumepropagation = Double()
@State var radicalvectorvol = Double()//Input
@State var spheresurfacepropagation = Double()
@State var radicalvectorspheresurface = Double()//Input
@State var nozzlevectordefinition = Double()
@State var nvdefinition = Double()//Input
@State var nozzlevectorscaleplus = Double()
@State var nvdefinitionsp = Double()//Input
@State var nozzlevectorscaleminus = Double()
@State var nvdefinitionsm = Double()//Input
@State var trimdiameter = Double()
@State var trimcircumference = Double()
@State var trimcirclearea = Double()
@State var trimvolume = Double()
@State var trimspheresurface = Double()
@State var trimorbitlocation = Double()
let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .scientific
formatter.positiveFormat = "0.###E+0"
formatter.exponentSymbol = "e"
return formatter
}()
func diameter(diameterresult: Double) -> Double { pow(sqrt(radicalsize * 3), 2) }
func circumference(circumferenceresult: Double) -> Double { pow(pow(sqrt(radicalcircumference * 3), 2), 2) }
func circlearea(circlearearesult: Double) -> Double { pow(pow(sqrt(radicalarea * 3), 2), 3) }
func volume(volumeresult: Double) -> Double { pow(pow(pow(sqrt(radicalvolume * 3), 2), 3), 2) }
func spheresurface(spheresurfaceresult: Double) -> Double{ pow(pow(pow(sqrt(quartervolume * 3), 2), 3), 2) - pow(pow(sqrt(quartervolume * 3), 2), 3) }
func diameterpropagation(diameterpropagationresult: Double) -> Double{ pow(sqrt(radicalvectordia * 3), 2) }
func circumferencepropagation(circumferencepropagationresult: Double) -> Double{ pow(pow(sqrt(radicalvectorcir * 3), 2), 2) }
func circleareapropagation(circleareapropagationresult: Double) -> Double{ pow(pow(pow(sqrt(radicalvectorareacir * 3), 2), 2), 2) }
func volumepropagation(volumepropagationresult: Double) -> Double{ pow(pow(pow(pow(sqrt(radicalvectorvol * 3), 2), 2), 2), 3) }
func spheresurfacepropagation(spheresurfacepropagationresult: Double) -> Double{ pow(pow(pow(pow(sqrt(radicalvectorspheresurface * 3), 2), 2), 2), 3) * (0.25) }
func nozzlevectordefinition(nozzlevectordefinitionresult: Double) -> Double{ pow(pow(pow(pow(sqrt(nvdefinition * 3), 2), 2), 2), 3) * (0.25) / 8 }
func nozzlevectorscaleplus(nozzlevectorscaleplusresult: Double) -> Double{ ((pow(pow(pow(pow(sqrt(nvdefinitionsp * 3), 2), 2), 2), 3)) * (0.25 / 8)) / ((pow(pow(pow(sqrt(nvdefinitionsp * 3), 2), 3), 2)) - (pow(pow(sqrt(nvdefinitionsp * 3), 2), 3))) }
func nozzlevectorscaleminus(nozzlevectorscaleminusresult: Double) -> Double{ ((pow(pow(pow(pow(sqrt(nvdefinitionsm * 3), 2), 2), 2), 3)) * (0.25 / 8)) / ((pow(pow(pow(sqrt(nvdefinitionsm * 3), 2), 3), 2)) - (pow(pow(sqrt(nvdefinitionsm * 3), 2), 3))) }
var body: some View{
VStack(alignment: .center) {
HStack(alignment: .top) {
VStack(alignment: .center) {
ScrollView(.vertical) {
VStack(alignment: .center) {
HStack(alignment: .center) {
Image("CotharticrenArcLakeNozzle300")
.shadow(radius: 3)
}
HStack(alignment: .center) {
Image("NozzleArtemis100")
Text("DART Edge Nozzle")
.font(.largeTitle)
.bold()
.colorInvert()
}
}.padding(.top, 20)
Divider()
HStack(alignment: .top) {
VStack(alignment: .leading) {
Text("Vector Diameter:")
.font(.callout)
.bold()
.colorInvert()
TextField("#", value: self.$radicalvectordia, formatter: formatter)
.colorInvert()
.textFieldStyle(RoundedBorderTextFieldStyle())
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 2)
)
Text("Vector Propagation Diameter : \(diameterpropagation(diameterpropagationresult: radicalvectordia))")
.font(.callout)
.bold()
.frame(width: 150, height: 60, alignment: .leading)
.colorInvert()
}.padding()
Divider()
VStack(alignment: .leading) {
Text("Vector Circumference:")
.font(.callout)
.bold()
.colorInvert()
TextField("#", value: self.$radicalvectorcir, formatter: formatter)
.colorInvert()
.textFieldStyle(RoundedBorderTextFieldStyle())
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 2)
)
Text("Vector Propagation Circumference: \(circumferencepropagation(circumferencepropagationresult: radicalvectorcir))")
.font(.callout)
.bold()
.frame(width: 150, height: 60, alignment: .leading)
.colorInvert()
}.padding()
Divider()
VStack(alignment: .leading) {
Text("Vector Circle Area:")
.font(.callout)
.bold()
.colorInvert()
TextField("#", value: self.$radicalvectorareacir, formatter: formatter)
.colorInvert()
.textFieldStyle(RoundedBorderTextFieldStyle())
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 2)
)
Text("Vector Propagation Circle Area: \(circleareapropagation(circleareapropagationresult: radicalvectorareacir))")
.font(.callout)
.bold()
.frame(width: 150, height: 60, alignment: .leading)
.colorInvert()
}.padding()
Divider()
}
HStack(alignment: .top) {
VStack(alignment: .leading) {
Text("Vector Volume:")
.font(.callout)
.bold()
.colorInvert()
TextField("#", value: self.$radicalvectorvol, formatter: formatter)
.colorInvert()
.textFieldStyle(RoundedBorderTextFieldStyle())
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 2)
)
Text("Vector Propagation Volume : \(volumepropagation(volumepropagationresult: radicalvectorvol))")
.font(.callout)
.bold()
.frame(width: 150, height: 60, alignment: .leading)
.colorInvert()
}.padding()
Divider()
VStack(alignment: .leading) {
Text("Vector Sphere Surface:")
.font(.callout)
.bold()
.colorInvert()
TextField("#", value: self.$radicalvectorspheresurface, formatter: formatter)
.colorInvert()
.textFieldStyle(RoundedBorderTextFieldStyle())
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 2)
)
Text("Vector Propagation Sphere Surface : \(spheresurfacepropagation(spheresurfacepropagationresult: radicalvectorspheresurface))")
.font(.callout)
.bold()
.frame(width: 150, height: 60, alignment: .leading)
.colorInvert()
}.padding()
Divider()
VStack(alignment: .leading) {
Text("Nozzle Vector Definition:")
.font(.callout)
.bold()
.colorInvert()
TextField("#", value: self.$nvdefinition, formatter: formatter)
.colorInvert()
.textFieldStyle(RoundedBorderTextFieldStyle())
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 2)
)
Text("Nozzle vector : \(nozzlevectordefinition(nozzlevectordefinitionresult: nvdefinition))")
.font(.callout)
.bold()
.frame(width: 150, height: 60, alignment: .leading)
.colorInvert()
}.padding()
Divider()
}
HStack(alignment: .top) {
VStack(alignment: .leading) {
Text("Nozzle Scale Plus:")
.font(.callout)
.bold()
.colorInvert()
TextField("#", value: self.$nvdefinitionsp, formatter: formatter)
.colorInvert()
.textFieldStyle(RoundedBorderTextFieldStyle())
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 2)
)
Text("Nozzle Scale : \(nozzlevectorscaleplus(nozzlevectorscaleplusresult: nvdefinition))")
.font(.callout)
.bold()
.frame(width: 150, height: 60, alignment: .leading)
.colorInvert()
}.padding()
Divider()
VStack(alignment: .leading) {
Text("Nozzle Scale Minus:")
.font(.callout)
.bold()
.colorInvert()
TextField("#", value: self.$nvdefinitionsm, formatter: formatter)
.colorInvert()
.textFieldStyle(RoundedBorderTextFieldStyle())
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 2)
)
Text("Nozzle Scale : \(nozzlevectorscaleminus(nozzlevectorscaleminusresult: nvdefinitionsm))")
.font(.callout)
.bold()
.frame(width: 150, height: 60, alignment: .leading)
.colorInvert()
}.padding()
Divider()
}
}
}
}
}.frame(width: 900, height: 800, alignment: .center)
.background(Color.white)
Spacer()
}
}
@propertyWrapper
struct SliderValue {
var value: Double
init(wrappedValue: Double) {
self.value = wrappedValue
}
var wrappedValue: Double {
get { value }
set { value = min(max(0.0, newValue), 1.0) }
}
}
class SliderHandle: ObservableObject {
//Slider Size
let sliderWidth: CGFloat
let sliderHeight: CGFloat
//Slider Range
let sliderValueStart: Double
let sliderValueRange: Double
//Slider Handle
var diameter: CGFloat = 40
var startLocation: CGPoint
//Current Value
@Published var currentPercentage: SliderValue
//Slider Button Location
@Published var onDrag: Bool
@Published var currentLocation: CGPoint
init(sliderWidth: CGFloat, sliderHeight: CGFloat, sliderValueStart: Double, sliderValueEnd: Double, startPercentage: SliderValue) {
self.sliderWidth = sliderWidth
self.sliderHeight = sliderHeight
self.sliderValueStart = sliderValueStart
self.sliderValueRange = sliderValueEnd - sliderValueStart
let startLocation = CGPoint(x: (CGFloat(startPercentage.wrappedValue)/1.0)*sliderWidth, y: sliderHeight/2)
self.startLocation = startLocation
self.currentLocation = startLocation
self.currentPercentage = startPercentage
self.onDrag = false
}
lazy var sliderDragGesture: _EndedGesture<_ChangedGesture<DragGesture>> = DragGesture()
.onChanged { value in
self.onDrag = true
let dragLocation = value.location
//Restrict possible drag area
self.restrictSliderBtnLocation(dragLocation)
//Get current value
self.currentPercentage.wrappedValue = Double(self.currentLocation.x / self.sliderWidth)
}.onEnded { _ in
self.onDrag = false
}
private func restrictSliderBtnLocation(_ dragLocation: CGPoint) {
//On Slider Width
if dragLocation.x > CGPoint.zero.x && dragLocation.x < sliderWidth {
calcSliderBtnLocation(dragLocation)
}
}
private func calcSliderBtnLocation(_ dragLocation: CGPoint) {
if dragLocation.y != sliderHeight/2 {
currentLocation = CGPoint(x: dragLocation.x, y: sliderHeight/2)
} else {
currentLocation = dragLocation
}
}
//Current Value
var currentValue: Double {
return sliderValueStart + currentPercentage.wrappedValue * sliderValueRange
}
}
class CustomSlider: ObservableObject {
//Slider Size
final let width: CGFloat = 300
final let lineWidth: CGFloat = 8
//Slider value range from valueStart to valueEnd
final let valueStart: Double
final let valueEnd: Double
//Slider Handle
@Published var highHandle: SliderHandle
@Published var lowHandle: SliderHandle
//Handle start percentage (also for starting point)@Binding var mhzValue: Float
@SliderValue var highHandleStartPercentage = 1.0
@SliderValue var lowHandleStartPercentage = 0.0
final var anyCancellableHigh: AnyCancellable?
final var anyCancellableLow: AnyCancellable?
init(start: Double, end: Double) {
valueStart = start
valueEnd = end
highHandle = SliderHandle(sliderWidth: width,
sliderHeight: lineWidth,
sliderValueStart: valueStart,
sliderValueEnd: valueEnd,
startPercentage: _highHandleStartPercentage
)
lowHandle = SliderHandle(sliderWidth: width,
sliderHeight: lineWidth,
sliderValueStart: valueStart,
sliderValueEnd: valueEnd,
startPercentage: _lowHandleStartPercentage
)
anyCancellableHigh = highHandle.objectWillChange.sink { _ in
self.objectWillChange.send()
}
anyCancellableLow = lowHandle.objectWillChange.sink { _ in
self.objectWillChange.send()
}
}
//Percentages between high and low handle
var percentagesBetween: String {
return String(format: "%.2f", highHandle.currentPercentage.wrappedValue - lowHandle.currentPercentage.wrappedValue)
}
//Value between high and low handle
var valueBetween: String {
return String(format: "%.2f", highHandle.currentValue - lowHandle.currentValue)
}
}
struct Content2View: View {
//@Binding var mhzValueplus: nvdefintionsm
//@Binding var mhzValueminus: nvdefintionsp
@ObservedObject var slider = CustomSlider(start: 0/*self.$mhzValueplus*/, end: 100/*self.$mhzValueminus*/)
var body: some View {
VStack(alignment: .leading) {
Text("Value: " + slider.valueBetween)
.font(.callout)
.bold()
.frame(width: 300, height: 30, alignment: .leading)
.colorInvert()
Text("Percentages: " + slider.percentagesBetween)
.font(.callout)
.bold()
.frame(width: 300, height: 30, alignment: .leading)
.colorInvert()
Text("High Value: \(slider.highHandle.currentValue)")
.font(.callout)
.bold()
.frame(width: 300, height: 30, alignment: .leading)
.colorInvert()
Text("Low Value: \(slider.lowHandle.currentValue)")
.font(.callout)
.bold()
.frame(width: 300, height: 30, alignment: .leading)
.colorInvert()
.padding(.bottom, 30)
//Slider
SliderView(slider: slider)
}.padding(.top, 20).padding(.bottom, 50).frame(width: 400, height: 250, alignment: .center).overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 2)
).shadow(radius: 3)
Spacer()
}
}
struct SliderView: View {
@ObservedObject var slider: CustomSlider
var body: some View {
RoundedRectangle(cornerRadius: slider.lineWidth)
.fill(Color.blue.opacity(0.2))
.frame(width: slider.width, height: slider.lineWidth)
.overlay(
ZStack {
//Path between both handles
SliderPathBetweenView(slider: slider)
//Low Handle
SliderHandleView(handle: slider.lowHandle)
.highPriorityGesture(slider.lowHandle.sliderDragGesture)
//High Handle
SliderHandleView(handle: slider.highHandle)
.highPriorityGesture(slider.highHandle.sliderDragGesture)
}
)
}
}
struct SliderHandleView: View {
@ObservedObject var handle: SliderHandle
var body: some View {
Circle()
.frame(width: handle.diameter, height: handle.diameter)
.foregroundColor(.white)
.shadow(color: Color.black.opacity(0.15), radius: 8, x: 0, y: 0)
.scaleEffect(handle.onDrag ? 1.3 : 1)
.contentShape(Rectangle())
.position(x: handle.currentLocation.x, y: handle.currentLocation.y)
}
}
struct SliderPathBetweenView: View {
@ObservedObject var slider: CustomSlider
var body: some View {
Path { path in
path.move(to: slider.lowHandle.currentLocation)
path.addLine(to: slider.highHandle.currentLocation)
}
.stroke(Color.green, lineWidth: slider.lineWidth)
}
}
解决方案
推荐阅读
- css - 为什么媒体查询在具有相同分辨率的不同网站响应测试中显示不同的外观
- angular - 我想实现,使用自调用组件的层次结构,是否需要在AppModule中声明?
- react-native - 如何通过 Expo 获取 FB Access Token
- android - arm-linux-androideabi-ld.exe 找不到 -lrtlhelper
- spring-boot - 当没有请求视图时,Spring 将用户发送到视图
- java - 如何在 mac osx 上的 Visual Studio 代码中运行 Java 代码?
- asp.net - 如何使用我的主网站的 URL(或 IP)访问我的临时第二个网站
- python - Pandas Dataframe 创建一个独特的列
- database - 数据库 - 多语言在线词典
- java - 无法查看 SQLite 数据库中保存的数据