I created a custom alert. I want the product to be added to the basket when the Ok button on Alert is clicked on the first screen. When the Ok button is pressed on the second screen, the purchase of the product is requested. I called the same alert on 2 pages and I want it to take different actions. I couldn't do that with #Escaping.
AlertView
struct AlertView: View {
#Binding var openShowAlert: Bool
#State var closeShowAlert: Bool = false
#State var openState: CGFloat = -UIScreen.main.bounds.height
#State var closeState: CGFloat = UIScreen.main.bounds.height
var title: String = ""
var message: String = ""
var okButtonText: String = ""
var cancelButtonText: String = ""
var body: some View {
VStack {
Text(title)
.michromaFont(size: 20)
.padding(.top)
Spacer()
Text(message)
.michromaFont(size: 18)
Spacer()
HStack {
Button(action: {
self.openShowAlert = false
openState = -UIScreen.main.bounds.height
closeState = UIScreen.main.bounds.height
}) {
Text(cancelButtonText)
.foregroundColor(.red)
}
Spacer()
Button(action: {}) {
Text(okButtonText)
}
}
.michromaFont(size: 18)
.padding([.horizontal, .bottom])
}
.neumorphisimBackground(width: 300, height: 200)
.offset(y: self.openShowAlert ? self.openState : self.closeState)
.animation(.easeInOut)
.onChange(of: self.openShowAlert, perform: { value in
if value {
self.openState = .zero
}
})
}
}
DetailView
On this screen, click Alert presentation to add the product to the cart.
struct DetailView: View {
#Environment(\.presentationMode) var presentationMode
var device = UIDevice.current.userInterfaceIdiom
#State var width: CGFloat = 300
#State var height: CGFloat = 450
#Binding var text: String
#State var showAlert: Bool = false
var body: some View {
ZStack() {
......
AlertView(openShowAlert: self.$showAlert)
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}
CartView Click I am providing an alert on this screen to purchase the product.
struct CartView: View {
#State var cartList = [1,2,3,4,5,6,7,8,9]
#Environment(\.presentationMode) var presentationMode
#State var showAlert: Bool = false
var body: some View {
ZStack(alignment: .top) {
.....
AlertView(openShowAlert: self.$showAlert)
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}
How can I send two different actions in the same alert.
Hmm, I don't see why it shouldn't work with a closure. Have you tried passing over a closure like so?
struct AlertView: View {
...
var okButtonAction: () -> ()
var body: some View {
...
Button(action: okButtonAction) {
Text(okButtonText)
}
}
}
Usage
AlertView(openShowAlert: self.$showAlert) {
// Your custom code
}
Alternative Idea
You could work with Combine and create a publisher with a specific key to identify the sender screen. Then you can put your custom code inside .onReceive().
Related
I'm studying SwiftUI and I'm having a hard time dealing with TextField.
When I do onCommit, I tried to put "" in the #State Property value, but there was no response.
What I'm trying to do is click the'retrun' key in TextField and I want to show you the gap where the text created disappeared.
struct TodoTextFieldView: View {
#EnvironmentObject var listViewModel: ListViewModel
#State var textFieldText = ""
var title: String = "here typing line"
var body: some View {
VStack{
HStack(spacing: 5){
Text("🔥")
.font(.title)
TextField("\(title)",
text: $textFieldText,
onCommit:{ addItem()
//
})
.disableAutocorrection(true)
.underline()
.font(.headline)
}.padding(.leading, 40)
}.padding(16)
}
func addItem() {
listViewModel.addItem(title: textFieldText)
textFieldText = "" // This is where I want to do it.
print(textFieldText)
}
This is a parent view.
struct ContentView: View {
#EnvironmentObject var listViewModel: ListViewModel
var body: some View {
VStack {
TodayView()
Spacer()
TodoTextFieldView()
Spacer()
/// List view
List{
ForEach(listViewModel.items) { item in
ListView(item: item)
.onTapGesture {
withAnimation(.linear){
listViewModel.updateItem(item: item)
}
}
}
.onDelete(perform: listViewModel.deleteItem) // Delete
.onMove(perform: listViewModel.moveItem) // Edit
}.listStyle(PlainListStyle())
}.navigationBarItems(trailing: EditButton()) // Edit Button
.padding()
}
}
#State var textFieldText = ""
The value was directly added to the state property. But there is no reaction.
textFieldText = ""
Emptying the binding property of TextField inside the Task block works for me.
func addItem() {
listViewModel.addItem(title: textFieldText)
Task {
textFieldText = ""
}
}
I am trying to get data from one view to another.
I can not figure out how to get values from the fourth view array into the Third view.
I am not using storyboards. I tried using #EnvironmentObject but can not make it work. New to coding. In xcode I am using watchos without app.
I tried to strip out most of the code and leave just the important stuff that can be tested. I used NavigationLink(destination: )to transfer between views.
enter code here
class viewFromEveryWhere: ObservableObject {
#Published var testname2: String = "testTTname"
}
struct secondView: View {
var body: some View {
Text("second view")
List(1..<7) {
Text("\($0)")
}
}
}
struct thirdView: View {
#EnvironmentObject var testname2: viewFromEveryWhere
#EnvironmentObject var testSixTestArray: viewFromEveryWhere
#State var sixTestArray:[String] = ["ww","GS","DW","CD","TS","JW",]
var body: some View {
List(sixTestArray, id:\.self) {
Text($0)
}
}
}
struct fourthView: View {
#StateObject var testname2 = viewFromEveryWhere()
#State private var name: String = ""
#State var testSixTestArray:[String] = []
func collectName () {
print("collectName triggered")
if testSixTestArray.count < 5 {
// testSixTestArray.append(name)
print(name)
print(testSixTestArray)
}
// .enviromentObject(testSixTestArray)
}
var body: some View {
VStack(alignment: . leading) {
Text("Type a name")
TextField("Enter your name", text: $name)
Text("Click to add, \(name)!")
// Button("click this if \(name) is correct") {}
Button(action:{
print("Button Tapped")
collectName()
print(testSixTestArray.count)
name = ""
}) {
Text("Add \(name) to list")
}
// .buttonStyle(GrowingButton1())
}
Text("forth view")
// testSixTestArray.append(name)
.environmentObject(testname2)
}
}
/*func presentTextInputControllerWithSuggestions(forLanguage suggestionsHandler:
((String)-> [Any]?)?,
allowedInputMode inputMode:
WKTextInputMode,
completion: #escaping ([Any]?) -> Void) {}
*/
struct ContentView: View {
#State var sixNameArray:[String] = ["","","","","","",]
#State var messageTextBox: String = "Start"
#State var button1: String = "Button 1"
#State var button2: String = "Button 2"
#State var button3: String = "Button 3"
var body: some View {
NavigationView {
VStack{
Text(messageTextBox)
.frame(width: 120, height: 15, alignment: .center)
.truncationMode(.tail)
.padding()
NavigationLink(destination: secondView(),
label:{
Text(button1)
})
.navigationBarTitle("Main Page")
NavigationLink(destination: thirdView(),
label:{
Text(button2)
})
NavigationLink(destination: fourthView(),
label:{
Text(button3)
})
}
}
}
}
enter code here
I'm not sure if I created my custom TextField properly, because I am unable to observe the value changes to an #Binded text. Running the following code, you may observe that print(text) is not executed when you manually enter text into the text field.
import SwiftUI
#main
struct TestOutWeirdTextFieldApp: App {
#State var text: String = "" {
didSet {
print(text)
}
}
var body: some Scene {
WindowGroup {
StandardTextField(placeholderText: "Enter text", defaultText: $text)
}
}
}
struct StandardTextField: View {
#State var placeholderText: String {
didSet {
print(#line)
print(placeholderText)
}
}
#Binding var defaultText: String {
didSet {
print(#line)
print(defaultText)
}
}
#State var systemImage: String?
#State var underlineColor: Color = .accentColor
#State var edges: Edge.Set = .all
#State var length: CGFloat? = nil
#State var secure: Bool = false
var body: some View {
HStack {
if secure {
SecureField(placeholderText, text: $defaultText)
.foregroundColor(underlineColor)
} else {
TextField(placeholderText, text: $defaultText)
.foregroundColor(underlineColor)
}
if let systemImage = systemImage {
Image(systemName: systemImage)
.foregroundColor(.white)
}
}
.overlay(
Rectangle()
.frame(height: 2)
.padding(.top, 35)
)
.foregroundColor(underlineColor)
.padding(edges, length)
}
}
struct StandardTextView_Previews: PreviewProvider {
static var previews: some View {
StandardTextField(placeholderText: "Placement text", defaultText: .constant("")).previewLayout(.sizeThatFits)
}
}
Instead of didSet you need to use .onChange(of: modifier, like
HStack {
// ... your code here
}
.onChange(of: defaultText) { print($0) } // << this !!
.overlay(
I'm trying to make a graph app, but animating it using a #State property does not help, for some reason.
struct GraphBars: View {
#State var percent: CGFloat
var body: some View {
Capsule()
.fill(Color.black)
.frame(width: 50, height: self.percent)
}
}
struct TEST3: View {
#State var bar1: CGFloat = 90.0
var body: some View {
GeometryReader { gg in
VStack {
Button(action: {
self.bar1 = 300.0
}) {
Text("Hello")
}
GraphBars(percent: bar1)
}
However, pressing the button does not increase the height of the bar as I thought it would. What am I doing wrong?
You need to use #Binding to transfer a variable back and forth between two Views otherwise the parent View doesn't get a notice of the variable change.
Do it like this:
struct GraphBars: View {
#Binding var percent: CGFloat
var body: some View {
Capsule()
.fill(Color.black)
.frame(width: 50, height: self.percent)
}
}
struct Test3: View {
#State var bar1: CGFloat = 90.0
var body: some View {
GeometryReader { gg in
VStack {
Button(action: {
self.bar1 = 300.0
}) {
Text("Hello")
}
GraphBars(percent: self.$bar1)
}
}
}
}
I don't want my Login Page and main page show navigationBar, but i need Navigation in RegistrationPage and forgetPasswordPage. I use .navigationBarHidden(self.isNavigationBarHidden) to control my navigationBar.
The mainPage with a tabView and there are some tabItemView with their own NavigationView.
It seemed that my app with a block on the top. When I jump to a sheet and go back to main page, the blank was disappear.
Here is the video for my issue.
https://youtu.be/rIZ3Awzpe3Y
struct LoginView: View {
#EnvironmentObject var userToken: UserToken
#State var account : String = ""
#State var password : String = ""
#State var hint : String = ""
#State var successLogin : Bool = false
#State var hideLoginNavigationBar : Bool = false
#State private var isNavigationBarHidden = true
var body: some View {
NavigationView {
NavigationLink(destination: ResetPassword(isNavigationBarHidden: self.$isNavigationBarHidden)) {
LoginButtonTextStyle(TextValue:"Resetpassword")
}
Button(action: LoginCheck) {
// log in logic
NavigationLink(destination: MainView(isNavigationBarHidden: self.$isNavigationBarHidden), isActive: $successLogin) {
EmptyView()
}
LoginButtonTextStyle(TextValue:"Login")
}
NavigationLink(destination: RegistrationView(isNavigationBarHidden: self.$isNavigationBarHidden)) {
LoginButtonTextStyle(TextValue:"Registration")
}
}.padding(EdgeInsets(top: 0, leading: 50, bottom: 0, trailing: 50))
}
.navigationBarTitle("Login",displayMode: .inline)
.navigationBarHidden(self.isNavigationBarHidden)
.onAppear {
self.isNavigationBarHidden = true
}
}
}
Here is my main page
struct MainView: View {
#State var selectedtab:Int = 1
#Binding var isNavigationBarHidden : Bool
var body: some View {
TabView (selection: $selectedtab){
UserInformationView()
.tabItem {
Image(systemName: "person.fill")
}.tag(0)
.navigationBarTitle("Main")
.navigationBarHidden(true)
TeamListView()
.tabItem {
Image(systemName: "person.3.fill")
}.tag(1)
.navigationBarTitle("Main")
.navigationBarHidden(true)
NotificationView()
.tabItem {
Image(systemName: "bell.fill")
}.tag(2)
.navigationBarTitle("Main")
.navigationBarHidden(true)
SettingView()
.tabItem {
Image(systemName: "list.bullet")
}.tag(3)
.navigationBarTitle("Main")
.navigationBarHidden(true)
}
.navigationBarTitle("Main")
.onAppear(perform: {
self.isNavigationBarHidden = true
})
}
}
one of my tab item view with NavigationView
struct TeamListView: View {
var tutors: [Tutor] = teamData
// var teams: [Team]?
#Environment(\.presentationMode) var presentationMode
#EnvironmentObject var userToken : UserToken
#State var showingDelete = false
#State var teamListFloatingButtonShow = false
#State var goToCreateTeam = false
#State var goToInputInvitionCode = false
#State var addMenuIsPresented: Bool = false
#State var creatTeamIsPresented: Bool = false
#State var teamResults : [TeamResult] = []
var body: some View {
NavigationView {
.....
}
.onAppear(perform: getTeamData)
}