Issues with setting layout of objects in widget on iPhone 6 Plus - iphone

I have added a widget to my app but I am having issues with running it on the iPhone 6 Plus.
Basically, the issue is that the iPhone 6 Plus has borders around the notification centre, whereas every other screen size does not. The way I have programmed my widget means that labels are getting cut off on the iPhone 6 Plus as I am not using Auto-Layout.
I have tried adding some code that changes the position of the labels if the widget detects it is being run on an iPhone 6 Plus. For some reason the code doesn't seem to be working however.
Here is my code:
totalBudgetDisplay.frame.origin.x = UIScreen.mainScreen().bounds.width - 186
currentBudgetDisplay.frame.origin.x = UIScreen.mainScreen().bounds.width - 186
budgetNameDisplay.frame.origin.x = 16
warningLabel.center = view.center
button.frame = CGRectMake(0, 0, view.bounds.width, view.bounds.height)
var height = UIScreen.mainScreen().bounds.size.height
if UIDevice.currentDevice().orientation.isLandscape && height == 540 {
totalBudgetDisplay.frame.origin.x = UIScreen.mainScreen().bounds.width - 250
currentBudgetDisplay.frame.origin.x = UIScreen.mainScreen().bounds.width - 250
budgetNameDisplay.frame.origin.x = 80
warningLabel.center = view.center
button.frame = CGRectMake(0, 0, view.bounds.width, view.bounds.height)
}
Any ideas?
EDIT:
I should mention that the issue is that the labels do not move when run on iPhone 6 Plus. They just stay in the positions that they should be for other screens. I'm not sure if I am checking for the wrong height or something? Also, it's only an issue in landscape orientation.

Related

Constrain/center CAEmitterLayer even after device rotation

In Swift Playgrounds for iPad, I am having difficulty constraining CAEmitterLayer instance to the center permanently. For example, it stays centered until the device is rotated, so I need to find some way to constrain it to the center for all device orientations.
Here is what I have so far, keep in mind I’ve tried adding observers to device orientation with no avail. But this could just be an error on my part. Thanks!
emitterLayer.emitterPosition = CGPoint(x: view.center.x, y: view.center.y)
let cell = CAEmitterCell()
cell.birthRate = 25
cell.lifetime = 30
cell.velocity = 250
cell.velocityRange = 250
cell.spinRange = 5
cell.scale = 0.04
cell.scaleRange = 0.03
cell.alphaSpeed = -0.15
cell.emissionRange = CGFloat.pi * 2
cell.contents = UIImage(named: "RainbowApple")?.cgImage
emitterLayer.emitterCells = [cell]
emitterLayer.beginTime = CACurrentMediaTime()
emitterLayer.zPosition = -1
view.layer.addSublayer(emitterLayer)
emitterLayer.emitterSize = CGSize(width: 320, height: 1)
emitterLayer.renderMode = CAEmitterLayerRenderMode.oldestLast
CALayer does not support constraints. It looks like you want to do this in a UIViewController so move the line emitterLayer.emitterPosition = CGPoint(x: view.center.x, y: view.center.y) into viewDidLayoutSubviews which gets called every time your views bounds change (ie during rotation). This will always keep your emitter in the center, even if the center changes for another reason, such as split screen multitasking on iPad.

Header Logo is wrong size on Swift 4 / XCode 9 / iOS 11

I just updated XCode to version 9, and when running my project with no major changes, the title logo has increased its size to fill the header. Before upgrading, its size covered around 50% of the navigation bar as I intended to.
The code where I position the logo is the following:
//Logo on NavBar
let logo = UIImage(named: "logo.png")
let imageView = UIImageView(image:logo)
imageView.height = (self.navigationController?.navigationBar.height)! - 25
imageView.contentMode = .scaleAspectFit
self.navigationItem.titleView = imageView
Here's how the logo used to (and it's supposed to) look:
And after the XCode update, this is how it looks:
Any ideas of why this might be happening?
I've had the same problem - just appearing in iOS 11.
So i've set a height and a width constraint for the imageview programmatically.
imageView.widthAnchor.constraint(equalToConstant: YOUR_WIDTH).isActive = true
imageView.heightAnchor.constraint(equalToConstant: YOUR_HEIGHT).isActive = true
To make the same in iOS 11, add a subView in the titleView and resize it as you like.
let imagen = UIImageView(frame: CGRect(x: -view.view.frame.width/3, y: -(view.navigationController?.navigationBar.frame.height)! / 2, width: view.view.frame.width/1.5 , height: (view.navigationController?.navigationBar.frame.height)!))
imagen.image = #imageLiteral(resourceName: "logo")
view.navigationItem.titleView = UIView()
view.navigationItem.titleView?.addSubview(imagen)

Why are the positions of my nodes different on every device?

