Adding a small UIView to an SKScene - uitableview

I have a Swift + SpriteKit game in development, in which I would like to insert a small UITableViewController into a small (100 x 200) UIView, and then add that view to my SKScene. I am using this code:
class BugsScene: SKScene {
override func didMoveToView(view: SKView) {
anchorPoint = CGPoint(x: 0.5, y: 0.5)
NSUserDefaults.standardUserDefaults().setObject("bugs", forKey: "lastSceneViewed")
let bugsTableView: BugsTVC = BugsTVC()
let nav = UINavigationController(rootViewController: bugsTableView)
let smallerRect = CGRectMake(0, 0, 100, 200)
let smallerView = UIView(frame: smallerRect)
smallerView.addSubview(nav.view)
self.view.addSubview(smallerView)
}
}
However, in landscape mode (my app only supports landscape left and landscape right, NO portrait), the tableview occupies the entire height of the landscape mode, and has the width of an iPad in portrait.
How do I add a small UIView to a bigger scene in swift/spritekit?

LearnCocos2D definitely deserves credit for this, so if he ever posts an answer I will accept it. Essentially, I was failing to set the frame for the navigation controller's view. Here is my method for adding the smaller view to the scene:
override func didMoveToView(view: SKView) {
anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.name = "Bugs Scene"
backgroundColor = bugsColor
let smallerRect = CGRectMake(400, 24, 600, 720)
let navRect = CGRectMake(0, 0, 600, 720)
let bugsTableView: BugsTVC = BugsTVC()
nav = UINavigationController(rootViewController: bugsTableView)
nav.view.frame = navRect
smallerView = UIView(frame: smallerRect)
smallerView.backgroundColor = UIColor.clearColor()
bugsTableView.view.frame = smallerRect
smallerView.frame = smallerRect
smallerView.addSubview(nav.view)
self.view.addSubview(smallerView)
}
It could probably be refined some but this is working for me. Now if I can only figure out how to remove the view when I transition to another scene!

Related

How to create present bottom view proper position for landscape mode using Swift?

My scenario, I am trying to create present bottom sheet with portrait and landscape compatibility for universal application. Here, I made some animation for bottom view present and dismiss by using view height and static height calculation. Here during portrait mode everything working fine but if I change landscape mode I am getting unaligned bottom sheet position, It is showing top of the screen during landscape mode, some time not showing.
I am using below code,
let cardHeight:CGFloat = 400
let cardHandleAreaHeight:CGFloat = 0
func setupCard() {
visualEffectView = UIVisualEffectView()
visualEffectView.frame = self.view.frame
self.view.addSubview(visualEffectView)
cardViewController = CardViewController(nibName:"CardViewController", bundle:nil)
self.addChild(cardViewController)
self.view.addSubview(cardViewController.view)
cardViewController.view.frame = CGRect(x: 0, y: self.view.frame.height - cardHandleAreaHeight, width: self.view.bounds.width, height: cardHeight)
cardViewController.view.clipsToBounds = true
}
func animateTransitionIfNeeded (state:CardState, duration:TimeInterval) {
if runningAnimations.isEmpty {
let frameAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1) {
switch state {
case .expanded:
self.cardViewController.view.frame.origin.y = self.view.frame.height - self.cardHeight
case .collapsed:
self.cardViewController.view.frame.origin.y = self.view.frame.height - self.cardHandleAreaHeight
}
}
}
Sample image for portrait mode
Sample image Landscape mode

Resizing screen for iPhone X using SpriteKit

