#swift #swiftui #uikit
#быстрый #свифтуи #uikit
Вопрос:
Я новичок в swift, и у меня возникает проблема, заставляющая мои части кода SwiftUI и UIKit взаимодействовать друг с другом.
У меня есть переменная в моем SwiftUI, которую я хочу перенести в часть UIKit или наоборот.
Это мой код swfitUI, и я хочу перейти someString
к коду UIKit
struct ForceTestView: View {
//MARK: - PROPERTIES
//MARK: - BODY
var body: some View {
VStack(spacing: 20){
TouchesSwiftUI()
.border(Color.gray, width: 5)
.frame(maxWidth: 200, maxHeight: 200)
Text("(someString)")
.onTapGesture {
someString = "New Value"
}
}//:VSTACK
}//: BODY
struct TouchesSwiftUI: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> TouchesHelper {
let touchControl = TouchesHelper()
return touchControl
}
func updateUIViewController(_ uiViewController: TouchesHelper, context: Context) {
}
}
Это код UIKit, который у меня есть
import Foundation
import UIKit
import SwiftUI
import Combine
class TouchesHelper: UIViewController{
var forceLabel: UILabel!
var forceText: String = "frcTxt Empty"
var xPosLabel: UILabel!
override func loadView() {
view = UIView()
view.backgroundColor = .white
forceLabel = UILabel()
forceLabel.translatesAutoresizingMaskIntoConstraints = false
forceLabel.textAlignment = .left
forceLabel.font = UIFont.systemFont(ofSize: 18)
forceLabel.text = "Force Readings"
forceLabel.numberOfLines = 0
view.addSubview(forceLabel)
xPosLabel = UILabel()
xPosLabel.translatesAutoresizingMaskIntoConstraints = false
xPosLabel.textAlignment = .left
xPosLabel.font = UIFont.systemFont(ofSize: 18)
xPosLabel.text = "Finger X Position"
xPosLabel.numberOfLines = 0
view.addSubview(xPosLabel)
NSLayoutConstraint.activate([
forceLabel.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
forceLabel.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
xPosLabel.topAnchor.constraint(equalTo: forceLabel.bottomAnchor),
xPosLabel.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
])
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let userForce = touch.force
forceLabel.text = "Force: (userForce)"
forceText = "(userForce)"
print("UI (testString)")
}//:if touch
}//: touchesMoved
}
Я хотел бы передать userForce в SwiftUI, а затем обновить что-то вроде userxPosLabel с помощью ввода текста из SwiftUI
Я попытался взглянуть на объекты и координаторов @Obverbable, но они на самом деле не имеют смысла или не работают, потому что они не помогают передавать вещи, связанные с событиями касания в touchesMoved (я кодирую это для проекта, который использует iPhoneX, у которого был 3D touch)
Любая помощь будет очень признательна!
Спасибо!
Ответ №1:
Есть несколько разных способов, которыми вы можете подойти к специфике этого, но ваша склонность использовать ObservableObject
то, что вы упомянули, является хорошей.
Сначала код, а затем некоторые пояснения:
class ViewModel : ObservableObject {
@Published var force : String = ""
@Published var xPos : String = ""
}
struct ContentView : View {
@StateObject var viewModel = ViewModel()
//MARK: - BODY
var body: some View {
VStack(spacing: 20){
TouchesSwiftUI(viewModel: viewModel, force: viewModel.force, xPos: viewModel.xPos)
.border(Color.gray, width: 5)
.frame(maxWidth: 200, maxHeight: 200)
Text(viewModel.force)
.onTapGesture {
viewModel.force = "New Value"
}
Text(viewModel.xPos)
}//:VSTACK
}//: BODY
}
struct TouchesSwiftUI: UIViewControllerRepresentable {
var viewModel : ViewModel
var force: String
var xPos: String
func makeUIViewController(context: Context) -> TouchesHelper {
let touchControl = TouchesHelper()
return touchControl
}
func updateUIViewController(_ uiViewController: TouchesHelper, context: Context) {
uiViewController.viewModel = viewModel
uiViewController.forceLabel.text = force
uiViewController.xPosLabel.text = xPos
}
}
class TouchesHelper: UIViewController{
var viewModel : ViewModel?
// {
// didSet {
// guard let viewModel = viewModel else { return }
// cancellable = viewModel.objectWillChange.sink(receiveValue: { _ in
// DispatchQueue.main.async {
// forceLabel.text = viewModel.force
// xPosLabel.text = viewModel.
// }
// })
// }
// }
var forceLabel: UILabel!
var xPosLabel: UILabel!
private var cancellable : AnyCancellable?
override func loadView() {
view = UIView()
view.backgroundColor = .white
forceLabel = UILabel()
forceLabel.translatesAutoresizingMaskIntoConstraints = false
forceLabel.textAlignment = .left
forceLabel.font = UIFont.systemFont(ofSize: 18)
forceLabel.text = "Force Readings"
forceLabel.numberOfLines = 0
view.addSubview(forceLabel)
xPosLabel = UILabel()
xPosLabel.translatesAutoresizingMaskIntoConstraints = false
xPosLabel.textAlignment = .left
xPosLabel.font = UIFont.systemFont(ofSize: 18)
xPosLabel.text = "Finger X Position"
xPosLabel.numberOfLines = 0
view.addSubview(xPosLabel)
NSLayoutConstraint.activate([
forceLabel.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
forceLabel.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
xPosLabel.topAnchor.constraint(equalTo: forceLabel.bottomAnchor),
xPosLabel.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
])
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let userForce = touch.force
//forceLabel.text = "Force: (userForce)"
//xPosLabel.text = "X: (touch.location(in: self.view).x)"
viewModel?.force = "(userForce)"
viewModel?.xPos = "X: (Int(touch.location(in: self.view).x))"
}//:if touch
}//: touchesMoved
}
Что происходит:
ViewModel
содержит общее состояние. Это управляет тем, чтоText
находится на ярлыках SwiftUI,ContentView
и передается наTouchesSwiftUI
который, в свою очередь, передает егоTouchesHelper
- В
touchesMoved
,TouchesHelper
обновленияViewModel
— изменения в метках в конечном итоге распространяются обратно наTouchesHelper
updateUIViewController
- Вы можете видеть, что ваш
onTapGesture
влияет на состояние, как и следовало ожидатьContentView
, как вTouchesHelper
- Я оставил немного комментариев в
TouchesHelper
— это просто для того, чтобы показать, что если вы хотите подписаться на обновления через издателейViewModel
, вы можете сделать это, чтобы изменить текст метки, а не передавать ее обратноupdateUIViewController
Комментарии:
1. Большое спасибо mcuh за подробный код и объяснение, вы даже не представляете, как это помогло! Я потратил три дня на поиски решения, а ты сделал это за один день! Опять же, я действительно ценю вашу помощь, вы не знаете, что это значит для меня 🙂
2. Фантастика. Рад, что это помогло. Поскольку это было полезно, вы также можете щелкнуть стрелку вверх рядом с ответом, чтобы «проголосовать» за него в дополнение к его принятию.
3. Да! извините, все еще новичок на форуме, да, я только что поддержал ответ и ваш комментарий, надеюсь, он показывает, что он не может быть общедоступным, потому что я новый пользователь, но я проверю через пару дней и посмотрю, прошло ли это!