How to simply animate an UIimageView? - swift

I want to move a 40, 40 pixel square from the top to the bottom, then repeat that action over a period of 3 seconds. Where would I put the entire thing in the viewcontroller? There is no start button so would I put in in the viewdidload?
So far I have this
UIView.animateWithDuration(0.2, animations: {
}, completion: {
})
As somewhere to start. Would I set the image to equal UIView? What should It look like? the image is called mrock.
I tried using blank.moveToPoint(CGPoint(x: 0,y: 0)) in the animations part, but dont I need A UIBezierPath thing?

As #picciano stated you should have an IBOutlet to an UIImageView if you are using storyboards. So you in your view controller you can try something like this:
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//'img' is a picture imported in your project
self.imageView.image = UIImage(named: "img")
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let newPos: CGFloat = 300.0
UIView.animateWithDuration(1.0, animations: { () -> Void in
self.imageView.frame = CGRectMake(0, newPos, CGFloat(self.imageView.bounds.size.width), CGFloat(self.imageView.bounds.size.height))
})
}

First, consider putting the animation in viewWillAppear, then disable it if needed in viewDidDisappear.
Second, if you're using auto layout, you will probably need to create an IBOutlet for the relevant constraint and animate the constant property of the constraint rather than the position of the view object directly.

Related

Changing constraints by pressing a button

Is there a way to change view’s centerXAnchor constraint to another object (with animation) by pressing a button while the app is running?
Thank's for all of the answers!
First, you need to create an IBOutlet for your constraint from the storyboard, something similar to this.
#IBOutlet weak var centerXConstraint: NSLayoutConstraint!
And when the button is pressed, you should change the constraint value and update the view layout.
centerXConstraint.constant = setYourValueHere
UIView.animate(withDuration: 0.3, animations: {
self.view.layoutIfNeeded()
})
If you want to add constraints programmatically, then remove #IBOutlet weak.
var centerXConstraint: NSLayoutConstraint!
Assign your view's center X anchor to it.
centerXConstraint = yourView.centerXAnchor.constraint(equalTo: super.view.centerXAnchor, constant: 0)
centerXConstraint.isActive = true
after that, you can change it as described above.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var centerXConstraintOutlet: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func buttonClickAction(_ sender: UIButton) {
animateViewCenterXConstraint()
}
func animateViewCenterXConstraint() {
UIView.animate(withDuration: 0.3) {
self.centerXConstraintOutlet.constant = 30
self.view.layoutIfNeeded()
}
}
}
1) Create view’s centerXAnchor constraints related to both the objects.
2) Take outlets of both the constraints.
3) Activate and de-activate them on click of the button as you wish.
Declare variable for centerXAnchor constraint and assign value on button action. You can try this:
var constraintOfCenterXAnchor: NSLayoutConstraint = NSLayoutConstraint()
in viewDidLoad() set constraintOfCenterXAnchor.constant = 0
When button pressed, change constraint value and update view
constraintOfCenterXAnchor.constant = 30
UIView.animate(withDuration: 0.3, animations: {
self.view.layoutIfNeeded()
})

Is it possible to make a circular NSButton?

