I have made my Viewcontroller to a SKview so I can add things.
let skview: SKView = {
let view = SKView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
self.view.addSubview(skview)
skview.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
skview.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
skview.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
skview.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
self.addchild(player) doesn't work.
You can't add a sprite to a view controller. You can't neither add a sprite to a SKView. You must first create a SKScene and present it:
let scene = SKScene(size: skview.bounds.size)
skview.presentScene(scene)
Then you can add sprites to the scene:
scene.addChild(player)
Related
Before presenting my GameScene I apply the safeAreaLayoutGuide to the initial view screen (code below is from GameViewController).
If at any point before I call view.presentScene(scene) I try to get the view's frame, I get back an empty set.
If however I get the frame, after presenting the scene, I get the rect for the full screen, even though the view does appear within the safeAreaLayoutGuide.
How can I get the view's safe adjusted screen coordinates? I should note I am doing this so I can apply the proper constraints to my GameScene, as I can only find how to do it for UIView.
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView?{
let screenWidthInPoints = UIScreen.main.bounds.width
let screenHeightInPoints = UIScreen.main.bounds.height
let imageView = UIView()
imageView.backgroundColor = .red
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
imageView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor , constant: -0).isActive = true
let scene = GameScene(size: CGSize(width: screenWidthInPoints,
height: screenHeightInPoints))
scene.backgroundColor = .black
scene.scaleMode = .aspectFit
view.presentScene(scene)
var myRect = view.frame
UIScreen.main.bounds represents the entire screen, not just the safe area. You will have to create a separate view constrained to safe area insets to get the proper safe area size. In your case, you already have an imageView placed within the safe area. Try printing out its size after adding the constraints and do it within a DispatchQueue.main.async to make sure that it gets called only after the current pass layout is complete.
let imageView = UIView()
imageView.backgroundColor = .red
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
imageView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor , constant: -0).isActive = true
DispatchQueue.main.async {
print("imageView.frame: ", imageView.frame)
let scene = GameScene(size: CGSize(width: imageView.frame.width,
height: imageView.frame.height))
scene.backgroundColor = .black
scene.scaleMode = .aspectFit
view.presentScene(scene)
}
I tried to add a subview to my GameViewController (because I want to add a banner ad at the bottom). I created it as follows:
if let view = self.view as! SKView? {
let subView = SKView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 415, height: 685)))
view.addSubview(subView)
if let scene = SKScene(fileNamed: "GameScene") {
scene.scaleMode = SKSceneScaleMode.aspectFit
subView.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = false
view.showsNodeCount = false
view.showsDrawCount = false
addBannerViewToView(bannerView)
}
}
This works initially - it presents my GameScene. But later, I ask my GameScene to present another subclass of SKScene that I created, which I call Shop, using the following code:
func initializeShop() {
let shop = Shop(size: self.size)
let transition = SKTransition.fade(withDuration: 0.1)
self.view?.presentScene(shop!, transition: transition)
}
And it simply does not present. It remains on the current view.
This works completely fine if I do NOT add a subview to the initial view in the GameViewController, i.e.
if let view = self.view as! SKView? {
if let scene = SKScene(fileNamed: "GameScene") {
scene.scaleMode = SKSceneScaleMode.aspectFit
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = false
view.showsNodeCount = false
view.showsDrawCount = false
}
}
So it seems like there is some property of the GameViewController's default SKView that allows presentation, but not a subview. But I can't find any documentation that says that - from what I can tell, all SKViews should be able to present SKScenes.
Any help would be much appreciated.
I'm trying to add a GestureRecognizer to a UIView which is an arranged subview of a UIStackView. I tried already this this or this. Also I tried to enable all underlying views for userInteraction, but it didn't work.
When I add the gesture recognizer to the imageView which is the parent view of the stackView, then the tap works. Strangely it also get's triggered when I tap on the "bannerView" which is a subview of the stackView and therefore lies on top of the imageView.
What's the proper way to get the tap gesture recognize on top of a stackViews's arrangedSubview?
Here my code:
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
var imageView: UIImageView!
var bannerStackView: UIStackView!
var bannerView: UIView!
override func loadView() {
let view = UIView()
view.backgroundColor = .white
self.view = view
setupImageView()
setupBannerStackView()
setupConstraints()
}
func setupImageView() {
let image = UIImage(named: "Apple.jpeg")
imageView = UIImageView(image: image)
imageView.backgroundColor = .red
view.addSubview(imageView)
}
func setupBannerStackView() {
bannerStackView = UIStackView()
bannerStackView.axis = .vertical
bannerStackView.alignment = .leading
bannerStackView.distribution = .equalCentering
bannerStackView.isUserInteractionEnabled = true
bannerView = UIView()
bannerView.backgroundColor = .blue
bannerStackView.addArrangedSubview(bannerView)
imageView.addSubview(bannerStackView)
/*
Also tried this but didn't work
*/
// let tapGesture = UITapGestureRecognizer(target: self, action:
#selector(onBannerTapped))
// bannerView.isUserInteractionEnabled = true
// bannerView.isUserInteractionEnabled = true
// bannerView.addGestureRecognizer(tapGesture)
for bannerView in bannerStackView.arrangedSubviews {
let tapGesture = UITapGestureRecognizer(target: self, action:
#selector(onBannerTapped))
bannerView.isUserInteractionEnabled = true
bannerView.addGestureRecognizer(tapGesture)
}
}
#objc func onBannerTapped() {
print("Banner view tapped!")
}
func setupConstraints() {
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 200).isActive = true
bannerStackView.translatesAutoresizingMaskIntoConstraints = false
bannerStackView.topAnchor.constraint(equalTo: imageView.topAnchor, constant: 10).isActive = true
bannerStackView.leadingAnchor.constraint(equalTo: imageView.leadingAnchor).isActive = true
bannerView.translatesAutoresizingMaskIntoConstraints = false
bannerView.heightAnchor.constraint(equalToConstant: 30).isActive = true
bannerView.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
}
.isUserInteractionEnabled cascades to subviews. So, even if I set it to true on a subview, if the subview's superview (or its superview, and on up the hierarchy) has .isUserInteractionEnabled set to false, the subview will not get touch events.
So, the first thing to do is check .isUserInteractionEnabled on each view in the hierarchy.
In your func, remove this line:
bannerStackView.isUserInteractionEnabled = true
then add these lines after creating your tapGesture:
print("imageView isUserInteractionEnabled:", imageView.isUserInteractionEnabled)
print("bannerStackView isUserInteractionEnabled:", bannerStackView.isUserInteractionEnabled)
print("bannerView isUserInteractionEnabled:", bannerView.isUserInteractionEnabled)
So it looks like this:
func setupBannerStackView() {
bannerStackView = UIStackView()
bannerStackView.axis = .vertical
bannerStackView.alignment = .leading
bannerStackView.distribution = .equalCentering
// remove this line (comment-it out)
// bannerStackView.isUserInteractionEnabled = true
bannerView = UIView()
bannerView.backgroundColor = .blue
bannerStackView.addArrangedSubview(bannerView)
imageView.addSubview(bannerStackView)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onBannerTapped))
bannerView.addGestureRecognizer(tapGesture)
print("view isUserInteractionEnabled:", view.isUserInteractionEnabled)
print("imageView isUserInteractionEnabled:", imageView.isUserInteractionEnabled)
print("bannerStackView isUserInteractionEnabled:", bannerStackView.isUserInteractionEnabled)
print("bannerView isUserInteractionEnabled:", bannerView.isUserInteractionEnabled)
}
You should see this output:
view isUserInteractionEnabled: true
imageView isUserInteractionEnabled: false
bannerStackView isUserInteractionEnabled: true
bannerView isUserInteractionEnabled: true
and that tells you.... you simply need to add:
imageView.isUserInteractionEnabled = true
I'm trying add a subview to UIScrollView. I add scrollView, subView and set constraints bellow :
class ViewController: UIViewController {
let scrollView : UIScrollView = {
let scrollView = UIScrollView()
scrollView.backgroundColor = .yellow
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.alwaysBounceVertical = true
return scrollView
}()
let catImageView : UIImageView = {
let img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.backgroundColor = .white
return img
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
view.addSubview(scrollView)
scrollView.frame = self.view.bounds
scrollView.contentSize = CGSize(width: self.view.frame.width, height: 1000)
scrollView.addSubview(catImageView)
catImageView.centerXAnchor.constraint(equalTo: self.scrollView.centerXAnchor).isActive = true
catImageView.centerYAnchor.constraint(equalTo: self.scrollView.centerYAnchor).isActive = true
catImageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
catImageView.heightAnchor.constraint(equalToConstant: 100).isActive = true
}
I builded and scrollView and subiew are disappear. I don't know why...
Then I trying add subview another way like this :
view.addSubview(catImageView)
catImageView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
catImageView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
catImageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
catImageView.heightAnchor.constraint(equalToConstant: 100).isActive = true
It's still the same. Please explained to me why. Thank a lot
You should only set the translatesAutoresizingMaskIntoConstraints to false in case you are adding the constraints to the view. You've set the property on the scrollView to false, but used the frame, and not constraints. Remove the line:
scrollView.translatesAutoresizingMaskIntoConstraints = false // <- remove
and it should work.
Hope this helps! Good luck!
I just finished my first game and I'm trying this code on my viewController to integrate an ad banner :
import iAd
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var skView = self.originalContentView as SKView
var scene:SKScene = GameScene(size: skView.bounds.size)
skView.showsFPS = false
skView.showsNodeCount = false
skView.showsPhysics = false
let turbulence = SKFieldNode.turbulenceFieldWithSmoothness(0.1, animationSpeed: 0.1)
scene.addChild(turbulence)
let noise = SKFieldNode.turbulenceFieldWithSmoothness(0.4, animationSpeed: 0.1)
scene.addChild(noise)
skView.presentScene(scene)
self.canDisplayBannerAds = true
}
On my firstViewController (the game presentation) it works but not on my gameViewController and I can't understand why.
Someone can help me ?
Thank you all !!!