I am making a UI to change the 3D coordinates of an object, and I thought it would make sense to put all three on the same line with a label beforehand, sort of like System Preferences does for number separators :
However, doing so messes up the alignment of the whole form, and I'm not sure how to resolve this (except by adding VStack
s and HStack
s everywhere, which I really hope is not the best available solution) :
Here is the code driving the view :
struct ObjectSettingsView: View {
@State var object : Object
var body : some View {
Form {
TextField("Name:", text: $object.name, prompt : Text("New Object"))
Toggle(
"Visible",
isOn: $object.visible
)
Divider()
HStack {
Text("Coordinates:")
NumberView(label : "X:", number : object.coordinates.x)
NumberView(label : "Y:", number : object.coordinates.y)
NumberView(label : "Z:", number : object.coordinates.z)
}
}
}
}
struct NumberView : View{
var label : String
@State var number : Int32
var body : some View {
HStack {
TextField(
self.label,
value: self.$number,
formatter: NumberFormatter()
)
Stepper("", value: self.$number, in: 1...8)
.labelsHidden()
}
}
}
( I know this really should be using a ViewModel
, I'm just trying to figure out how forms work right now )
CodePudding user response:
I add @Binding and LazyVGrid to your Code.
Maybe this helps:
struct ObjectData {
var name: String = "New Object"
var visible: Bool = true
var coordinates_x: Int32 = 0
var coordinates_y: Int32 = 0
var coordinates_z: Int32 = 0
}
struct ContentView: View {
@State var data = ObjectData()
let columns = [
GridItem(alignment: .trailing),
GridItem(alignment: .leading),
]
var form: some View {
Form {
LazyVGrid(columns: columns) {
Text("Name:")
TextField("", text: $data.name)
.frame(width: 200.0)
Text("Visible:")
HStack {
Text("").frame(width: 3.0)
Toggle("", isOn: $data.visible)
}
Text("Coordinates:")
HStack {
NumberView(label : "X:", number : $data.coordinates_x)
NumberView(label : "Y:", number : $data.coordinates_y)
NumberView(label : "Z:", number : $data.coordinates_z)
}
}
}
.padding(.all)
}
var body : some View {
VStack {
form
Text(" --- Check --- ")
Text(String(describing: data))
}
}
}
struct NumberView : View{
var label : String
@Binding var number : Int32
var body : some View {
HStack {
Spacer()
TextField(
self.label,
value: self.$number,
formatter: NumberFormatter()
)
Stepper("", value: self.$number, in: 1...8)
.labelsHidden()
}
.frame(width: 80.0)
}
}
CodePudding user response:
Separating things into two Form
s almost does the trick, although labels are still not exactly aligned as in system Preferences :
struct ObjectSettingsView: View {
@State var object : Object
var body : some View {
VStack {
Form {
TextField("Name:", text: $object.name, prompt : Text("New Object"))
Toggle("Visible", isOn: $object.visible)
}
Divider()
Form {
HStack {
Text("Coordinates:")
NumberView(label : "X:", number : object.coordinates.x)
NumberView(label : "Y:", number : object.coordinates.y)
NumberView(label : "Z:", number : object.coordinates.z)
}
}
}
.padding()
}
}