Post

Replies

Boosts

Views

Activity

Reply to Observation on SwiftUI+DragGesture: GestureState is already reset when OnEnded starts
I may have been misusing what GestureState was intended for. I came up with another approach that seems easier for what I want. This is what I want: I have a SpriteView with a GameScene (subclassed from SKScene). I want the SpriteView to handle the gestures (since it is way easier than the old approach). I want the tapped buttonNode in the GameScene to track the location for highlighting and unhighlighting. When the tracking ends, I want the tapped buttonNode to do its action if it is still being selected. But I cannot attach the SwiftUI gestures to the SKNode buttonNodes of the GameScene since they are not Views. Thus, I have to have a custom SwiftUI dragGesture to handle the above. The major problem is to remember the originally touched buttonNode. Instead of trying to use GestureState, I just use a locally captured variable within the "var" or "function" gesture. Here is a modified version of what I do. The modification uses force unwrapping to keep it simple. I put the dragGesture as part of the GameScene rather than as part of the file with the SpriteView. This is because of the needs for my particular program. The code can be simplified if you put it with the file with the SpriteView. For example, you can eliminate the guard statements for gameScene. The major point of the example is to how to capture the "begin" state of the gesture without using GestureState. extension GameScene {     var buttonNodeGesture: some Gesture {         var hitButtonNode:Button3Node?         return DragGesture(minimumDistance: 0)             .onChanged { [weak self] gesture in                 guard let gameScene = self else { return }                 let buttonNodes = gameScene.buttonNodes                 let firstButtonNode = buttonNodes.first!                 let parent = firstButtonNode.parent!                 do { // updating stuff                     if hitButtonNode == nil {                         let startLocation = gameScene.convert(fromGesture: gesture.startLocation, to: parent)                         hitButtonNode = gameScene.buttonNodes.filter{$0.contains(startLocation)}.first                     }                 }                 do { // onChanged stuff                     if let hitButtonNode = hitButtonNode {                         let location = gameScene.convert(fromGesture: gesture.location, to: parent)                         if hitButtonNode.contains(location) {                             hitButtonNode.highlight()                         }                         else {                             hitButtonNode.unhighlight()                         }                     }                 }             }             .onEnded { [weak self] gesture in                 guard let gameScene = self else { return }                 let buttonNodes = gameScene.buttonNodes                 let firstButtonNode = buttonNodes.first!                 let parent = firstButtonNode.parent!                 do { // onEnded stuff                     if let hitButtonNode = hitButtonNode {                         hitButtonNode.unhighlight()                         let location = gameScene.convert(fromGesture: gesture.location, to: parent)                         if hitButtonNode.contains(location) {                             hitButtonNode.doButtonAction()                         }                     }                 }                 hitButtonNode = nil // Note: probably not needed             }     } }
Feb ’23
Reply to Observation on SwiftUI+DragGesture: GestureState is already reset when OnEnded starts
In the given example, the last line is needed (hitButtonNode = nil). This could be a source of error, especially when there are many items to reset. Since GestureState automatically handles the resetting of the state, it would be nice if it wasn't reset before onEnded is started (this is my original note). I am not sure why it is being reset before .onEnded starts. My surmise is that Apple intends the gestureState to be used to change the appearance of some other item within the view (like its highlighting or its color). But, I don't see why this would require the gestureState to be reset before beginning .onEnded. This last comment leads to another comment about .onChange and .onEnded for gestures. It is not clear to me whether the mouseUp event that triggers .onEnded would first call .onChange and then call .onEnded. It would be nice if it was documented (and actually done) this way. Since I am not sure, I usually make the code in .onChange a single function and when .onEnded starts I call that function to insure that I am following the last mouse or tap event.
Feb ’23
Reply to Making button size bigger
I am also learning SwiftUI. Here is my initial solution. The button needs a stoke outline which I did not handle since I am putting the button on a green background. I am not sure if this is the best way to do it. It duplicates what I did in my Swift application so I did not spend more time on refining it. It uses buttonStyle property since I have many buttons. In my application, I named "MyButtonStyle" as "GameButtonStyle" since I am using it on a menu View for game actions. struct ExampleView: View {     var body: some View {         ZStack {             Color(red: 0, green: 0.5, blue: 0)             VStack {                 Button("Button") {                     print("tap button")                 }                 .buttonStyle(MyButtonStyle(labelWidth: 150, labelHeight: 30, scaleFactor: 1))             }         }     } } struct MyButtonStyle: ButtonStyle {     let labelWidth:CGFloat     let labelHeight:CGFloat     let scaleFactor:CGFloat     let minWidth:CGFloat     let verticalPadding:CGFloat     init(labelWidth: CGFloat, labelHeight: CGFloat, scaleFactor: CGFloat, minWidth: CGFloat = 0, verticalPadding: CGFloat = 0) {         self.labelWidth = labelWidth         self.labelHeight = labelHeight         self.scaleFactor = scaleFactor         self.minWidth = minWidth         self.verticalPadding = verticalPadding     }     func makeBody(configuration: Configuration) -> some View {         let darkBlue = Color(red: 0, green: 0, blue: 1)         configuration.label             .frame(width: labelWidth, height: labelHeight)             .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))             .font(Font.system(size: (7 * labelHeight) / 9))             .frame(minWidth: minWidth)             //.padding(.horizontal, 10)             .padding(.vertical, verticalPadding)             .foregroundColor(configuration.isPressed ? Color.white : Color.black)             .background(configuration.isPressed ? darkBlue : Color.white)             .cornerRadius(labelHeight)     } }
Feb ’23