I have this code:
struct MyTestScreen: View {
#State var text1 = ""
#State var text2 = ""
var body: some View {
VStack {
TextField("text1", text: self.$text1)
TextField("text2", text: self.$text2)
}
}
}
How can I change focus on text2 TextField, when I fill text1 and press "return"?
this should be possible with the code as below.
#State private var isFirstTextFieldFocused = false
#State private var isSecondTextFieldFocused = false
#State private var firstText: String = ""
#State private var secondText: String = ""
var body: some View {
VStack {
TextField("First text field", text: $firstText)
.padding()
.border(Color.white, width: isFirstTextFieldFocused ? 2 : 0)
.scaleEffect(isFirstTextFieldFocused ? 1.1 : 1)
.focusable(true) { focused in
isFirstTextFieldFocused = focused
}
TextField("Second text field", text: $secondText)
.padding()
.border(Color.white, width: isSecondTextFieldFocused ? 2 : 0)
.scaleEffect(isSecondTextFieldFocused ? 1.1 : 1)
.focusable(true) { focused in
isSecondTextFieldFocused = focused
}
}
}
Now the textFields should be focusable and you would just need to handle the text input.
Related
i try to make an invoice app by using core data, i have 4 attribute: Article String, Price String , Quantity String and Taxe String and i try to make a fonction to multiply price * quantity and the result of them i want to make another function for calculate the taxe for each article
Like this ->
Article:
Price $:
Quantity x:
Taxe %:
Total taxe %:
Total price taxe incl $:
and then at the end i want sum total price and total taxe of my list created by user in textfield in 2 diffrent textView
like this ->
Total taxe %:
Total prie incl taxe $:
struct Facturation: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(entity: FacturationCoreData.entity(), sortDescriptors: []) private var factures: FetchedResults<FacturationCoreData>
#State private var article = ""
#State private var prix = ""
#State private var quantite = ""
#State private var tvac = ""
#State private var tva = [0, 6, 12, 21]
#State private var tipIndex = 2
#AppStorage("textChange") private var textChange = ""
func prixQuantite() -> Double {
let fact = FacturationCoreData(context: viewContext)
let prix = fact.prix ?? ""
let quan = fact.quantite ?? ""
let sum = ((Double(prix) ?? 00) * (Double(quan) ?? 00))
return sum
}
func calculeTvaC() ->Double {
let fact = FacturationCoreData(context: viewContext)
let prixEtQuantite = prixQuantite()
let tva = fact.tva ?? ""
let prixTTC = ((prixEtQuantite / 100 * (Double(tva ?? "") ?? 00)) +
prixEtQuantite)
return prixTTC
}
var body: some View {
NavigationView{
VStack {
Form {
Section("Article"){
TextField("Article", text: $article)
.disableAutocorrection(true)
}
HStack{
Section("Q"){
TextField("Quantite", text: $quantite)
.keyboardType(.decimalPad)
}
Section("P") {
TextField("Prix", text: $prix)
.keyboardType(.decimalPad)
}
Section("T") {
TextField("TVA", text: $tvac)
.keyboardType(.decimalPad)
}
}
Button {
let facture = FacturationCoreData(context: viewContext)
facture.article = article
facture.quantite = quantite
facture.prix = prix
facture.tva = tvac
do{
try viewContext.save()
}catch{
print(error)
}
} label: {
Image(systemName: "square.and.arrow.down.fill")
.font(.title)
}
List{
ForEach(factures) { facture in
VStack(alignment: .leading){
Text("Artile: " + (facture.article ?? ""))
Text("Quantité: " + (facture.quantite ?? "") + "x")
Text("Prix: " + (facture.prix ?? "") + "€")
Text("Tva: " + (facture.tva ?? "") + "%")
Text("Total price:\(prixQuantite())$ ")
Text("Total taxe:\(calculeTvaC())$ ")
}.onTapGesture {
textChange = facture.article ?? ""
}
}.onDelete { indexSet in
indexSet.forEach { index in
let deletfacture = factures[index]
viewContext.delete(deletfacture)
do{
try viewContext.save()
}catch{
print(error)
}
}
}
}
}
Text(textChange)
}
.navigationTitle("Facturation")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink {
Client()
} label: {
Image(systemName: "person.badge.plus")
}
}
ToolbarItem(placement: .navigationBarLeading) {
NavigationLink {
ClientList()
} label: {
Image(systemName: "list.bullet")
}
}
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
}
}
}
You can use an extension
extension FacturationCoreData{
var prixQuantite : Double {
let prix = self.prix ?? ""
let quan = self.quantite ?? ""
let sum = ((Double(prix) ?? 00) * (Double(quan) ?? 00))
return sum
}
var calculeTvaC : Double {
let prixEtQuantite = prixQuantite
let tva = self.tva ?? ""
let prixTTC = ((prixEtQuantite / 100 * (Double(tva ?? "") ?? 00)) +
prixEtQuantite)
return prixTTC
}
}
Then you can use
Text("Total price:\(facture.prixQuantite)$ ")
Text("Total taxe:\(facture.calculeTvaC)$ ")
Im getting an error when using my Question struct in my function checkAnswer
I want to use the value in questions[index].answer but it error says
Cannot convert value of type 'Int' to expected argument type 'Range' and Value of type 'ArraySlice' has no member 'answer'
What did I do wrong on that part?
import SwiftUI
struct Question {
var question: String
var answer: Int
}
struct ContentView: View {
#State private var isGameRunning = false
let multiplyTableRange = Range(2...12)
#State private var selectedTable = 2
#State private var selectedNumOfQuestions = 5 //min of 5
#State private var variantsForCountOfQuestions = [5, 10, 20]
#State private var questions = [Question]()
#State private var currentQuestionIndex: Int = 1
#State private var answerInput: Int = 0
#State private var score = 0
#State private var isGameDone = false
#State private var gameCompleteMessage = ""
var body: some View {
if isGameRunning{
Group{
VStack{
Text("Your Score \(score)")
Text("\(questions[currentQuestionIndex].question)")
TextField("Enter your answer", value: $answerInput, formatter: NumberFormatter())
//error here
Button("Enter") {
checkAnswer(userAnswer: answerInput ?? 0 , answer: questions[currentQuestionIndex].answer)
}
.alert(isPresented: $isGameDone) {
Alert(title: Text(gameCompleteMessage), message: Text("Restart game"), primaryButton: .destructive(Text("Okay")) {
isGameRunning = false
answerInput = 0
score = 0
gameCompleteMessage = ""
currentQuestionIndex = 1
}, secondaryButton: .cancel())
}
}
}
}else{
Group{
VStack{
Text("Pick multiplication table to practice")
Picker("Pick multiplication table to practice", selection: $selectedTable){
ForEach(multiplyTableRange, id: \.self){
Text("\($0)")
}
} //eof picker
.labelsHidden()
.pickerStyle(SegmentedPickerStyle())
Text("How many questions?")
Picker("", selection: $selectedNumOfQuestions){
ForEach(variantsForCountOfQuestions, id: \.self){
Text("\($0)")
}
}//eofPicker
.labelsHidden()
.pickerStyle(SegmentedPickerStyle())
Button("Start"){
generateQuestions()
isGameRunning.toggle()
}
}
}
}
} //eof body
func generateQuestions(){
questions.removeAll()
for question in 1...selectedNumOfQuestions {
let x = Question(question: ("\(selectedTable) X \(question)"), answer: selectedTable * question)
questions.append(x)
}
}
func checkAnswer(userAnswer: Int, answer: Int) {
if userAnswer == answer {
score += 1
}
if currentQuestionIndex < selectedNumOfQuestions - 1 {
currentQuestionIndex += 1
} else {
gameCompleteMessage = "Your score is \(score)"
isGameDone = true
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I'm currently developing an application using CoreData in SwiftUI.
I want to show a value from CoreData Entity as a state variable after I edit that data.
When I add a value as a new date I can show that value well, but after I edit the value it doesn't reflect the editing...
If I don't use #State, the value can be shown well, even after I edit it. But I need to use as #State value to bind it to a child view.
How could I solve this problem?
(I want to show the collect value after editing in a place I comment out as B same as like A in ListView.swift )
CDTest.xcdatamodeld
CDTestApp.swift
import SwiftUI
#main
struct CDTestApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
ListView()
}
}
PersistenceController.swift
import CoreData
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "CDTest")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
}
}
HomeViewModel.swift
import SwiftUI
import CoreData
class HomeViewModel :ObservableObject{
#Published var content = ""
//for newdata sheet
#Published var isNewDate = false
//storing update Item
#Published var updateItem : Task!
func writeData(context : NSManagedObjectContext){
if updateItem != nil {
updateItem.content = content
try! context.save()
updateItem = nil
isNewDate.toggle()
content = ""
return
}
let newTask = Task(context: context)
newTask.content = content
do{
try context.save()
isNewDate.toggle()
content = ""
}catch{
print(error.localizedDescription)
}
}
func EditItem(item:Task){
updateItem = item
content = item.content!
isNewDate.toggle()
}
}
ListView.swift
import SwiftUI
import CoreData
struct ListView: View {
#StateObject var homeData = HomeViewModel()
#FetchRequest(entity: Task.entity(), sortDescriptors: [NSSortDescriptor(key:"date",
ascending:true)],animation:.spring()) var results:FetchedResults<Task>
#Environment(\.managedObjectContext) var context
var body: some View {
NavigationView{
VStack(spacing:0){
//Empty View...
if results.isEmpty{
Text("NO Data")
}else{
LazyVStack{
ForEach(results){task in
VStack(alignment: .leading, spacing: 5, content: {
Text(task.content ?? "") // A
ListRow(content: task.content ?? "") // B
})
.contextMenu{
Button(action: {
homeData.EditItem(item: task)
}, label: {
Text("Edit")
})
Button(action: {
context.delete(task)
try! context.save()
}, label: {
Text("Delete")
})
}
}
}
.padding()
}
//Add Button...
Button(action: {homeData.isNewDate.toggle()}, label: {
Image(systemName: "plus")
.font(.largeTitle)
.padding()
})
.sheet(isPresented: $homeData.isNewDate, content: {
NewDataView(homeData: homeData)
})
}
}
}
}
ListRow.swift
import SwiftUI
struct ListRow: View {
#State var content:String
var body: some View {
Text(content)
NavigationLink(destination:DetailView(content: $content)){
Text("DETAIL")
}
}
}
DetailView.swift
import SwiftUI
struct DetailView: View {
#Binding var content:String
var body: some View {
Text(content)
}
}
NewDataView.swift
import SwiftUI
struct NewDataView: View {
#ObservedObject var homeData : HomeViewModel
#Environment(\.managedObjectContext) var context
var body: some View {
VStack{
Text("\(homeData.updateItem == nil ? "Add New" : "Up date")Task")
.font(.title)
TextEditor(text: $homeData.content)
.padding()
//Add Button...
Button(action: {homeData.writeData(context: context)}, label: {
Text(homeData.updateItem == nil ? "Add Now" : "Update")
.font(.title)
.fontWeight(.bold)
})
.padding()
.disabled(homeData.content == "" ? true : false)
.opacity(homeData.content == "" ? 0.5 : 1)
}
}
}
Xcode: Version 12.0.1
iOS: 14.0
Life Cycle: SwiftUI App
Just pass entire task object into ListRow, like
VStack(alignment: .leading, spacing: 5, content: {
Text(task.content ?? "") // A
ListRow(task: task) // B // << here !!
so now we can use ObservedObject wrapper, which gives binding to published property:
struct ListRow: View {
#ObservedObject var task: Task
var body: some View {
Text(task.content ?? "")
NavigationLink(destination:DetailView(content: $task.content)){
Text("DETAIL")
}
}
}
Goal: update a core data object with SwiftUI: DetailView -> EditDetail -> DetailView (updated).
Problem: code bellow works, but creates a new object, instead of updating existing one.
import SwiftUI
struct DetailView: View {
var order = Order()
#State var showOrderEdit = false
var body: some View {
Form{
Text(order.tableNumber)
Text(order.pizzaType)
}
.navigationTitle(order.pizzaType)
.toolbar {
ToolbarItem(placement: .primaryAction) {
//edit button
Button(action: {
showOrderEdit = true
}, label: {
Text("Edit")
})
.sheet(isPresented: $showOrderEdit) {
OrderEdit(order: order)
}
}
}
}
}
import SwiftUI
struct DetailEdit: View {
#State var tableNumber = ""
#Environment(\.managedObjectContext) private var viewContext
#Environment (\.presentationMode) var presentationMode
var order = Order()
var body: some View {
NavigationView {
Form {
TextField("table number", text: $tableNumber)
//update button
Button(action: {
updateOrder(order: order)
}) {
Text("Update")
.foregroundColor(.blue)
}
}
//passing data item detail -> item edit
.onAppear {
self.tableNumber = self.order.tableNumber
}
.navigationTitle("Edit Order")
}
}
func updateOrder(order: Order) {
let newtableNumber = tableNumber
viewContext.performAndWait {
order.tableNumber = newtableNumber
try? viewContext.save()
}
}
You create new Order object in each view, so it is stored as new one into database. Instead you need to inject CoreData object from parent view (which shows DetailView) as observed object,
struct DetailView: View {
#ObservedObject var order: Order // << here !!
// .. other code
and
struct DetailEdit: View {
#State var tableNumber = ""
#Environment(\.managedObjectContext) private var viewContext
#Environment (\.presentationMode) var presentationMode
#ObservedObject var order: Order // << here !!
// ... other code
in such approach you will work with same instance of Order in both views and they will be updated because observe that instance for modifications.
If a calculation is performed in SwiftUI and no values are added to the Textfield it displays "-NaN" (Not a Nummber?) instead.
How can a value (for example "0", "-") be displayed until values are inserted?
I have tried adding #State private var display = 0 but it displayed both values...
Example code:
struct ContentView: View {
#EnvironmentObject var userData: UserData
var Brutto: Double{
let price = Double(userData.BPrice) ?? 0
let rent = Double(userData.Rent) ?? 0
let Brutto = rent * 12 / price * 100
return Brutto
}
var body: some View {
VStack {
Text ("\(Brutto, specifier: "%.1f")")
}
// The UserData File:
class UserData : ObservableObject {
private static let userDefaultBPrice = "BPrice"
private static let userDefaultRent = "Rent"
#Published var BuyingPrice = UserDefaults.standard.string(forKey: UserData.userDefaultBPrice) ?? ""
{
didSet {
UserDefaults.standard.set(self.BPrice, forKey: UserData.userDefaultBPrice)
}
}
#Published var Rent = UserDefaults.standard.string(forKey: UserData.userDefaultRent) ?? "" {
didSet {
UserDefaults.standard.set(self.Rent, forKey: UserData.userDefaultRent)
}
}
private var canc: AnyCancellable!
}
Thanks
Here is possible approach
VStack {
Text ("\(Brutto.isNaN ? 0 : Brutto, specifier: "%.1f")")
}