I am trying to create a custom shape NSButton. In particular I am trying to make a round button, using a custom image. I've found a tutorial on the creation of custom UIButton and tried to adapt it to NSButton. But there's a huge problem. clipsToBounds seems to be iOS only(
Here's my code:
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var mainButton: NSButton!
var size = 32
override func viewDidLoad() {
super.viewDidLoad()
configureButton()
// Do any additional setup after loading the view.
}
func configureButton()
{
mainButton.wantsLayer = true
mainButton.layerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay
mainButton.layer?.cornerRadius = 0.5 * mainButton.bounds.size.width
mainButton.layer?.borderColor = NSColor(red:0.0/255.0, green:122.0/255.0, blue:255.0/255.0, alpha:1).CGColor as CGColorRef
mainButton.layer?.borderWidth = 2.0
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
What am I doing wrong? How can I make a circular NSButton? Can you suggest anything on replacing clipsToBounds?
Because here is what I was able to get so far:
NSButton is a subclass of NSView, so all methods in NSView, such as drawRect(_:), are also available in NSButton.
So create a new Button.swift which you draw your custom layout
import Cocoa
class Button: NSButton {
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
// Drawing code here.
let path = NSBezierPath(ovalIn: dirtyRect)
NSColor.green.setFill()
path.fill()
}
}
Great Tutorial Here. It is iOS , but quite similar!
Don't play around with corner radius. A circle doesn't have corners. To make the button appear as a circle, mask the button's layer to a circle.
You are setting the radius based upon the width of the button. By the look of your screenshot, the button is not a square when you start, so rounding the corners cannot create a circle.

Animate view by changing constraint constant

I have a datePicker that I want to animate in and out of view from the bottom by changing its' top constraint to the super view top.
I have an IBOutlet set to it and on viewDidLoad I'm allowed to change the constraint constant.
override func viewDidLoad() {
super.viewDidLoad()
self.datePickerTopConstraint.constant = self.view.frame.size.height // I can set this to whatever and it will persist
}
However via an IBAction I try to set the constant to another value and that doesn't persist.
#IBAction func showDatePicker() {
UIView.animateWithDuration(0.25, animations: {
() -> Void in
self.datePickerTopConstraint.constant = self.view.frame.size.height - self.datePicker.frame.size.height // Doesn't persist
self.view.layoutIfNeeded()
})
}
It seems that I can reverse this and have the datePicker appear in view (in viewDidLoad) and animate it out of view, but not have the datePicker appear out of view (like in the example above) and animate inside the view. What have I missed?
EDIT
By setting the top constraint constant to the super view's height I (for some reason I don't understand) also set the date picker's height to 0 which in turn makes the subtraction in showDatePicker pointless.
Restructure the code so that in the button's method work's by first working out the constant's new value and then calling the animation. Pull the height calculation in to it's own function. I think that self.datePicker.frame.size.height does not exist and results in 0, but I would check this using the debugger.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
datePickerTopConstraint.constant = constantForDatePickerViewHeightConstraint()
view.setNeedsLayout()
}
#IBAction func showDatePicker(button: UIButton) {
// Check constraint constant
if datePickerTopConstraint.constant == self.view.frame.size.height {
// Date picker is NOT visible
datePickerTopConstraint.constant = constantForDatePickerViewHeightConstraint()
} else {
// Date picker is visible
datePickerTopConstraint.constant = self.view.frame.size.height
}
UIView.animateWithDuration(0.25,
animations: {() -> Void in
self.view.layoutIfNeeded()
})
}
private func constantForDateOPickerViewHeightConstraint() -> CGFloat {
var value : CGFloat = 200.0
// Workout value you want to as the constant for the constraint.
return value
}
Try this:
func showDatePicker() {
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.25, animations: {
() -> Void in
self.datePickerTopConstraint.constant = self.view.frame.size.height - self.datePicker.frame.size.height // Doesn't persist
self.view.layoutIfNeeded()
})
}
You need to call layoutIfNeeded before the animation bock and in the block. Now it is calculating the views correctly. Like I said there is also no point in having any constraints set in the viewDidLoad, if you are going to do it anywhere do it in viewWillAppear. The view hasn't finished setting up in viewDidLoad so there is no constraints available to set properly. Calling layoutIfNeeded before the animation block fixes this mistake and you need it there anyway so it can calculate correctly in the future too.

Where to add subviews in a viewcontrollers lifecycle

