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。