I am making an IOS App in which I am rotating an imageView. Now, All things are complete. But when the rotation is completed. x, y, of that image View is changing .. How to resolve it . I am attaching code and screenshots so that you can easily find my problem.
let i = defaults.integerForKey("myown")
let g = nViews[i].frame
imageViews[i].transform = CGAffineTransformRotate(imageViews[i].transform, recognizer.rotation)
// nViews[i].transform = CGAffineTransformRotate(imageViews[i].transform, recognizer.rotation)
//
recognizer.rotation = 0
if recognizer.state == UIGestureRecognizerState.Ended
{
let f = imageViews[i].frame
// print(f.size.width) -->111.576689146311
// print(f.size.height) -->111.576689146311
// nViews[i].frame = f
nButtons[i].frame = CGRect(x: f.origin.x - 10, y: f.origin.y - 10, width: 25, height: 25)
// imageView.addSubview(nViews[i])
imageView.addSubview(nButtons[i])
}
Now the another view which is on that imageView become rectangular because of that changes.. As shown in screenshot first time when imageView is not rotated the view is perfect but when it rotates view becomes rectangular.. Hope you will understand problem now
Try to use bounds instead of frame: let g = nViews[i].bounds and let f = imageViews[i].bounds. See When to Use Bound and When to use Frame
Related
I have a label in GameScene, there is no auto layout to use here, how I can use CGpoint to make sure this label stay at the same position on different screens.
Below is the code where I put my score label
scoreLabel?.position = CGPoint(x: -size.width / 2 + 120, y: size.height / 2 - 150)
let scoreLabel = //insert functionality of scoreLabel here
scoreLabel?.position = CGPoint(x: size.width + //insert dimention,
y: size.height + //insert dimension)
self.addChild(scoreLabel)
seeing your previous comment, I would suggest you use the following functions, which change the dimensions when they are run on different screen sizes:
AspectFill
AspectFit
ResizeFill
Here is a link that could help you on how to use these functions: Sprite Kit Scene Editor GameScene.sks scene width and height
Hope this helps!
Here is what I put in my View Controller:
var h, w = 1000
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
w = view.frame.width / (view.frame.height / 1000)
let scene = GameScene(size: CGSize(width: w, height: h))
scene.scaleMode = .aspectFill
view.presentScene(scene)
}
}
}
It's handy to know that I make the height of any device 1000. It's much easier to make it universal.
Then I place everything percentage-wise on the screen.
label.position.x = w/2
label.position.y = h/2
label2.position.x = w/2
label2.position.y = h/2 - 50
These lines of code will place 2 labels in the center of the screen. Even if you rotate your device, and even if you use different sized devices. That - 50 I used will always stay the same.
My main takeaway: I create global states of the relative size of the screen.
Helpful tip: I always make my scene's anchor point to be .zero. That way, the min width and height are always 0, and the max height is always 1000.
I'm trying to position a button at a fixed position inside a UIImageView (AspectFit) which itself is inside a UIScrollView. This worked perfectly on my first try when the UIScrollView and the UIImageView containers both covered the whole screen, the button was pinned to a certain location of the image and stayed at position during zooming. You can see the result in the below image.
As you can obviously see there are white borders above and below the image (related to aspect fit) therefore I had to do some calculation to get the margin from top to calculate the "real" y position of the red square. My code looks like this:
let originalImageSize: CGSize = CGSize(width: image.size.width, height: image.size.height)
let aspectRatio = image.size.width/image.size.height;
let requiredHeight = self.view.bounds.size.width / aspectRatio;
let screenHeight = self.view.bounds.height;
let marginTop = (screenHeight - requiredHeight) / 2;
let renderedImageSize: CGSize = CGSize(width: self.view.bounds.width, height: requiredHeight)
let x:Double = 0
let y:Double = 0
let button = UIButton()
button.frame = CGRect(x: Double(renderedImageSize.width/originalImageSize.width) * x,
y: Double(renderedImageSize.height/originalImageSize.height) * y + Double(marginTop),
width: 10, height: 10)
button.backgroundColor = UIColor.red
imageView.addSubview(button)
As you see I calculated the "marginTop" to get the real y position. The square is perfectly located on x: 0 and y:0 (relative to the image). So far so good, this example worked perfectly.
Now I created a new view which contains a navigation bar and tab bar. The scrollView is in between and no longer covers the whole screen but only the area between my navigation and my tab bar. The imageView has the same size like my scrollView. Pretty much the same as in the example above. Now I tried to set my button a specific location again, but this time there is an offset on the y axis of exactly 6 pixels and I have no idea what I'm doing wrong. And to make it even worse when testing it on other devices the offset on the y axis is even bigger than 6 pixels, while the first example works perfectly accross all devices I tested. You can see the result with the "wrong" y-axis value here.
I changed my code to the following, based on the fact that sizes should be calculated according to the "new" scrollView size.
let originalImageSize: CGSize = CGSize(width: image.size.width, height: image.size.height)
let aspectRatio = image.size.width/image.size.height;
let requiredHeight = scrollView.bounds.size.width / aspectRatio;
let screenHeight = scrollView.bounds.height;
let marginTop = (screenHeight - requiredHeight) / 2;
let renderedImageSize: CGSize = CGSize(width: scrollView.bounds.width, height: requiredHeight)
let x:Double = 0
let y:Double = 0
let button = UIButton()
button.frame = CGRect(x: Double(renderedImageSize.width/originalImageSize.width) * x,
y: Double(renderedImageSize.height/originalImageSize.height) * y + Double(marginTop),
width: 10, height: 10)
button.backgroundColor = UIColor.red
imageView.addSubview(button)
A quick workaround would be something likes this, but it is hacky as hell and doesn't work for other device sizes and I obviously want to learn how to do it the right way:
[...] y: Double(renderedImageSize.height/originalImageSize.height) * y + Double(marginTop) - 6, [...]
I've been sitting on this for hours now and still don't have any idea why the y-axis is off even though the calculation of the top margin should be right and why the y axis offset is even bigger now on different devices. I'm thankful for any advice as I'm pretty new to iOS developing and I guess I'm missunderstanding something related to calculating correct sizes.
Turns out, that the solution to my problem is rather simple. I first started wondering when I saw that scrollView.bounds.size.height
returned a bigger value than the actual screen height on devices smaller than the iPhone X, which seemed pretty strange. Then I tried to figure out how to find the "real" size of my scrollView on different devices, because it is obviously not really bigger than the whole screen according to the simulator visual result.
So instead of doing the above quoted calculation inside viewDidLoad() doing all my calculation in viewDidLayoutSubviews() instead and this solved the whole problem.
The only thing I'm still wondering about is, why there was an offset even on the iPhone X as it was my default template in Xcode.
I am wanting to create a SKLabelNode that is in the top left corner of every device. Also, to the left of the label in the top left corner I want an image that is a coin to show that this is the current coin count label. Every time I place my label in the corner on my iPhone 6s+ it isn't in the corner on my iPad.
Here is my code so far:
cornerCoin.position = CGPoint(x: screenWidth / -3.1, y: screenHeight / 3.175)
cornerCoin.zPosition = 10
cameraNode.addChild(cornerCoin)
coinLabel.position = CGPoint(x: screenWidth / -2.4, y: screenHeight / 8)
coinLabel.zPosition = 1
coinLabel.fontSize = 50
coinLabel.fontColor = UIColor.black
coinLabel.fontName = "04b19"
cameraNode.addChild(coinLabel)
Personally, I would not be tracking screenWidth/screenHeight, it goes against the foundation of SpriteKit to begin with (Your scene behaves as your virtual screen, this is how you should handle everything inside of it) Instead, what you should do is convert from screen to scene, this way regardless of scale mode or anchor point, your label is where you want it to be.
To get the top right corner of your view converted to your scene, you do
if let view = scene.view
{
let topRightPos = view.convert(CGPoint(x:view.frame.maxX,y:view.frame.minY),to:scene)
let camTopRight = scene.convert(topRightPos,to:cameraNode)
}
Now we know where our top right position is:
We can do
if let view = scene.view
{
let topRightPos = view.convert(CGPoint(x:view.frame.maxX,y:view.frame.minY),to:scene)
let camTopRight = scene.convert(topRightPos,to:cameraNode)
coinLabel.position = camTopRight
coinLabel.zPosition = 1
coinLabel.fontSize = 50
coinLabel.fontColor = UIColor.black
coinLabel.fontName = "04b19"
coinLabel.horizontalAlighmentMode = .right
coinLabel.verticalAlighmentMode = .top
cameraNode.addChild(coinLabel)
}
to right align our label so that the text always extends to the left, then to add the coin, we do:
if let view = scene.view
{
let topRightPos = view.convert(CGPoint(x:view.frame.maxX,y:view.frame.minY),to:scene)
let camTopRight = scene.convert(topRightPos,to:cameraNode)
coinLabel.position = camTopRight
coinLabel.zPosition = 1
coinLabel.fontSize = 50
coinLabel.fontColor = UIColor.black
coinLabel.fontName = "04b19"
coinLabel.horizontalAlighmentMode = .right
coinLabel.verticalAlighmentMode = .top
cameraNode.addChild(coinLabel)
cornerCoin.position = CGGPoint(x:0.0,y:coinLabel.frame.midY)
cornerCoin.anchorPoint = CGPoint(x:1.0,y:0.5)
cornerCoin.zPosition = 10
cameraNode.addChild(cornerCoin)
}
Our label should now be in the top right position of our camera, and the coin should be to the left of our label centered vertically with the text.
You may want to play with how your label is positioned if you do not like the look of top alignment.
I am trying to make a basic game for iOS10 using swift 3 and scenekit. In one part of my games code I have a function that adds fishes to the screen, and gives each one a certain tag so i can find them later:
let fish = UIImageView(frame: CGRect(x: 0, y: 0, width: CGFloat(fishsize.0), height: CGFloat(fishsize.1)))
fish.contentMode = .scaleAspectFit
fish.center = CGPoint(x: CGFloat(fishsize.0) * -0.6, y: pos)
fish.animationImages = fImg(Fishes[j].size, front: Fishes[j].front)
fish.animationDuration = 0.7
fish.startAnimating()
fish.tag = j + 200
self.view.insertSubview(fish, belowSubview: big1)
What I would like is to be able to, at a certain point, recall the fish and
Change the images shown, and
Stop the animation.
Is this possible? I've been trying it with var fish = view.viewWithTag(killer+200)! but from this I can't seem to change any image properties of the new variable fish.
Any help would be much appreciated.
Tom
Try to cast the UIView to UIImageView like this.
if let fish = view.viewWithTag(killer+200) as? UIImageView {
//Perform your action on imageView object
}
I'm learning SpriteKit and Swift, and I'm trying to make 5 small images "spawn" at the top of the screen, and slide down to the bottom. This is what I got so far, added in the didMoveToView method.
var myArray = NSMutableArray()
myArray.addObject(NSNumber(int: 40))
myArray.addObject(NSNumber(int: 80))
myArray.addObject(NSNumber(int: 120))
myArray.addObject(NSNumber(int: 160))
myArray.addObject(NSNumber(int: 200))
for item in myArray
{
let location = CGPoint(x: CGFloat(item.floatValue), y: 1)
let sprite = SKSpriteNode(imageNamed: "myImage")
sprite.xScale = 0.5
sprite.yScale = 0.5
sprite.position = location
let action = SKAction.moveToY(-4, duration: 4.5)
sprite.runAction(action)
addChild(sprite)
}
But all the objects appear at the bottom. I've tried to change the y-position, with the same result..
Thanks!
You need to increase the y coordinate.
Think about the axis system as the left bottom corner is (0,0) and the top right is (self.frame.size.width,self.frame.size.height)
You may also want to read about anchor points - the default anchor point for an object is 0.5,0.5 so if you locate it on 1 half of it (+ 1 pixel) will appear from the top.
If you want it to pop in from out of the screen you need either to change the anchor point or the poisition
Try changing your location variable to this:
let location = CGPoint(x: CGFloat(item.floatValue) , y:self.size.height)
This will set the y-value to the top of the screen and move the nodes there.