在 Swift 中不断更新 UILabel



我正在创建一个应用程序,该应用程序将在检测到图像时不断更新平面节点的坐标。但是,我想知道我将如何做到这一点。我的代码如下:

extension ViewController: ARSCNViewDelegate {
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
guard let imageAnchor = anchor as? ARImageAnchor,
var imageName = imageAnchor.referenceImage.name  else { return }
let planeNode = self.getPlaneNode(withReferenceImage: imageAnchor.referenceImage)
planeNode.opacity = 1.0
planeNode.eulerAngles.x = -.pi / 2
planeNode.runAction(self.fadeAction)
node.addChildNode(planeNode)
let nodeCam = self.sceneView.session.currentFrame!.camera
let cameraTransform = nodeCam.transform
planeNode.position.x = cameraTransform.columns.3.x + 1
planeNode.position.y = cameraTransform.columns.3.y + 1

if imageName == "sample" {
self.imageOne.text = ""(imageName)""
self.instructions.text = "IMAGE DETECTED: "(imageName)""
self.coordinateView.isHidden = false
self.updateOne.isHidden = false
self.coordinateX.text = "X: " + String(planeNode.position.x)
self.coordinateY.text = "Y: " + String(planeNode.position.y)
}

如何使坐标 X 和坐标 Y 对应的标签在平面节点移动时不断变化和更新?我尝试过重复循环,其中:

repeat {
self.coordinateX.text = "X: " + String(planeNode.position.x)
self.coordinateY.text = "Y: " + String(planeNode.position.y)
} while imageName == "sample" 

但这只会导致代码在检测到图像时冻结。有什么建议吗?

这里有两个选项;您可以设置一个 DispatchSource,用于注册计划事件并建立处理程序。 该处理程序可以是将点设置为标签的函数。例:

func startUpdating() {
timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
timer?.schedule(deadline: DispatchTime.now(),
repeating: DispatchTimeInterval.milliseconds(16),
leeway: .milliseconds(5))
timer?.setEventHandler(qos: .userInitiated, flags: [], handler: self.update)
timer?.resume()
}
func update() {
coordinateX.title = String(planeNode.position.x)
coordinateY.title = String(planeNode.position.y)
}

如果您认为数据会在短时间内大量更新/更改,这非常有用。

如果您认为这不会发生,那么我将使用"didSet"来监视变量并在"didSet"函数中设置该函数。

假设我有一个叫做BlackMirrorzARReferenceImage

在以下ARSCNViewDelegate中。 方法,当检测到ARReferenceImage时,我正在加载我的模型:

//-------------------------
//MARK: - ARSCNViewDelegate
//-------------------------
extension ViewController: ARSCNViewDelegate{
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//1. Check We Have A Valid Image Anchor
guard let imageAnchor = anchor as? ARImageAnchor else { return }
//2. Get The Detected Reference Image
let referenceImage = imageAnchor.referenceImage
//3. Load Our Model Only If Our Reference Image Name Is Valid & The Model Hasnt Already Been Placed
if let matchedTargetImageName = referenceImage.name, matchedTargetImageName == "BlackMirrorz" && !modelPlaced {
//a. Set Our Model To The Size Of The ReferenceImage
let model = SCNNode(geometry: SCNPlane(width: referenceImage.physicalSize.width, height: referenceImage.physicalSize.height))
//b. Rotate It
model.eulerAngles.x = -.pi/2
//c. Add It To Our Node
node.addChildNode(model)
//d. Name Our Node
node.name = matchedTargetImageName
}
}
}

这里重要的是最后一行代码;在其中,我为ARImageAnchor's节点提供了一个名称,这将使我们以后很容易跟踪。

加载模型后,我们可以使用以下ARSessionDelegate方法:

func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) { }

这很简单:

告知委托会话已调整一个属性 或更多锚点。

因此,很容易用ARImageAnchor的当前坐标更新任何LabelsSCNText's或类似内容,例如:

//--------------------------
//MARK: -  ARSessionDelegate
//--------------------------
extension ViewController: ARSessionDelegate{
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
//1. Enumerate Through Our Current ARAnchors
for anchor in anchors{
//2. If We Have An ARImageAnchor Then Get The Corresponding Node & Check That It's Name Is The One We Want To Track
if let imageAnchor = anchor as? ARImageAnchor,
let targetNode = self.augmentedRealityView.node(for: imageAnchor), targetNode.name == "BlackMirrorz"{
//3. Get The Transform For The Anchor And Log This To The Console Or Update Your Labels
print("""
Current Position X Of Anchor = (imageAnchor.transform.columns.3.x)
Current Position Y Of Anchor = (imageAnchor.transform.columns.3.y)
Current Position Z Of Anchor = (imageAnchor.transform.columns.3.z)
""")
}
}
}
}

希望它能为你指明正确的方向...

最新更新