Ios 将tapAction从SwiftUI按钮操作发送到UIView函数

Ios 将tapAction从SwiftUI按钮操作发送到UIView函数,ios,swift,swiftui,Ios,Swift,Swiftui,我试图找到一种方法来触发一个动作,当在swiftUI中点击一个按钮时,该动作将调用我的ui视图中的一个函数 以下是我的设置: 点击按钮(SwiftUI)时,需要运行foo()(UIView) 我的自定义UIView类使用AVFoundation框架 class-SomeView:UIView{ func foo(){} } 要在swiftUI中使用我的UIView,我必须将其包装在UIViewRepresentable struct someviewsrepresentable:uiviews

我试图找到一种方法来触发一个动作,当在
swiftUI
中点击一个按钮时,该动作将调用我的
ui视图中的一个函数

以下是我的设置:

点击
按钮(SwiftUI)
时,需要运行
foo()(UIView)

我的自定义UIView类使用AVFoundation框架
class-SomeView:UIView{
func foo(){}
}
要在swiftUI中使用我的UIView,我必须将其包装在
UIViewRepresentable
struct someviewsrepresentable:uiviewsrepresentable{
func makeUIView(上下文:context)->CaptureView{
SomeView()
}
func updateUIView(uiView:CaptureView,context:context){
}
}
承载my UIView()的SwiftUI视图
struct ContentView:View{
var body:一些观点{
VStack(对齐:中心,间距:24){
SomeViewRepresentable()
.背景(颜色.灰色)
HStack{
按钮(操作:{
打印(“快捷键:点击按钮”)
//在SomeView()中调用func
}) {
文本(“点击此处”)
}
}
}
}
}

您可以在可表示结构(
SomeViewRepresentable
此处)中存储自定义
UIView
的实例,并在点击操作时调用其方法:

struct SomeViewRepresentable: UIViewRepresentable {

  let someView = SomeView() // add this instance

  func makeUIView(context: Context) -> SomeView { // changed your CaptureView to SomeView to make it compile
    someView
  }

  func updateUIView(_ uiView: SomeView, context: Context) {

  }

  func callFoo() {
    someView.foo()
  }
}
您的视图主体将如下所示:

  let someView = SomeViewRepresentable()

  var body: some View {
    VStack(alignment: .center, spacing: 24) {
      someView
        .background(Color.gray)
      HStack {
        Button(action: {
          print("SwiftUI: Button tapped")
          // Call func in SomeView()
          self.someView.callFoo()
        }) {
          Text("Tap Here")
        }
      }
    }
  }
为了测试它,我在
foo()
方法中添加了一个打印:

class SomeView: UIView {

  func foo() {
    print("foo called!")
  }
}

现在点击按钮将触发
foo()
,并显示打印语句。

M Reza的解决方案适用于简单情况,但是如果您的父SwiftUI视图在每次刷新时都有状态更改,它将导致UIViewRepresentable创建UIView的新实例,因为:
让someView=someView()//添加此实例
。因此,
someView.foo()
正在调用您创建的
someView
的上一个实例上的操作,该实例在刷新时已过时,因此您可能不会在父视图上看到UIViewRepresentable的任何更新。 见:

更好的做法是在调用UIView函数时避免创建和引用该实例

我对M Reza解决方案的适应是通过父视图的状态更改间接调用函数,这会触发
updateiview

  var body: some View {
    @State var buttonPressed: Bool = false
    VStack(alignment: .center, spacing: 24) {

      //pass in the @State variable which triggers actions in updateUIVIew
      SomeViewRepresentable(buttonPressed: $buttonPressed)
        .background(Color.gray)
      HStack {
        Button(action: {
          buttonPressed = true
        }) {
          Text("Tap Here")
        }
      }
    }
  }

struct SomeViewRepresentable: UIViewRepresentable {
  @Binding var buttonPressed: Bool 

  func makeUIView(context: Context) -> SomeView {
    return SomeView()
  }

  //called every time buttonPressed is updated
  func updateUIView(_ uiView: SomeView, context: Context) {
    if buttonPressed {
        //called on that instance of SomeView that you see in the parent view
        uiView.foo()
        buttonPressed = false
    }
  }
}

这里有另一种使用桥接类的方法

//SwiftUI
struct SomeView: View{
  var bridge: BridgeStuff?

  var body: some View{
    Button("Click Me"){
      bridge?.yo()
    }
  }
}

//UIKit or AppKit (use NS instead of UI)
class BridgeStuff{
  var yo:() -> Void = {}
}

class YourViewController: UIViewController{

  override func viewDidLoad(){
    let bridge = BridgeStuff()
    let view = UIHostingController(rootView: SomeView(bridge: bridge))
    bridge.yo = { [weak self] in
      print("Yo")
      self?.howdy()
    }
  }

  func howdy(){
    print("Howdy")
  }
}

真不敢相信这么简单。我不知道为什么我觉得会不一样。非常感谢,妈的!我花了今天的时间试图从
SwiftUI
推送或触发
UIKit
中的某些内容,实际上几分钟前我就提出了一个问题。它现在被删除了。我只希望我能给你多投一票。哈哈,这么简单吧?保留对uiview的引用会给我带来一些奇怪的效果,我们发现它会重新绘制uiview它正在工作,但添加此实例变量会导致更新请求一直被发送。当我移除它时,它不会被调用。我的UIView是MKMapView,可能会有所不同。这应该是更正确的答案,因为这是在SwiftUI中执行此操作的正确方法。。。。在SwiftUI中做事的心态与传统的UIKit大不相同。这导致->[SwiftUI]在视图更新期间修改状态,这将导致未定义的行为。这是因为在更新块中再次将buttonPressed设置为false。