How can I make an image start at a predetermined location on screen, and when tapped, appear at a different location, also predetermined. And when tapped then, return to the original location?
Thanks
PS: Working on Xcode 6 - Swift
If you are using an UIImageView, simply change its frame. (Let me know if you're using autolayouts):
let imageView = UIImageView(frame: CGRectMake(0, 0, width, height))
imageView.image = UIImage(named: "assetName")
then when clicked (you can detect by overlaying a clear button over your image, etc):
imageView.frame = CGRectMake(100, 100, width, height)
etc.
Every UIView has a frame property of type CGRect which specifies both its size and position. To change the position of a view, you thus have to modify the x and y values of the frame's origin, the location of the upper-left point of the framing rectangle:
let view = UIView()
// Set location and size
view.frame = CGRectMake(0, 0, width, height)
// Modify location
view.frame.origin = CGPointMake(newX, newY)
Depending on what type your view has, there are different approaches to react to taps on the view. A button, for example, can specify a target function that is called when it's tapped.
Generally speaking, you can attach a UIGestureRecognzier (such as a UITapGestureRecognizer) to detect gestures the user performed on the given UIView. You also need to make sure its userInteractionEnabled property is set to true so that the interaction can be detected in the first place.
Related
I'm attempting to create a CAShapeLayer animation that draws an outline around the frame of a UILabel. Here's the code:
func newQuestionOutline() -> CAShapeLayer {
let outlineShape = CAShapeLayer()
outlineShape.isHidden = false
let circularPath = UIBezierPath(roundedRect: questionLabel.frame, cornerRadius: 5)
outlineShape.path = circularPath.cgPath
outlineShape.fillColor = UIColor.clear.cgColor
outlineShape.strokeColor = UIColor.yellow.cgColor
outlineShape.lineWidth = 5
outlineShape.strokeEnd = 0
view.layer.addSublayer(outlineShape)
return outlineShape
}
func newQuestionAnimation() {
let outlineAnimation = CABasicAnimation(keyPath: "strokeEnd")
outlineAnimation.toValue = 1
outlineAnimation.duration = 5
newQuestionOutline().add(outlineAnimation, forKey: "key")
}
The animation performs as expected when running on the simulator for an iPhone 11 which is the device size that I used in the storyboard. However when running the project on a different device with different screen dimensions (like iPhone 8 plus) the shape is drawn out of place and not around the UILabel as it should be. I used autolayout to horizontally and vertically center the UILabel to the center of the view so the UILabel is centered no matter what device.
Any suggestions? Thanks in advance!
Cheers!
A shape layer is not a view, so it is not subject to auto layout. And any time you say something like roundedRect: questionLabel.frame you are making yourself dependent on what questionLabel.frame is at that moment, which is a huge mistake because that is exactly what is not determined until auto layout determines what the frame will be (and can change later if auto layout changes its mind due to changing conditions, such as rotation etc.)
There are two kinds of solution:
Host the shape layer in a view. Now you have something that is subject to autolayout. You will still need to redraw the shape layer whenever the view changes its frame, but you can detect that and perform the redraw.
Implement your view controller's viewDidLayoutSubviews to detect that auto layout has just done its work. Respond by (for example) removing the shape layer and making a new one based on the current conditions.
I am using a UIObject to display an animation using Lottie framework which is a submit button, and when this UIView object is tapped, the animation is played.
However the text within this animation does not appear, and the dimensions are also wrong. My UIView object has dimensions of 193*33 and the animation also does. Here is my code;
let SubmitButton = LOTAnimationView(name: "submit_195_33")
self.SubmitViewName.addSubview(SubmitButton)
SubmitButton.frame = CGRect(x: 0, y: 0, width: 195, height: 33)
SubmitButton.contentMode = .scaleAspectFill
SubmitButton.play()
My UIView object is larger then the animation even if I use this code, and the animation is super small like this:
Maybe you can try setting constraints to the button, for example:
submitButton.translatesAutoresizingMaskIntoConstraints = false
submitButton.widthAnchor.constraint(equalToConstant: 195).isActive = true
submitButton.heightAnchor.constraint(equalToConstant: 33).isActive = true
What do I need to code in order to have an image (that is already in the assets.xcassets) displayed as the background of the GameScene.swift?
First of all you could call you scene with the scaleMode .resizeFill that modify the SKScene's actual size to exactly match the SKView :
scene.scaleMode = .resizeFill
.resizeFill – The scene is not scaled. It is simply resized so that its fits the view. Because the scene is not scaled, the images will all remain at their original size and aspect ratio. The content will all remain relative to the scene origin (lower left).
By default, a scene’s origin is placed in the lower-left corner of the view. So, a scene is initialized with a height of 1024 and a width of 768, has the origin (0,0) in the lower-left corner, and the (1024,768) coordinate in the upper-right corner. The frame property holds (0,0)-(1024,768).The default value for the anchor point is CGPointZero (so you don't need to change it), which places it at the lower-left corner.
Finally, you can use the code below to add your background image (called of example bg.jpg):
// Set background
let txt = SKTexture(imageNamed: "bg.jpg")
let backgroundNode = SKSpriteNode(texture: txt, size:size)
self.addChild(backgroundNode)
backgroundNode.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
Although this might not be the best way, but it's what I always do, and it works.
Assuming that you have an image that is exactly the same aize as your scene, you can do this:
// please declare bg as a class level variable
bg = SKSpriteNode(imageNamed: "name of your texture")
// the below two lines of code is my preference only. I want the
// background's anchor point to be the bottom left of the screen
// because IMO it's easier to add other sprites as children of the background.
bg.anchorPoint = CGPoint.zero
bg.position = CGPoint(x: self.frame.width / -2, y: self.frame.height / -2)
self.addChild(bg)
Alernatively, just do this in an sks file. It's much easier.
After that, add all your game sprites as children of bg instead of self because it is easier to manage.
I got some UILabel which can be pressed to open a menu. When pressed, they call my function with the label itself as a parameter. I make a popover that behave correctly in phone view but I would like to position it when it is on ipad view.
My problem is that I can not get the exact position of the UILabel that was pressed.
I tried
myYCoordinates = label.bounds.origin.y
or
myYCoordinates = label.frame.origin.y
to
optionMenu.popoverPresentationController?.sourceRect = CGRectMake(self.view.bounds.size.width / 2, myYCoordinates, 1.0, 1.0)
But I cant get the good coordinate.
I don't know if it is because my label are in a tableview with 2 section or if there is a way at all.
Thank in advance for the help.
Here is my sceen (cropped du to development confidentiality)
Here is what append when I press my label
And here is what I would like ti to look like
I tried
optionMenu.popoverPresentationController?.sourceRect = label.frame
Based on #Özgür Erzil answer, I found out that I could simply use
optionMenu.popoverPresentationController?.sourceView = label
optionMenu.popoverPresentationController?.sourceRect = CGRectMake(label.frame.width, label.frame.height / 2, 1.0, 1.0)
By setting the source view to my label and using the label width and height to position it.
Thank
if you create your UILabel dynamically, try to set the position when you set it like:
CGRectMake(x, y, width, height)
var label = UILabel(frame: CGRectMake(0, 0, 200, 20))
or if it is in storyBoard, you have to use constraint methods and use autolayout. Explained here
I've been struggling for a view hours to figure out how to get my view masked by a shape that is in another view. Basically I have a circular countdown timer that I want to be masked out by an animating circle that scales up from the center of the timer when the timer is reset.
I tried setting timerMask.maskView = timerCircleGrahics where timerCircleGraphics is the name of my timer animation view. But this is giving me very strange results when I test the app. It seems to clip the view to the rectangle bounds of my mask view rather than the alpha of the bounds that are drawn within that view. The mask layer is centered and being drawn properly, but I've never attempted this before so am not sure if I am doing it right.
Here is the class for my mask shape:
class timerBackgroundMask: UIView {
override func drawRect(rect: CGRect) {
var ovalPath = UIBezierPath(ovalInRect: CGRectMake(0, 0, 238, 238))
colorGreen.setFill()
ovalPath.fill()
}
}
Then using IB, I assign this mask to a manually placed View in my Storyboard called timerMask. I am realizeing now that by assigning timerBackgroundMask class to timerMask I have programatically added a subview to my manually placed Storyboard view, but I feel like the alpha should come through just the same when set this view to mask out anotherview. Here is the code i use to set the mask
timerCircleGraphics.layer.mask = timerMask.layer
The result I am getting is pretty weird:
The red portion should be a circle that is partially clipped by my timerMask from the center outward. The light green circle that you see is simply the background view of the counter, however it happens to be the exact position and size as my timerBackgroundMask for reference.
Don't bother creating a class and using the Storyboard. Do it straight in code, the simple way:
var ovalPath = UIBezierPath(ovalInRect: CGRectMake(0, 0, 238, 238))
colorGreen.setFill()
ovalPath.fill()
var mask = CAShapeLayer()
mask.path = ovalPath.CGPath
timerCircleGraphics.layer.mask = mask