I have a View where I take input from the user. Once they click the Calculate button, I'll run a function to calculate the results and display the results below the Calculate button. What I would like to see is the results section to scroll up after the user clicks the Calculate button.
I tried to use ScrollViewReader but I don't know how to implement it in this case.
Here is my code:
import SwiftUI
enum ParameterType: String, CaseIterable, Identifiable {
case Mean, Proportion
var id: Self { self }
}
struct confidenceValue: Identifiable {
var id: Int
var name: String
var dispName: String
var isSelected: Bool = false
var relCoeff: String = ""
var level: Int
}
extension View {
//Hide Keyboard
func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
struct ContentView: View {
@State var inputtext: String = ""
@State var standardDeviation: String = "12"
@State var marginofError: String = "8"
@State var proportiondata: String = "0.5"
@State var proportionME: String = "0.1"
@State var showResults: Bool = false
@State private var selectedParameterType: ParameterType = .Mean
@State private var selectedInterval = 1
@State var confidenceValues:[confidenceValue] = [confidenceValue(id: 1, name: "0.90", dispName: "90%", isSelected: true, relCoeff: "1.645", level: 0),confidenceValue(id: 2, name: "0.95", dispName: "95%", isSelected: true, relCoeff: "1.96", level: 1),confidenceValue(id: 3, name: "0.99", dispName: "99%" , isSelected: true, relCoeff: "2.575", level: 2)
]
var body: some View {
ScrollViewReader { proxy in
NavigationView {
Form {
//Number of Samples - One or Two samples
Section(header: Text("Parameter of Interest")) {
Picker("ParameterType", selection: $selectedParameterType) {
Text("Population Mean").tag(ParameterType.Mean)
Text("Population Proportion").tag(ParameterType.Proportion)
}
.pickerStyle(SegmentedPickerStyle())
//Text("selected parameter is : \(selectedParameterType.rawValue)")
//.onChange(of: selectedParameterType, ParameterTypeOnChange())
} //Section
if (selectedParameterType.rawValue == "Mean") {
//This section is applicable only for Population Mean
Section(header: Text("Enter Values")) {
HStack (alignment: .center) {
Text("Population Std. Dev(σ)")
.font(.callout)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer(minLength: /*@START_MENU_TOKEN@*/0/*@END_MENU_TOKEN@*/)
Divider()
TextField("Std. Deviation:", text: $standardDeviation)
} //HStack
.onTapGesture {
self.hideKeyboard()
}
HStack (alignment: .center) {
Text("Margin of Error (E)")
.font(.callout)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer(minLength: /*@START_MENU_TOKEN@*/0/*@END_MENU_TOKEN@*/)
Divider()
TextField("Margin of Error:", text: $marginofError)
} //HStack
.onTapGesture {
self.hideKeyboard()
}
} // Section
} //If condition
else if (selectedParameterType.rawValue == ParameterType.Proportion.rawValue) {
//This section is applicable only for Population Mean
Section(header: Text("Enter Values")) {
HStack (alignment: .center) {
Text("Target Proportion (p̂)")
.font(.callout)
.frame(maxWidth: .infinity, alignment: .leading)
//Spacer(minLength: /*@START_MENU_TOKEN@*/0/*@END_MENU_TOKEN@*/)
Divider()
TextField("proportion data:", text: $proportiondata)
} //HStack
.onTapGesture {
self.hideKeyboard()
}
HStack (alignment: .center) {
Text("Margin of Error (E)")
.font(.callout)
.frame(maxWidth: .infinity, alignment: .leading)
// Spacer(minLength: /*@START_MENU_TOKEN@*/0/*@END_MENU_TOKEN@*/)
Divider()
TextField("proportion ME:", text: $proportionME)
} //HStack
.onTapGesture {
self.hideKeyboard()
}
} // Section
} //Else condition
List{
HStack {
ForEach(0..<confidenceValues.count, id: \.self) {index in
//HStack {
Button(action: {
confidenceValues[index].isSelected = confidenceValues[index].isSelected ? false : true
}) {
HStack{
if confidenceValues[index].isSelected {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
} else {
Image(systemName: "circle")
.foregroundColor(.primary)
}
Text(confidenceValues[index].name)
}
.padding(10)
}.buttonStyle(BorderlessButtonStyle())
//} //HStack
} //ForEach
} //HStack
}//List
Section(){
Button(
action: {
calculateEstimate()
},
label: {
Text("Calculate")
.frame(minWidth: 0, maxWidth: 300)
.foregroundColor(.blue)
.cornerRadius(40)
.font(.title)
}
)
}
.listRowBackground(Color.clear)
//Print Results
if showResults == true {
Section(header: Text("Results")) {
//Display the results for each confidence level selected
List {
ForEach(0..<confidenceValues.count, id: \.self)
{nEstimate in
VStack{
Text("The required sample size with a \(confidenceValues[nEstimate].name) confidence level is: ")
.frame(alignment: .topLeading)
//.id(nEstimate.level)
//.foregroundColor(.red)
Divider()
if selectedParameterType.rawValue == "Mean" {
Text("n = ((Zα/2 * σ) / E))^2")
.frame(alignment: .topLeading)
Spacer()
Text("n = (1.645 * 12.0) / 8.0)^2 ")
.frame(alignment: .topLeading)
Spacer()
}
else if selectedParameterType.rawValue == "Proportion" {
Text("n = (p̂ * (1−p̂ )) * (Zα/2 / E)^2")
.frame(alignment: .topLeading)
Spacer()
Text("n = (0.5) * 0.5) * (1.645 / 0.1)^2 ")
.frame(alignment: .topLeading)
Spacer()
}
Text("n = 67.6506 ≈ 68")
.frame(alignment: .topLeading)
Spacer()
} // VStack
} //ForEach
} //List
} //Section
//Display Reset button
Button(
action: {resetDSData()},
label: {
Text("Reset Values")
.frame(minWidth: 0, maxWidth: 300)
.foregroundColor(.blue)
.cornerRadius(40)
.font(.title)
}
)
.listRowBackground(Color.clear)
} //If showResults
} //Form
} //Navigation
} //ScrollViewReader
} //Body
struct ParameterTypeOnChange {
var showResults = false
}
func calculateEstimate() {
showResults = true
}
func resetDSData() {
showResults = false
}
} //ContentView
You can set
.id(0)to somewhere you want, and then useproxy.scrollTo(0)in the button's action