在SpriteKit场景中添加UITextField不显示,求正确实现方案
SpriteKit场景中UITextField不显示的问题解决
你的代码问题分析
UITextField不显示的核心原因是添加时机错误:
在init(size:)方法中尝试访问self.view并添加子视图时,Scene还未被附加到SKView上,self.view此时大概率为nil,导致添加UITextField的代码块完全没有执行。
另外还有坐标系的潜在问题:SpriteKit的坐标系原点在屏幕左下角,而UIKit的坐标系原点在左上角,直接用UIKit的frame计算位置,会导致控件位置和你预期的SpriteKit场景布局错位。
修正方案
1. 调整UITextField的添加时机
把添加UITextField的代码移到didMove(to view:)方法中,这个方法会在Scene被成功添加到SKView后调用,此时self.view已经有效:
override func didMove(to view: SKView) { let textFieldWidth: CGFloat = 200 let textFieldHeight: CGFloat = 50 // 转换SpriteKit居中坐标到UIKit坐标系 let sceneCenter = CGPoint(x: size.width/2, y: size.height/2) let viewCenter = view.convert(sceneCenter, from: self) let textFieldFrame = CGRect( x: viewCenter.x - textFieldWidth/2, y: viewCenter.y - textFieldHeight/2, width: textFieldWidth, height: textFieldHeight ) self.editCharName = UITextField(frame: textFieldFrame) self.editCharName.placeholder = "Enter character name" self.editCharName.borderStyle = .roundedRect self.editCharName.delegate = self view.addSubview(self.editCharName) }
同时让CharacterCreatorView遵守UITextFieldDelegate协议,方便处理输入事件:
class CharacterCreatorView: SKScene, UITextFieldDelegate { // ... 原有代码 ... // 处理输入完成事件 func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() if let name = textField.text { self.charName = name } return true } }
2. 适配SpriteKit的替代方案(纯SpriteKit风格)
如果不想混用UIKit控件,可以用SKLabelNode配合点击触发弹窗的方式,更贴合SpriteKit的场景逻辑:
override func didMove(to view: SKView) { // 创建显示角色名的标签 let nameLabel = SKLabelNode(text: charName) nameLabel.position = CGPoint(x: size.width/2, y: size.height/2) nameLabel.fontSize = 30 nameLabel.name = "nameLabel" addChild(nameLabel) // 创建透明点击区域,覆盖标签范围 let tapArea = SKShapeNode(rect: CGRect(x: -100, y: -20, width: 200, height: 40)) tapArea.position = nameLabel.position tapArea.fillColor = .clear tapArea.strokeColor = .clear tapArea.name = "nameTapArea" addChild(tapArea) } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first else { return } let location = touch.location(in: self) let nodes = nodes(at: location) if nodes.contains(where: { $0.name == "nameTapArea" }) { let alert = UIAlertController(title: "修改角色名", message: nil, preferredStyle: .alert) alert.addTextField { textField in textField.text = self.charName textField.placeholder = "输入新名字" } alert.addAction(UIAlertAction(title: "确定", style: .default) { _ in if let newName = alert.textFields?.first?.text, !newName.isEmpty { self.charName = newName if let nameLabel = self.childNode(withName: "//nameLabel") as? SKLabelNode { nameLabel.text = newName } } }) alert.addAction(UIAlertAction(title: "取消", style: .cancel)) self.view?.window?.rootViewController?.present(alert, animated: true) } }
内容的提问来源于stack exchange,提问作者Andrew Nazareth
相关产品推荐
相关产品推荐