So, there are tens of questions on Stack Overflow referencing about fitting a SpriteKit scene properly on the iPhone X. I could not find anyone however, where there is the same gap.
Is there anyway I can resize the screen just for the iPhone X? Or do I have to create another scene, JUST for the iPhone X to fit the screen?
Here is what I am getting using .aspectFit:
I want to extend that scene towards just under the notch and just above where the screen corner curves are. I see many games which fit perfectly, but have not found a suitable solution.
Note: I cannot use aspectFill as some parts of the game go out of view.
Any links or answers will be greatly appreciated!
EDIT
resizeFill is too big, everything gets enlarged
I have tried all 4 options for sizing the screen, but none did the job. Anyone got suggestions?
I feel like the solution is going to be done pragmatically because it will need to be relative to those borders.
Add this to your code it will set the Playable Game Area for both the iPhone X and the regular iPhones and then use the gameArea constant to define how far things can move.
//MARK: Playable Game Araa
let gameArea: CGRect
override init(size: CGSize) {
if UIDevice().userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436 {
//iPhone X
let maxAspectRatio: CGFloat = 19.5/9.0
let playableWidth = size.height / maxAspectRatio
let margin = (size.width - playableWidth) / 2
gameArea = CGRect(x: margin, y: 0, width: playableWidth, height: size.height)
} else {
let maxAspectRatio: CGFloat = 16.0/9.0
let playableWidth = size.height / maxAspectRatio
let margin = (size.width - playableWidth) / 2
gameArea = CGRect(x: margin, y: 0, width: playableWidth, height: size.height)
}
super.init(size: size)
}
We (me and snapbackdev) found a solution, suitable for any phones now or any coming in the future to set the screen to fit the whole view, without stretching or empty spaces.
We ended up doing everything programmatically, which made everything work.
In GameViewController.swift, this code loads the GameScene:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load a GameScene with the size of the view
let scene = GameScene(size: view.frame.size)
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
This may also be done in viewDidLayoutSubviews instead, depending on what you are doing.
The only code needed to setup the scene in GameScene.swift is:
override func didMove(to view: SKView) {
// Set (0, 0) as the centre of the screen
scene?.anchorPoint = CGPoint(x: 0.5, y: 0.5)
// Create the frame
let frameEdge = SKPhysicsBody(edgeLoopFrom: frame)
self.physicsBody = frameEdge
}

UIViewController hidden behind UINavigationController but should be placed below

I'm working on a app where I've got a NavigationBar at the top and added a UIViewController as an RootViewController.
Now my plan was to add a new Subview to this UIViewController. The new Subview extended also of UIViewController. I added de view (Gray Rect) of the controller to the UIViewController but it is placed behind the NavigationBar. I don't want that.. So I searched for a solution and found something interesting..:
When I just add a UIView() (Green Rect) to the UIViewController, the placing of the view works perfectly, as I would love see it from the other UIViewController-View.
My code looks like following:
class DashboardController: UIViewController {
var ccview:ContactCircleController!
override func viewDidLoad() {
super.viewDidLoad()
edgesForExtendedLayout = []
self.view.backgroundColor = .white
let test = UIView()
test.backgroundColor = .green
test.frame = CGRect(x: self.view.frame.width - 200, y: 0, width: self.view.frame.width / 2, height: self.view.frame.width / 2)
self.view.addSubview(test)
setup()
}
func setup(){
ccview = ContactCircleController()
ccview.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width / 2, height: self.view.frame.width / 2)
ccview.edgesForExtendedLayout = UIRectEdge.top
self.view.addSubview(ccview.view)
}}
I've already unchecked the "Extend Edges" - toggle of the navigationcontroller on the storyboard. I also added edgesForExtendedLayout = [] to the UIViewController and for the UIView it worked fine. But for the view of another UIViewController... it didn't worked.
Thank you!
If you use Debug View Hierarchy, you will see that your gray ccview.view is not behind the navigation bar, but rather it is not keeping the height of self.view.frame.width / 2.
This is because the .view of a UIViewController instantiated from Storyboard has by default an .autoresizingMask = [], whereas the .view of a UIViewController instantiated without a storyboard has a default .autoresizingMask = [.flexibleWidth, .flexibleHeight].
You can correct this by changing setup() to:
func setup(){
ccview = ContactCircleController()
ccview.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width / 2, height: self.view.frame.width / 2)
// remove this line
//ccview.edgesForExtendedLayout = UIRectEdge.top
// add this line
ccview.view.autoresizingMask = []
self.view.addSubview(ccview.view)
}

How to size SKView sub view and SKScene correctly