For me it make sense to add subviews in viewDidLoad, because it gets call when the view load, but i can't do that with my subviews. I have subviews which frame depends on another already added subviews height and width, and height and width is not correct before viewDidAppear. So i add my subviews in viewDidAppear, but viewDidAppear gets call everytime the view appears which is bad. So for my solution right now i add my subviews in viewDidAppear and when view disappear I remove the subviews in viewDidDisappear. Is there another way to archieve this without I manual removing subviews from superview.
Example
override func viewDidAppear(animated: Bool) {
print(PercentageView.frame.width)
print(PercentageView.frame.height)
CreateInfoRecipeLabels()//Add subviews
CreateCircleDiagram() //Add subviews
}
override func viewDidDisappear(animated: Bool) {
//When view disappear deallocate subviews
for view in PercentageView.subviews {
view.removeFromSuperview()
}
}
UPDATE - Tried this instead, but it is like it can't add subview before there is a frame?
#IBOutlet weak var RecipeInfoContain: UIView!
var MinLabel: SMIconLabel?
var Min = "15"
override func viewDidLoad() {
super.viewDidLoad()
RecipeInfoContain.addSubview(MinLabel!)
// Do any additional setup after loading the view.
}
override func viewWillLayoutSubviews() {
MinLabel = SMIconLabel(frame: CGRectMake(RecipeInfoContain.frame.width/4 - 50, RecipeInfoContain.frame.height/2 - 10, 100, 20))
MinLabel!.text = Min + " min"
//MinLabel.backgroundColor = UIColor.redColor()
MinLabel!.font = UIFont(name: "OpenSans", size: 11)
MinLabel!.textColor = UIColor.whiteColor()
MinLabel!.icon = UIImage(named: "Clock")
MinLabel!.clipsToBounds = true
MinLabel!.iconPadding = 5
MinLabel!.iconPosition = .Left
MinLabel!.textAlignment = .Left
}
Two thoughts:
If you use autolayout to dictate the frame of the subviews, then you can add them in viewDidLoad and the autolayout engine will take care of sizing them appropriately.
Just set translatesAutoresizingMaskIntoConstraints for the subviews to false and then add the appropriate constraints rather than setting frame values manually.
If you really want to manually adjust the frames, you can add the subviews in viewDidLoad, but then adjust the frames in viewWillLayoutSubviews.

Swift - Cropping images *outside* of allowsEditing

I have a very very simple project set up that allows you to click a "browse photo" button. The user then selects a photo from their photo gallery, and it's displayed on a programmatically created UIImageView.
Works like a charm. However - I am missing key functionality that is required.
I need the user to be able to scale the image (via pinching and dragging) after it is displayed within the UIImageView. allowsEditing = true, lets the user crop before. I need similar functionality, however, allowing them to edit once it's on the main UI.
Help is appreciated. Please and thank you!!
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var imageViewLayer: CALayer{
return imageView.layer
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
imageViewLayer.contents = UIImage(named: "ss3.jpg")?.CGImage
imageViewLayer.contentsGravity = kCAGravityResizeAspect
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func newGesture(sender: AnyObject) {
imageViewLayer.transform = CATransform3DMakeScale(sender.scale, sender.scale, 1)
}
}
I did something similar a while back. I added the image to UIImageView's layer property, added gesture recognizer to the view and implemented the gesture call backs modifying the layer property and not the view. Adding the image to the UIImageView's layer did the trick. As a side note, I would like to add that every UIView is supported by CALayer class. It has a lot of methods and properties which help to dynamically change the view, which in your case will be done by gestures.
As an alternative, you can also use CALayer's hitTest method instead of implementing the call backs for gesture recognizers.
EDIT- Sample Code
You could do some thing like this:
#IBOutlet weak var imageView: UIImageView!
var imageViewLayer: CALayer{
return imageView.layer
}
In the viewDidLoad, set up the image
imageViewLayer.contents = UIImage(named: "CoreDataDemoApp")?.CGImage
imageViewLayer.contentsGravity = kCAGravityResizeAspect
Add pinch gesture to the imageview in storyboard (or programmatically) and in it's call back you could do something like this:
#IBAction func pinchGestureRecognized(sender: AnyObject) {
imageViewLayer.transform = CATransform3DMakeScale(sender.scale, sender.scale, 1)
}
Again this is just to give you an idea of how it could work and it is not the complete code. Hope this helps!
This is another way of doing it:
Stackoverflow link to related question