向使用 UIViewRepresentable 创建的按钮添加操作
Add action to button created using UIViewRepresentable
我正在使用 FluentUI#button
,它后面使用了 UIKit
我需要在 SwiftUI 视图中显示该按钮,我正在尝试切换 @State
属性 或向按钮添加 #selector
,但我做不到
我创建了一个通用的 UIViewRepresentable
结构来帮助我在我的 SwiftUI 视图中嵌入任何 UIView,遵循这个 tutorial:
struct Anything<Wrapper : UIView>: UIViewRepresentable {
typealias Updater = (Wrapper, Context) -> Void
var makeView: () -> Wrapper
var update: (Wrapper, Context) -> Void
init(_ makeView: @escaping @autoclosure () -> Wrapper,
updater update: @escaping (Wrapper) -> Void) {
self.makeView = makeView
self.update = { view, _ in update(view) }
}
func makeUIView(context: Context) -> Wrapper {
makeView()
}
func updateUIView(_ view: Wrapper, context: Context) {
update(view, context)
}
}
我有以下代码:
import SwiftUI
import FluentUI
struct MyView: View {
@State var isGreen = true
var body: some View {
VStack {
Text("Hello, World!")
.background(isGreen ? Color.green : Color.blue)
Spacer().frame(height: 20)
Anything(FluentUI.Button(style: .primaryFilled)) {
[=11=].setTitle("Try me!", for: .normal)
}
.frame(height: 30)
.padding()
}
}
}
struct Anything<Wrapper: UIView>: UIViewRepresentable {
typealias Updater = (Wrapper, Context) -> Void
var makeView: () -> Wrapper
var update: (Wrapper, Context) -> Void
var action: (() -> Void)?
init(_ makeView: @escaping @autoclosure () -> Wrapper,
updater update: @escaping (Wrapper) -> Void) {
self.makeView = makeView
self.update = { view, _ in update(view) }
}
func makeUIView(context: Context) -> Wrapper {
makeView()
}
func updateUIView(_ view: Wrapper, context: Context) {
update(view, context)
}
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
MyView()
}
}
如果我尝试添加这个:
[=12=].addTarget(self, action: #selector(toggleColor), for: .touchUpInside)
有:
func toggleColor() {
isGreen = !isGreen
}
我收到这个错误:
Argument of '#selector' refers to instance method 'toggleColor()' that is not exposed to Objective-C
如果我将 @objc
添加到方法中,我会收到此错误:
@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
并且由于我的 Anything
结构不是来自 SwiftUI 的 Button
,我无法正常添加 action
参数
如何用这种方式将 target/action 添加到我的按钮?
这是一个可能解决方案的演示 - 我们需要在 UIKit objective-c 选择器和 SwiftUI swift 函数之间进行包装。
测试 Xcode 13.3 / iOS 15.4
这是主要部分(为简单起见,使用 UIButton 而不是 FluentUI.Button):
Anything(UIButton(type: .system)) {
[=10=].setTitle("Try me!", for: .normal)
[=10=].addTarget(toggleColor, action: #selector(Action.perform(sender:)), for: .touchUpInside)
toggleColor.action = {
isGreen.toggle()
}
}
我正在使用 FluentUI#button
,它后面使用了 UIKit
我需要在 SwiftUI 视图中显示该按钮,我正在尝试切换 @State
属性 或向按钮添加 #selector
,但我做不到
我创建了一个通用的 UIViewRepresentable
结构来帮助我在我的 SwiftUI 视图中嵌入任何 UIView,遵循这个 tutorial:
struct Anything<Wrapper : UIView>: UIViewRepresentable {
typealias Updater = (Wrapper, Context) -> Void
var makeView: () -> Wrapper
var update: (Wrapper, Context) -> Void
init(_ makeView: @escaping @autoclosure () -> Wrapper,
updater update: @escaping (Wrapper) -> Void) {
self.makeView = makeView
self.update = { view, _ in update(view) }
}
func makeUIView(context: Context) -> Wrapper {
makeView()
}
func updateUIView(_ view: Wrapper, context: Context) {
update(view, context)
}
}
我有以下代码:
import SwiftUI
import FluentUI
struct MyView: View {
@State var isGreen = true
var body: some View {
VStack {
Text("Hello, World!")
.background(isGreen ? Color.green : Color.blue)
Spacer().frame(height: 20)
Anything(FluentUI.Button(style: .primaryFilled)) {
[=11=].setTitle("Try me!", for: .normal)
}
.frame(height: 30)
.padding()
}
}
}
struct Anything<Wrapper: UIView>: UIViewRepresentable {
typealias Updater = (Wrapper, Context) -> Void
var makeView: () -> Wrapper
var update: (Wrapper, Context) -> Void
var action: (() -> Void)?
init(_ makeView: @escaping @autoclosure () -> Wrapper,
updater update: @escaping (Wrapper) -> Void) {
self.makeView = makeView
self.update = { view, _ in update(view) }
}
func makeUIView(context: Context) -> Wrapper {
makeView()
}
func updateUIView(_ view: Wrapper, context: Context) {
update(view, context)
}
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
MyView()
}
}
如果我尝试添加这个:
[=12=].addTarget(self, action: #selector(toggleColor), for: .touchUpInside)
有:
func toggleColor() {
isGreen = !isGreen
}
我收到这个错误:
Argument of '#selector' refers to instance method 'toggleColor()' that is not exposed to Objective-C
如果我将 @objc
添加到方法中,我会收到此错误:
@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
并且由于我的 Anything
结构不是来自 SwiftUI 的 Button
,我无法正常添加 action
参数
如何用这种方式将 target/action 添加到我的按钮?
这是一个可能解决方案的演示 - 我们需要在 UIKit objective-c 选择器和 SwiftUI swift 函数之间进行包装。
测试 Xcode 13.3 / iOS 15.4
这是主要部分(为简单起见,使用 UIButton 而不是 FluentUI.Button):
Anything(UIButton(type: .system)) {
[=10=].setTitle("Try me!", for: .normal)
[=10=].addTarget(toggleColor, action: #selector(Action.perform(sender:)), for: .touchUpInside)
toggleColor.action = {
isGreen.toggle()
}
}