I am trying to get / set the correct size of a subview (SKView).
I am using the storyboard to create a UIView, and a subview that is a SKView. I would like to the programmatically create a SKScene with the dimensions of the SKView.
My thought is that scene.size.height and scene.size.width will be equal to the SKView's height and width. To test this, I am drawing four blue circles in each corner, and red lines on the borders. I am only able to see the bottom left corner, when I am expecting to see all four blue corner dots and boarder lines.
Please ignore the black circles in the Scene, they are irrelevant.
iPhone 6 Screenshot (portrait)
iPhone 6 Screenshot (landscape)
I added SW (South West), SE, NE, and NW labels
ViewController With SKView Reference
This is where I create the SKSCene (see func newGame)
import UIKit
import SpriteKit
class CenterView: UIViewController, ActionDelegate {
#IBOutlet weak private var navBar:UINavigationBar!
#IBOutlet weak private var titleBar:UINavigationItem!
#IBOutlet weak private var gameView:SKView!
var navigation:NavigationDelegate?
var action:ActionDelegate?
var game:GameDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.action = self
newGame()
}
#IBAction func menuClick(sender: AnyObject) {
navigation?.toggleLeftPanel()
}
func setTitleBarTitle(title: String) {
titleBar.title = title
}
func newGame() {
print("skview bounds: \(self.gameView.bounds.size)")
let game = GameScene(size: self.gameView.bounds.size)
self.game = game
game.action = action
game.scaleMode = .ResizeFill
self.gameView.presentScene(game)
}
}
Main.storyboard
Constraints
Adding Corner Circles & Border Lines
if let scene = self.scene {
let dot = SKShapeNode(circleOfRadius: 10)
dot.fillColor = UIColor.blueColor()
dot.position = CGPoint(x: 0,y: 0)
let dot1 = SKShapeNode(circleOfRadius: 10)
dot1.fillColor = UIColor.blueColor()
dot1.position = CGPoint(x: scene.size.width,y: 0)
let dot2 = SKShapeNode(circleOfRadius: 10)
dot2.fillColor = UIColor.blueColor()
dot2.position = CGPoint(x: 0,y: scene.size.height)
let dot3 = SKShapeNode(circleOfRadius: 10)
dot3.fillColor = UIColor.blueColor()
dot3.position = CGPoint(x: scene.size.width,y: scene.size.height)
let left = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 3, height: scene.size.height))
let top = SKShapeNode(rect: CGRect(x: 0, y: scene.size.height, width: scene.size.width, height: 3))
let right = SKShapeNode(rect: CGRect(x: scene.size.width, y: 0, width: 3, height: scene.size.height))
let bottom = SKShapeNode(rect: CGRect(x: 0, y: 0, width: scene.size.width, height: 3))
left.fillColor = UIColor.redColor()
top.fillColor = UIColor.redColor()
bottom.fillColor = UIColor.redColor()
right.fillColor = UIColor.redColor()
scene.addChild(dot)
scene.addChild(dot1)
scene.addChild(dot2)
scene.addChild(dot3)
scene.addChild(left)
scene.addChild(top)
scene.addChild(right)
scene.addChild(bottom)
}
It turned out that my constraints were not set up correctly.
Constraints
Result

Swift CATransition Between Two Views - Slide over effect previous screen turns white

I am trying to animate between two full screen views (same view controller) in swift using CATransition. Looking to replicate (or get close to) navigation view controller push transition. Running into issue where view2 (the new view to present) is sliding over correctly, but view1 (the view underneath) disappears. Basically the view that is being animated is sliding over a white screen, but I want it to slider over the previous screen.
var pushAnimationEffect = CATransition()
override func viewDidLoad() {
super.viewDidLoad()
pageToUIView[i] = UIView()
view1.frame = CGRect(x: 0, y: 0, width: screenSize.width, height: screenSize.height)
view1.center = CGPointMake(screenSize.width/2, screenSize.height/2)
view2.frame = CGRect(x: 0, y: 0, width: screenSize.width, height: screenSize.height)
view2.center = CGPointMake(screenSize.width/2, screenSize.height/2)
view1.layer.addAnimation(pushAnimationEffect, forKey: nil)
view2.layer.addAnimation(pushAnimationEffect, forKey: nil)
self.view.addSubview(view1)
pushAnimationEffect.delegate = self
pushAnimationEffect.duration = 0.4
pushAnimationEffect.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
}
func nextPage() {
pushAnimationEffect.type = kCATransitionMoveIn
pushAnimationEffect.subtype = kCATransitionFromRight
self.view.addSubview(view2)
view1.removeFromSuperview()
}
func prevPage() {
pushAnimationEffect.type = kCATransitionMoveIn
pushAnimationEffect.subtype = kCATransitionFromLeft
self.view.addSubview(view1)
view2.removeFromSuperview()
}
Simplified the code a bit so its easier to read.
Is there a better way to do this? Is there something wrong with the code?
You need to do the view remove on after the animation completes. Use the animationDidStop:finished: delegate method.

Resources