When I tap on the textfield it does not respond.
Here is a clip of the weird behaviour…
https://drive.google.com/file/d/16HwOhCsTRzVpg8INMrvxmG4FofnUcr6G/view?usp=sharing
Any ideas on how to make it responsive?
When I tap on the textfield it does not respond.
Here is a clip of the weird behaviour…
https://drive.google.com/file/d/16HwOhCsTRzVpg8INMrvxmG4FofnUcr6G/view?usp=sharing
Any ideas on how to make it responsive?
Please show us some code to help us diagnose (and hopefully solve!) the problem.
This is the code for the name field (It is imbedded in a Vstack then a Vstack then a GeoReader)
var nameField : some View
{
TextField(editMode == .inactive ? $message.wrappedValue: "Click 'Done' button to continue", text: self.$enteredName)
.onSubmit
{
self.addEnteredName()
}
}
here is all the states and environment objects…
@EnvironmentObject var gameSettings:GameSetting
@State var enteredName : String = ""
@State private var editMode: EditMode = .inactive
@State private var message:String = "You must have 4 players! Enter here"
@State private var previousMessage:String = ""
@FocusState private var isTextFieldFocused: Bool
Unfortunately, that’s really not enough code to help. Please provide a complete View
, preferably stripped of as much as possible except what causes the issue. You want a minimal example that can reproduce the issue.
Like here, I can see that you have a nameField
computed property that generates a TextField
, but how is it put into the greater View
scope? You say it’s in a VStack
then a VStack
then a GeometryReader
but that can encompass a wide variety of layouts. Are there any modifiers attached to these elements? Is the nameField
the first item in its VStack
? The second? What else is in the stack? etc.
import SwiftUI
import Combine
import Foundation
import Neumorphic
struct CreateNames: View
{
@EnvironmentObject var gameSettings:GameSetting
@State var enteredName : String = ""
@State private var editMode: EditMode = .inactive
@State private var message:String = "You must have 4 players! Enter here"
@State private var previousMessage:String = ""
@FocusState private var isTextFieldFocused: Bool
//--functions--\\
func updatePlayers()
{
$gameSettings.players.wrappedValue = $gameSettings.namesInOrder.wrappedValue.count
}
func canPlay() -> Bool
{
if $gameSettings.namesInOrder.wrappedValue.count >= gameSettings.minimumPlayers && $gameSettings.namesInOrder.wrappedValue.count <= gameSettings.maximimPlayers && $editMode.wrappedValue == .inactive
{
return true
}
else
{
return false
}
}
func updateMessageForPlayerCount()
{
if $gameSettings.namesInOrder.wrappedValue.count >= gameSettings.minimumPlayers && $gameSettings.namesInOrder.wrappedValue.count < gameSettings.maximimPlayers
{
$message.wrappedValue = "You can now play!"
}
else if $gameSettings.namesInOrder.wrappedValue.count != 10
{
$message.wrappedValue = "You need \(gameSettings.minimumPlayers-$gameSettings.namesInOrder.wrappedValue.count) more player\(gameSettings.minimumPlayers-$gameSettings.namesInOrder.wrappedValue.count==1 ? "":"s")"
}
}
func startMessage() -> String
{
if $gameSettings.namesInOrder.wrappedValue.count >= gameSettings.minimumPlayers && $gameSettings.namesInOrder.wrappedValue.count < gameSettings.maximimPlayers
{
return "You can now play!"
}
else if $gameSettings.namesInOrder.wrappedValue.count != 10
{
return "You need \(gameSettings.minimumPlayers-$gameSettings.namesInOrder.wrappedValue.count) more player\(gameSettings.minimumPlayers-$gameSettings.namesInOrder.wrappedValue.count==1 ? "":"s"). Enter here!"
}
else
{
return "You can play!"
}
}
func nameIsNotUsed() -> Bool
{
var counter = 0
for _ in $gameSettings.namesInOrder.wrappedValue
{
if $enteredName.wrappedValue.capitalized.filter({$0 != " "}) == $gameSettings.namesInOrder.wrappedValue[counter].capitalized.filter({$0 != " "})
{
return false
}
else
{
counter+=1
}
}
return true
}
func addEnteredName()
{
if $gameSettings.namesInOrder.wrappedValue.count < gameSettings.maximimPlayers
{
if $enteredName.wrappedValue.isEmptyOrWhitespace() == false
{
if $enteredName.wrappedValue.count<30
{
if nameIsNotUsed()
{
$gameSettings.namesInOrder.wrappedValue.append(enteredName)
self.enteredName = ""
updateMessageForPlayerCount()
}
else
{
self.enteredName = ""
$message.wrappedValue = "You have already entered that name"
}
}
else
{
self.enteredName = ""
$message.wrappedValue = "That name is too big!"
}
}
else
{
self.enteredName = ""
$message.wrappedValue = "That name was blank!"
}
}
else
{
self.enteredName = ""
$message.wrappedValue = "You have reached max players"
}
print($gameSettings.namesInOrder.wrappedValue)
}
func move(from source : IndexSet, to destination : Int) {
$gameSettings.namesInOrder.wrappedValue.move(fromOffsets: source, toOffset: destination)
}
func delete(at offsets : IndexSet)
{
$gameSettings.namesInOrder.wrappedValue.remove(atOffsets: offsets)
updateMessageForPlayerCount()
}
//--custom Views--\\
var nameField : some View
{
TextField(editMode == .inactive ? $message.wrappedValue: "Click 'Done' button to continue", text: self.$enteredName)
.onSubmit
{
self.addEnteredName()
}
}
var addNameBtn : some View
{
Button(action: self.addEnteredName, label: {
Text("Add")
})
}
private var editButton: some View {
return Button {
if editMode == .inactive
{
editMode = .active
$previousMessage.wrappedValue = $message.wrappedValue
$message.wrappedValue = "Click the 'Done' button to continue"
}
else
{
editMode = .inactive
updateMessageForPlayerCount()
}
}
label: {
Text(editMode == .inactive ? "Edit" : "Done")
.frame( alignment: .trailing)
}
}
//--BODY--\\
var body: some View
{
GeometryReader
{ geo in
ZStack
{
VStack
{
nameField
// .font(.system(size: geo.size.width*0.05))
// .frame(width: geo.size.width, height: geo.size.height*0.1)
// .border($isTextFieldFocused.wrappedValue==true ? .cyan:.gray, width:$isTextFieldFocused.wrappedValue==true ? 2:0)
// .padding(.leading, 15)
// .font(.system(size: geo.size.width*0.05))
// .textFieldStyle(.roundedBorder)
// .focused($isTextFieldFocused)
HStack
{
Spacer()
addNameBtn
Spacer()
editButton
Spacer()
}
List
{
ForEach(self.$gameSettings.namesInOrder, id: \.self)
{ name in
Text(name.wrappedValue)
}
.onMove(perform: self.move)
.onDelete(perform: self.delete)
}
.frame(height: geo.size.height*0.7)
.environment(\.editMode, $editMode)
}
.offset(y:-geo.size.height*0.05)
NavigationLink(destination: RolePage())
{
Text("Set Roles")
.font(.system(size: geo.size.width*0.14, weight: .heavy, design: .rounded))
.frame(width: geo.size.width*0.7, height: geo.size.height*0.06)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: 18))
}
.disabled(canPlay() ? false:true)
.opacity(canPlay() ? 1:0.3)
.offset(y: geo.size.height*0.5)
.padding(.bottom, geo.size.height*0.05)
}
.onDisappear
{
updatePlayers()
}
}
}
}
struct CreateNames_Previews: PreviewProvider {
static var previews: some View {
CreateNames()
.environmentObject(GameSetting())
}
}
It’s this line that is preventing you from editing the TextField
:
.offset(y:-geo.size.height*0.05)
That line is shoving your VStack
up under the NavigationView
and blocking taps on the field. You can see this by assigning a background color to the NavigationView
's header.
with negative y offset:
without negative y offset:
Side note: You don’t need to do this all the time:
$message.wrappedValue = "whatever"
Just assign to message
normally:
message = "whatever"
Thank you! Removing that line of code solved the problem, just one more thing, is there a way to make the three items (the name field, add button and edit button) be a navigation bar item?
I tried to do this by embedding the Zstack in a “NavigationView” but then there is two toolbars, one with the back button and then underneath is the three items and it pushes the three items down.