first of all I have two textfields and when one of them is focused and changed something this textfield that is changed has to convert a number to the other textfield so my code of the textfield look like this
@State var leftAmount = ""
@State var rightAmount = ""
@State var showInfoScreen = false
@State var showSelectCurrency = false
@FocusState var leftTyping
@FocusState var rightTyping
@State var leftCurrency: Currency = .silverPiece
@State var rightCurrency: Currency = .goldPiece
var body: some View {
ZStack{
Image("background")
.resizable()
.ignoresSafeArea()
VStack{
Image("prancingpony")
.resizable()
.scaledToFit()
.frame(height: 200)
Text("Curreny Exchange")
.foregroundColor(.white)
.font(.largeTitle)
.kerning(2)
HStack{
VStack{
HStack{
Image(leftCurrency.image)
.resizable()
.scaledToFit()
.frame(height: 33)
Text(leftCurrency.name)
.font(.headline)
.foregroundColor(.white)
}
.onTapGesture {
showSelectCurrency = true
}.sheet(isPresented: $showSelectCurrency){
SelectCurrency(showSelectCurrency: $showSelectCurrency, topCurrency: $leftCurrency, bottomCurrency: $rightCurrency)
}
TextField("Amount", text: $leftAmount)
.textFieldStyle(.roundedBorder)
.focused($leftTyping)
.onChange(of: leftAmount) { newValue in
if leftTyping {
rightAmount = leftCurrency.convert(leftAmount, to: rightCurrency)
}
}
}
Image(systemName: "equal")
.foregroundColor(.white)
.font(.largeTitle)
VStack{
HStack{
Text(rightCurrency.name)
.font(.headline)
.foregroundColor(.white)
Image(rightCurrency.image)
.resizable()
.scaledToFit()
.frame(height: 33)
}
.onTapGesture {
showSelectCurrency = true
}.sheet(isPresented: $showSelectCurrency){
SelectCurrency(showSelectCurrency: $showSelectCurrency, topCurrency: $leftCurrency, bottomCurrency: $rightCurrency)
}
TextField("Amount", text: $rightAmount)
.textFieldStyle(.roundedBorder)
.multilineTextAlignment(.trailing)
.focused($rightTyping)
.onChange(of: rightAmount) { newValue in
leftAmount = rightCurrency.convert(rightAmount, to: leftCurrency)
}
}
}
.padding()
.background(.black.opacity(0.5))
.clipShape(Capsule())
Spacer()
HStack {
Spacer()
Button {
showInfoScreen = true
} label: {
Image(systemName: "info.circle.fill")
.foregroundColor(.white)
.font(.largeTitle)
}
}
.padding()
.sheet(isPresented: $showInfoScreen) {
InfoView(showInfoScreen: $showInfoScreen)
}
}
}
}
}
and this is my func
func convert(_ amountString: String, to currency: Currency) -> String {
guard let doubleAmount = Double(amountString) else {
return "" // eğer kullanıcı textfield'a numara yerine harf yazarsa boş string return yapıyor yani textfield boş kalıyor
}
let convertedAmount = (doubleAmount / self.rawValue) * currency.rawValue
return String(format: "%.2f", convertedAmount)
when I don't put the if statement everything works fine about converting, but when I put the if statement on the onChange it does nothing, no converts and nothing. I think I have to use the newValue on somewhere but I'm not sure so if you guys can help me with this problem.
This is my first question so I'm sorry if I couldn't explainn the best way.
I want to use that if statement about if right textfield is focused it'll type there and leave the other textfield, but when I put the if statement there, nothing works.
You are using the version of .onChange
with one parameter that has been replaced in iOS 17.0, so it is now deprecated. The documentation has a useful note:
Be aware that the replacements have slightly different behvavior. This modifier’s closure captures values that represent the state before the change. The new modifiers capture values that correspond to the new state.
So inside your closures, the values are from before the change, with the important exception of newValue
. For example, in this case:
.onChange(of: leftAmount) { newValue in
if leftTyping {
rightAmount = leftCurrency.convert(leftAmount, to: rightCurrency)
}
}
the values for leftTyping
, leftCurrency
, leftAmount
and rightCurrency
are all from before the change.
1. Use the new version of .onChange
You might find that it works if you use the new version of .onchange
that takes two parameters:
.onChange(of: leftAmount) { _, newValue in
2. Use newValue
in the closure
If the new version of .onchange
is not an option (because you need to support older iOS versions) then try replacing leftAmount
with newValue
inside the closure:
.onChange(of: leftAmount) { newValue in
if leftTyping {
rightAmount = leftCurrency.convert(newValue, to: rightCurrency)
}
}
The other case needs updating similarly - try replacing rightValue
with newValue
inside the closure (and add an if
condition too).
3. Use newValue
to supply more information
If making the simple change to the closure doesn't fix it then you will need to consider using a different value for the .onChange
, so that newValue
gives you more information. For example, you could use an empty string to indicate that the field did not have focus. Something like:
let leftAmountEntered = leftTyping ? leftAmount : ""
TextField("Amount", text: $leftAmount)
.textFieldStyle(.roundedBorder)
.focused($leftTyping)
.onChange(of: leftAmountEntered) { newValue in
if !newValue.isEmpty {
rightAmount = leftCurrency.convert(newValue, to: rightCurrency)
}
}