I originally used rectangles to test out the program but now I need to make them buttons. How would I do that programmatically?
import UIKit
class interestViewController: UIViewController {
var squareView: UIView!
var square: UIView!
var frogs: UIView!
var colson: UIView!
var wwdc: UIView!
var gravity: UIGravityBehavior!
var animator: UIDynamicAnimator!
var collision: UICollisionBehavior!
override func viewDidLoad() {
super.viewDidLoad()
squareView = UIView(frame: CGRectMake(100, 100, 100, 100))
view.addSubview(squareView)
animator = UIDynamicAnimator(referenceView: view)
squareView.backgroundColor = UIColor.blackColor()
gravity = UIGravityBehavior(items: [squareView])
animator.addBehavior(gravity)
collision = UICollisionBehavior(items: [squareView])
collision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(collision)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Question: How would I do that programmatically?
Short answer: Don't. Create your buttons in IB. It's easier than code the first time, and way, waaaaay easier to update and maintain. Learn to use IB. It's a huge timesaver.
If you are bound and determined to do things the hard way, then you'll need to use one of the UIButton class initializers, like buttonWithType. Then you'd set the frame and other attributes like you're doing with your squareView.
Related
I have researched a LOT, but the only examples I can find anywhere are for the purpose of defining the bounds of a UIView so that they collide/bounce off each other on the OUTSIDE of the objects.
Example: A ball hits another ball and they bounce away from each other.
But what I want to do is create a circular view to CONTAIN other UIViews, such that the containing boundary is a circle, not the default square. Is there a way to achieve this?
Yes, that's totally possible. The key to achieving collision within a circle is to
Set the boundary for the collision behaviour to be a circle path (custom UIBezierPath) and
Set the animator’s referenceView to be the circle view.
Output:
Storyboard setup:
Below is the code of the view controller for the above Storyboard. The magic happens in the simulateGravityAndCollision method:
Full Xcode project
class ViewController: UIViewController {
#IBOutlet weak var redCircle: UIView!
#IBOutlet weak var whiteSquare: UIView!
var animator:UIDynamicAnimator!
override func viewDidLoad() {
super.viewDidLoad()
self.redCircle.setCornerRadius(self.redCircle.bounds.width / 2)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5) { [unowned self] in
self.simulateGravityAndCollision()
}
}
func simulateGravityAndCollision() {
//The dynamic animation happens only within the reference view, i.e., our red circle view
animator = UIDynamicAnimator.init(referenceView: self.redCircle)
//Only the inside white square will be affected by gravity
let gravityBehaviour = UIGravityBehavior.init(items: [self.whiteSquare])
//We also apply collision only to the white square
let collisionBehaviour = UICollisionBehavior.init(items:[self.whiteSquare])
//This is where we create the circle boundary from the redCircle view's bounds
collisionBehaviour.addBoundary(withIdentifier: "CircleBoundary" as NSCopying, for: UIBezierPath.init(ovalIn: self.redCircle.bounds))
animator.addBehavior(gravityBehaviour)
animator.addBehavior(collisionBehaviour)
}
}
extension UIView {
open override func awakeFromNib() {
super.awakeFromNib()
self.layer.allowsEdgeAntialiasing = true
}
func setCornerRadius(_ amount:CGFloat) {
self.layer.cornerRadius = amount
self.layer.masksToBounds = true
self.clipsToBounds = true
}
}
I have found this answer How to check text field input at real time?
This is what I am looking for. However I am having trouble actually implementing this code. Also my current geographical location makes googling almost impossible.
I want to be able to change the background color of the next text field if the correct number is entered into the previous text field. textfieldTwo background color will change to green if the correct value is entered in textFieldOne. If the value is incorrect then nothing will happen. Please help me out. I have two text fields called textFieldOne and textFieldTwo and nothing else in the code.
Just pop this in your main view controller in an empty project (try using iphone 6 on the simulator)
import UIKit
class ViewController: UIViewController {
var txtField:UITextField!
var txtFieldTwo:UITextField!
var rightNumber = 10
override func viewDidLoad() {
super.viewDidLoad()
//txtFieldOne
var txtField = UITextField()
txtField.frame = CGRectMake(100, 100, 200, 40)
txtField.borderStyle = UITextBorderStyle.None
txtField.backgroundColor = UIColor.blueColor()
txtField.layer.cornerRadius = 5
self.view.addSubview(txtField)
//txtFieldTwo
var txtFieldTwo = UITextField()
txtFieldTwo.frame = CGRectMake(100, 150, 200, 40)
txtFieldTwo.borderStyle = UITextBorderStyle.None
txtFieldTwo.backgroundColor = UIColor.blueColor()
txtFieldTwo.layer.cornerRadius = 5
self.view.addSubview(txtFieldTwo)
txtField.addTarget(self, action: "checkForRightNumber", forControlEvents: UIControlEvents.AllEditingEvents)
self.txtField = txtField
self.txtFieldTwo = txtFieldTwo
}
func checkForRightNumber() {
let number:Int? = self.txtField.text.toInt()
if number == rightNumber {
self.txtFieldTwo.backgroundColor = UIColor.greenColor()
} else {
self.txtFieldTwo.backgroundColor = UIColor.blueColor()
}
}
}
EDIT: Adding a version with IBOutlets and IBActions
Note that in this example the IBAction is connected to txtFieldOne on Sent Events / Editing Changed
Also, make sure your Text Fields border colors are set to None. In the storyboard, the way to do this is to choose the left most option with the dashed border around it. That's so you can color the backgrounds. You can use layer.cornerRadius to set the roundness of the border's edges.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var txtField: UITextField!
#IBOutlet weak var txtFieldTwo: UITextField!
var rightNumber = 10
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func checkForRightNumber(sender: AnyObject) {
let number:Int? = self.txtField.text.toInt()
if number == rightNumber {
self.txtFieldTwo.backgroundColor = UIColor.greenColor()
} else {
self.txtFieldTwo.backgroundColor = UIColor.blueColor()
}
}
}
So I am trying to add gravity to 4 UIButtons but they are not falling, I added this code to the view did load, I don't why this isn't working well.
Here is the code:
//initialize the animator
var animator = UIDynamicAnimator(referenceView: self.view)
//add gravity
let gravity = UIGravityBehavior(items: [redButton!, greenButton!, blueButton!, cameraButton!])
let direction = CGVectorMake(0.0, 1.0)
gravity.gravityDirection = direction
animator.addBehavior(gravity)
My buttons are the redButton, greenButton, blueButton, and the cameraButton, also I have applied the direction of the fall but when I run the app they are just static. So is it possible to add gravity to the UIButtons?
You are declaring your animator locally to the function. When the function returns, the animator is released from memory, and all animation stops (actually viewDidLoad() returns so early in the lifecycle that animation never gets started).
Declare it as:
var animator: UIDynamicAnimator!
at class scope
Class scope means put it within the curly braces of the class:
class Foo {
var thisVariableIsAtClassScopeAndPersistsAcrossMethods: Int
func bar() {
var thisVariableIsAtLocalScopeAndDisappearsWhenFunctionReturns: String
}
}
And only initialize it in viewDidLoad():
animator = UIDynamicAnimator(referenceView: self.view)
(You cannot initialize it at class scope without lazy trickiness, because self is not yet available.)
** EDIT FINAL ANSWER **
After chat, we resolved the misunderstood answer and now we have:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var redButton: UIButton!
#IBOutlet weak var greenButton: UIButton!
#IBOutlet weak var blueButton: UIButton!
#IBOutlet weak var cameraButton: UIButton!
// Declare the animator at class scope so it doesn't get released prematurely.
var animator: UIDynamicAnimator!
override func viewDidLoad() {
super.viewDidLoad()
//add gravity
let gravity = UIGravityBehavior(items: [redButton, greenButton, blueButton, cameraButton])
let direction = CGVectorMake(0.0, 1.0)
gravity.gravityDirection = direction
animator.addBehavior(gravity)
// other viewDidLoad setup code to set attributes of buttons
}
}
I have a very general question about the Initialization in Swift.
Unlike in Objective C it's now possible to call the init() directly at the declaration outside of my functions:
e.g.
class ViewController: UIViewController {
let myView: UIView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
myView.frame = getFrame()
myView.backgroundColor = UIColor.redColor()
self.view.addSubview(myView)
}
func getFrame() -> CGRect {
return CGRectMake(0, 0, 100, 100)
}
}
In Objective C I would have done the initialization in my function.
But what if I want to call an Initializer with parameters which are not set yet?
e.g.
I want to init with a frame which is being calculated in a func()
class ViewController: UIViewController {
//THIS IS NOT WOKRING
let myView: UIView = UIView(frame: getFrame())
override func viewDidLoad() {
super.viewDidLoad()
myView.backgroundColor = UIColor.redColor()
self.view.addSubview(myView)
}
func getFrame() -> CGRect {
return CGRectMake(0, 0, 100, 100)
}
}
I don't wanna do my initializations at two different places in the Code. Is there any general pattern for the initializations?
So your options for initialisation in swift are numerous. With your current example you cannot use the method getFrame() yet because you do not yet have a reference to self as the ViewController has not get been initialised. Instead you could use:
let myView: UIView = UIView(frame: CGRectMake(0, 0, 100, 100))
As this does not require the reference to self. Alternatively you could lazy instantiation which will get run after self is available (this can only be used with var not let:
lazy var myView: UIView = {
return UIView(frame:self.getFrame())
}()
To answer your question, when using UIKit class where you often don't have control over their instantiation you can keep doing it the same was as you were in objective c and use implicitly unwrapped optionals (to prevent you having to use a ! or ? every time you instantiate a variable, e.g.:
var myView: UIView!
override func viewDidLoad(){
super.viewDidLoad();
myView = UIView(frame:getFrame())
}
This however does not work with let constants, as they need to be assigned either immediately or in the constructor of the object. Hope this helps.
I am developing an iOS app with swift and i ran into a problem. Using solely UIKit, I have a square that falls onto a platform, bounces back to its original position, and keeps going. I want the platform to change color every time the square hits it but i don't know how to detect that the square has come into contact with the platform. Please help. Here is the the code
import UIKit
import SpriteKit
class PlayScreen : UIViewController {
#IBOutlet var ScreenBack: UIImageView!
#IBOutlet var Platform: UIImageView!
var squareView: UIImageView!
var gravity: UIGravityBehavior!
var animator: UIDynamicAnimator!
var collision: UICollisionBehavior!
var itemBehaviour: UIDynamicItemBehavior!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
// Creating a bouncing Ball with the barrier of the platform
squareView = UIImageView(frame: CGRect(x: ScreenBack.frame.width/2, y: ScreenBack.frame.height/4, width: 40, height: 40))
squareView.frame.origin.x-=squareView.frame.width/2
squareView.image = redBall
view.addSubview(squareView)
animator = UIDynamicAnimator(referenceView: view)
gravity = UIGravityBehavior(items: [squareView])
animator.addBehavior(gravity)
collision = UICollisionBehavior(items: [squareView])
collision.translatesReferenceBoundsIntoBoundary = true
collision.addBoundaryWithIdentifier("barrier", fromPoint: CGPointMake(self.Platform.frame.origin.x, self.Platform.frame.origin.y), toPoint: CGPointMake(self.Platform.frame.origin.x + self.Platform.frame.width, Platform.frame.origin.y))
animator.addBehavior(collision)
itemBehaviour = UIDynamicItemBehavior(items: [squareView])
itemBehaviour.elasticity = 1.0
itemBehaviour.resistance = 0.0
animator.addBehavior(itemBehaviour)
}
}
to detect collision use UICollisionBehaviorDelegate
class ViewController: UIViewController, UICollisionBehaviorDelegate {
Set your collision behavior object delegate to self
collision.collisionDelegate=self
Add add the following function
func collisionBehavior(behavior: UICollisionBehavior, beganContactForItem item: UIDynamicItem, withBoundaryIdentifier identifier: NSCopying, atPoint p: CGPoint) {
println("Contact - \(identifier)")
}