10
votes

When working with UIKit I was handling within UIView or in a UIViewController.

func touchesBegan(_ touches: Set, with event: UIEvent?)

How to handle a touch events with SwiftUI?

2

2 Answers

20
votes

Easiest thing is to add a DragGesture. Check out DragGesture.Value to get a sense of what information you have available.

Circle()
    .gesture(
        DragGesture(minimumDistance: 5, coordinateSpace: .global)
            .onChanged { value in
              self.dragLocation = value.location
            }
            .onEnded { _ in
              self.dragLocation = .zero
            }
    )

You can use minimumDistance: 0 in order to have a gesture that starts updating immediately, similar to touchesBegan(...) in UIKit.

2
votes

As another way, We have way of creating a custom button. SwiftUI provides ButtonStyle, PrimitiveButtonStyle and more.

https://developer.apple.com/documentation/swiftui/buttonstyle

In fact, Button does not create a label by myself, Button has Style and delegates creating the label to Style.

So, Style has makeBody method and we can get a configuration object. That object has label passed from outside and isPressed flag.

isPressed will be changed touchDown and touchUpInside events.

I've created the custom button style. That adds an overlay when the component is getting a touch.

https://www.notion.so/muukii/Create-custom-highlight-component-Like-subclassing-UIControl-a4e231ffa3624dfda96141a2f60588f1

Sample code

struct OverlayButton<Content: View>: View {

  private let content: Content

  init(
    @ViewBuilder _ content: () -> Content
  ) {
    self.content = content()
  }

  var body: some View {
    Button(action: {}) { content }
      .buttonStyle(_ButtonStyle())    
  }

  private struct _ButtonStyle: ButtonStyle {

    func makeBody(configuration: Self.Configuration) -> AnyView {
      if configuration.isPressed {
        return AnyView(
          configuration.label
            .background(Color(white: 0.96))
        )
      } else {
        return AnyView(
          configuration.label
            .background(Color(white: 1, opacity: 0.0001))
        )
      }
    }
  }

}

I hope that will be your idea.