Ok, so I've been trying to position a line on my iPhone 6s+ and my iPad 2. The line was added in an SKCamera (I don't know if that effects it or not). Here is the code for the line:
var leftWall = SKSpriteNode()
leftWall.size = CGSize(width: 1, height: 10000)
leftWall.position = CGPoint(x: 0, y: 0)
leftWall.color = UIColor.red
leftWall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: leftWall.size.width, height: leftWall.size.height))
leftWall.physicsBody?.affectedByGravity = false
leftWall.physicsBody?.isDynamic = false
leftWall.physicsBody?.categoryBitMask = groundGroup
leftWall.physicsBody?.collisionBitMask = ballGroup
leftWall.physicsBody?.contactTestBitMask = 0
theCamera.addChild(leftWall)
Okay, so the x position is 0,0 right? Here is how it looks on my iPhone 6s+:
As you see, the line is in the middle?
Here is how it looks on my iPad 2:
I just don't understand why the position of the line is completely different.. Please help me!
You are not taking into account the cropping that happens on the iPad, or your scaleMode is all wrong
What you need to do is set all nodes anchor points (Including the scene) to (0.5,0.5), make sure your GameScene has a static size and not based on view.frame (750,1334 is a good one) and that your scale mode is set to .aspectFill. This makes (0,0) the center of the screen, and you will notice everything line up on all devices

How to properly display a HUD on a SpriteKit game across different resolutions?

I originally created my game with iOS 8 and tested on my iPhone 6S. The game looks fine in the 5, 5S, 6, 6 Plus, 6S, and 6S Plus (since all devices have the same ratio of 16:9). As you can see from the image, the music button is offset from the top right corner. The image is offset by this code:
muteButton.position = CGPoint(x: CGRectGetMidX(self.frame) + 920, y: CGRectGetMidY(self.frame) + 480)
The problem I have is if someone tried this game on an iPad, it will display this. As you can see, the bottom graphic and the mute button are offset from the sides by a lot.
I want to make it so that the objects will always stay close to the sides of the frame/view. Making the app "universal" on xCode does not fix it either. Or do I just make a completely new project built for the iPad?
Don't forget about the 4s, you will get the same problems as iPad. SpriteKit does not have constraints like in the UI builder, so you are going to have to accommodate for the 4:3 and the 16:9 devices by applying some math, or force the 4:3 to be 16:9 with black borders using the .AspectFit scaling method.
Now I am not sure where 920, and 480 are coming from, but those numbers may have to be tweaked in this code when detecting the device. Simplest way to determine your aspect ration is to do UIScreen.mainScreen().bounds.width/UIScreen.mainScreen().bounds.height, then work from there.
Solution! I figured it out! For those who come from the future and also might need help with this. This works with landscape orientation and portrait orientation.
Note: You must have your scene.scaleMode set to .AspectFill for this to work on all scenes and the scene size has to be 2048x1536 or 1536x2048. This will make it scaleable for iPad too.
I have declared the following variable on the top of my class.
class StartScene: SKScene {
let playableArea: CGRect
}
Then, I have the following code inside the override init() function.
override init(size: CGSize) {
//1. Get the aspect ratio of the device
let deviceWidth = UIScreen.mainScreen().bounds.width
let deviceHeight = UIScreen.mainScreen().bounds.height
let maxAspectRatio: CGFloat = deviceWidth / deviceHeight
//2. For landscape orientation, use this*****
let playableHeight = size.width / maxAspectRatio
let playableMargin = (size.height - playableHeight) / 2.0
playableArea = CGRect(x: 0, y: playableMargin, width: size.width, height: playableHeight)
//3. For portrait orientation, use this*****
let playableWidth = size.height / maxAspectRatio
let playableMargin = (size.width - playableWidth) / 2.0
playableArea = CGRect(x: playableMargin, y: 0, width: playableWidth, height: size.height)
super.init(size: size)
}
From here, I then use the variable playableArea to position my objects.
titleChild.position = CGPoint(x: CGRectGetMidX(playableArea), y: CGRectGetMaxY(playableArea) - (titleChild.size.height * 0.90))
Works amazing. Looks good in the iPhone 4S, 5, 5S, 6, 6 Plus, 6S, 6S Plus, and iPads.
If you want to see the box in the app to make sure you did it right, use the following function.
func drawPlayableArea() {
let shape = SKShapeNode()
let path = CGPathCreateMutable()
CGPathAddRect(path, nil, playableArea)
shape.path = path
shape.strokeColor = SKColor.redColor()
shape.lineWidth = 8
addChild(shape)
}
Then just call the function in the didMoveToView() function to view the red frame to make sure you did the code right. This will create a red frame the size of the view that is viewable to the user. Now that you have playableArea to hold the frame that the user can see, you can use it for other things such as making sure objects don't or can't leave the bounds, etc. For this screenshot, I use it to prevent the user from moving the spaceship outside the device.

UILabel sizeThatFits returns different values for different devices. Why?

In my swift project I need to resize a UILabel to fit a text. I use sizeThatFits to calculate the size. However the results vary enormously among the devices. The width is limited to 280 points. For iPhone 5/s the height is calculated to 19 but for iPhone 4s it is 115. iPhone 6+ determines it should be a lot more.
This is the entire code snippet. For testing I have used fixed width rather than the calculated values. The label is set to be the full size of its superview in storyboard. That is why I change the bottom constraint to do the resizing. Any idea why the different devices get different values even when width is set to the same value?
var bounds = UIScreen.mainScreen().bounds
let attrStr = self.infoLabel.attributedText
var width = bounds.width - 40
let size = self.infoLabel.sizeThatFits(CGSizeMake(bounds.width - 40, bounds.height))
let delta = (self.infoLabel.frame.size.height) - size.height
bottomConstaint.constant += delta
Used self.view.bounds rather than UIDevice.mainScreen().bounds, and moved it from viewWillAppear to viewDidLayoutSubviews, and got a perfect result for all devices.