Spin button infinitely: Swift - xcode

I found this code that allows you to rotate/spin 90 degrees when button is pushed in Swift. But what I would like to do is rotate/spin the button infinitely when it is pushed, and stop spinning when the button is pushed again. Here is the code I have:
import UIKit
class ViewController: UIViewController {
#IBOutlet var otherbutton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func Rotate(sender: AnyObject) {
UIView.animateWithDuration(1.0,
animations: ({
self.otherbutton.transform = CGAffineTransformMakeRotation(90)
}))
}
}

You can use a CABasicAnimation to animate it infinitely as follow:
class ViewController: UIViewController {
#IBOutlet weak var spinButton: UIButton!
// create a bool var to know if it is rotating or not
var isRotating = false
#IBAction func spinAction(sender: AnyObject) {
// check if it is not rotating
if !isRotating {
// create a spin animation
let spinAnimation = CABasicAnimation()
// starts from 0
spinAnimation.fromValue = 0
// goes to 360 ( 2 * π )
spinAnimation.toValue = M_PI*2
// define how long it will take to complete a 360
spinAnimation.duration = 1
// make it spin infinitely
spinAnimation.repeatCount = Float.infinity
// do not remove when completed
spinAnimation.removedOnCompletion = false
// specify the fill mode
spinAnimation.fillMode = kCAFillModeForwards
// and the animation acceleration
spinAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
// add the animation to the button layer
spinButton.layer.addAnimation(spinAnimation, forKey: "transform.rotation.z")
} else {
// remove the animation
spinButton.layer.removeAllAnimations()
}
// toggle its state
isRotating = !isRotating
}
}

It should be the same as yours.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var spinButtton: UIButton!
var isRotating = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func spinAction(sender: AnyObject) {
if !isRotating {
let spinAnimation = CABasicAnimation()
// start from 0
spinAnimation.fromValue = 0
// goes to 360
spinAnimation.toValue = M_1_PI * 2
// define how long it will take to complete a 360
spinAnimation.duration = 1
// make spin infinitely
spinAnimation.repeatCount = Float.infinity
// do not remove when completed
spinAnimation.removedOnCompletion = false
// specify the fill mode
spinAnimation.fillMode = kCAFillModeForwards
// animation acceleration
spinAnimation.timingFunction = CAMediaTimingFunction (name: kCAMediaTimingFunctionLinear)
// add the animation to the button layer
spinAnimation.layer.addAnimation(spinAnimation, forKey: "transform.rotation.z")
} else {
// remove the animation
spinButtton.layer.removeAllAnimations()
}
// toggle its state
isRotating = !isRotating
}
}

Related

OSX Swift , Draw a simple line with a push of a button

Have looked a lot for this but nothing found to match.
Real simple I want to draw a line buy a push of a button.
I have a class which is from NSView to do the drawing, this monitors a var and if it changes to redraw the view.
I can get the mouse click to call the view by changing the value and it draws just fine. But I cant get the button to work. It calls the drawing method but the view is not updated ???
I know its got to be something simple, but I just cannot find it.
Thanks in advance.
Below is my View class and View Controller.
//
// LineDrawer.swift
// TestDraw3
//
// Created by Colin Wood on 21/04/17.
// Copyright © 2017 Colin Wood. All rights reserved.
//
import Cocoa
class LineDrawer : NSView {
// Vars
var newLinear = NSBezierPath()
public var QQ: Int = 0 { // every time QQ changes redraw information in QQ
didSet{
boom() // drawing method
}
}
// Methods
override func draw(_ dirtyRect: NSRect) {
NSColor.red.set()
newLinear.lineWidth = 5
newLinear.lineCapStyle = NSLineCapStyle.roundLineCapStyle
newLinear.stroke()
}
func boom(){ // draw a simple line
Swift.print("In BooM")
Swift.print(QQ)
let lastPt = NSPoint(x: QQ, y: 1)
newLinear.move(to: lastPt)
let newPt = NSPoint(x: QQ, y: 50)
newLinear.line(to: newPt)
needsDisplay = true
}
override func mouseDown(with theEvent: NSEvent) {
QQ = QQ + 7 // just add 7 so you can see it being drawn after didSet
}
}
//
// ViewController.swift
// TestDraw3
//
// Created by Colin Wood on 15/04/17.
// Copyright © 2017 Colin Wood. All rights reserved.
//
import Cocoa
class ViewController: NSViewController {
// Vars
#IBOutlet weak var textField: NSTextField!
// Methods
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
#IBAction func button(_ sender: Any) {
let v = LineDrawer()
v.QQ = 300 // change QQ to call didSet
}
}
You need to add your LineDrawer as a subview. A good place, to add it, is in the viewDidLoad method:
private var line: LinerDrawer!
override func viewDidLoad() {
super.viewDidLoad()
line = LinerDrawer()
line.frame = NSMakeRect(0, 0, 200, 200)
line.QQ = 300
line.isHidden = true
view.addSubview(line)
}
And then finally show it when you hit the button:
#IBAction func button(_ sender: Any) {
line.isHidden = false
}
You still need to work out the correct frame for your LineDrawer view.

Changing default SKScene

I have a class called IntroLayer I'm trying to load as the inital scene when my game is launched. However after simply changing the GameScene to IntroScene as described in these simple steps, my IntroScene isn't being loaded. I set breakpoints on if let scene to see that it skips over it, and even set breakpoints in the actual IntroScene to verify didMoveToView is not being called. Any ideas?
I changed the let scene from GameScene to IntroScene in the GameViewController like so:
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = IntroScene(fileNamed:"IntroScene") {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .AllButUpsideDown
} else {
return .All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
Then renamed GameScene.swift to IntroScene.swift and changed the class to this:
import SpriteKit
class IntroScene: SKScene {
override func didMoveToView(view: SKView) {
backgroundColor = UIColor.blackColor()
let fadeIn:SKAction = SKAction.fadeInWithDuration(1.0)
let fadeOut:SKAction = SKAction.fadeOutWithDuration(1.0)
let inspiredText = SKLabelNode(fontNamed: "Dead Kansas")
inspiredText.alpha = 0.0
inspiredText.text = "Inspired By"
inspiredText.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
addChild(inspiredText)
inspiredText.runAction(fadeIn)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
// let location = touch.locationInNode(self)
}
}
}
However when I launch the app, it doesn't appear that IntroScene is even called when I set breakpoints, and I'm getting a screen with a gray background.
You need to rename your GameScene.sks to IntroScene.sks
The sks file is an archived file for your scene data, if you open it up, you will notice you can change a lot of things about the scene, and even add nodes and sprites directly to it. When you call if let scene = IntroScene(fileNamed:"IntroScene") { you are unarchiving the sks file to be loaded as a scene, so anytime you want to create a new scene, remember that you will need this file.

"type" viewController does not conform to protocol "UITableViewDataSource"

I keep getting this error for some reason.
"type" viewController does not conform to protocol "UITableViewDataSource"
I know that this has been covered a million times and there are even videos explaining why this problem occurs, but for some reason I can't fix it and can't figure out exactly what it is that I have done wrong.
Here is my code:
//
// ViewController.swift
// ChatApp
//
// Created by K on 17/03/2015.
// Copyright (c) 2015 Krazy88 All rights reserved.
//
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet weak var dockViewHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var sendButton: UIButton!
#IBOutlet weak var messageTextField: UITextField!
#IBOutlet weak var messageTableView: UITableView!
var messagesArray:[String] = [String]()
var delegate: UITableViewDataSource? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.messageTableView.delegate = self
self.messageTableView.dataSource = self
// Set self as the delegate for the textfield
self.messageTextField.delegate = self
//Add a tap gesture recognizer to the tableview
let tapGesture:UITapGestureRecognizer = UITapGestureRecognizer(target:self, action: "tableViewTapped")
self.messageTableView.addGestureRecognizer(tapGesture)
// Retrieve messages from Parse
self.retreiveMessages()
}
override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func sendButtonTapped(sender: UIButton) {
// Send button is tapped
// Call the end editing method for the text field
self.messageTextField.endEditing(true)
//Disable the send button and textfield
self.messageTextField.enabled = false
self.sendButton.enabled = false
// Create a PFObject
var newMessageObject:PFObject = PFObject(className: "Message")
// Set the Text key to the text of the messageTextField
newMessageObject["Text"] = self.messageTextField.text
// Save the PFObject
newMessageObject.saveInBackgroundWithBlock { (success:Bool, error:NSError!) -> Void in
if (success == true) {
//Message has been saved!
// TODO: Retrieve the latest messages and reload the table
NSLog("Message saved successfully.")
}
else {
// Something bad happened.
NSLog(error.description)
}
// Enable the textfield and send button
self.sendButton.enabled = true
self.messageTextField.enabled = true
self.messageTextField.text = ""
}
}
func retreiveMessages() {
// Create a new PFQuery
var query:PFQuery = PFQuery(className: "Message")
// Call findobjectsinbackground
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]!, error:NSError!) -> Void in
// clear the messageArray
self.messagesArray = [String]()
// Loop through the objects array
for messageObject in objects {
// Retrieve the Text column of each PFObject
let messageText:String? = (messageObject as PFObject)["Text"] as? String
// Assign it into our messagesArray
if messageText != nil {
self.messagesArray.append(messageText!)
}
}
// Reload the tableview
self.messageTableView.reloadData()
// Reload the tableview
}
func tableViewTapped() {
// Force the textfield to end editing
self.messageTextField.endEditing(true)
}
// MARK: Textfield Delegate Methods
func textFieldDidBeginEditing(textField: UITextField) {
// Perform an animation to grow the dockview
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.5, animations: {
self.dockViewHeightConstraint.constant = 350
self.view.layoutIfNeeded()
} , completion: nil)
}
func textFieldDidEndEditing(textField:UITextField) {
// Perform an animation to grow the dockview
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.5, animations: {
self.dockViewHeightConstraint.constant = 60
self.view.layoutIfNeeded()
}, completion: nil)
}
// MARK: TableView Delegate Methods
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Create a table cell
let cell = self.messageTableView.dequeueReusableCellWithIdentifier("MessageCell") as UITableViewCell
// Customize the cell
cell.textLabel.text = self.messagesArray[indexPath.row]
//Return the cell
return cell
}
func TableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messagesArray.count
}
}
}
Any helps tips or suggestion will be much appreciated as I have tried everything!
thanks for reading
Kurando
Your UITableViewDataSource #required delegates are inside retreiveMessages(). Fix the position of that second last bracket..!!
Here is your correct code :
import Foundation
import UIKit
class ViewController : UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
#IBOutlet weak var dockViewHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var sendButton: UIButton!
#IBOutlet weak var messageTextField: UITextField!
#IBOutlet weak var messageTableView: UITableView!
var messagesArray:[String] = [String]()
var delegate: UITableViewDataSource? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
messageTableView.delegate = self
messageTableView.dataSource = self
// Set self as the delegate for the textfield
self.messageTextField.delegate = self
//Add a tap gesture recognizer to the tableview
let tapGesture:UITapGestureRecognizer = UITapGestureRecognizer(target:self, action: "tableViewTapped")
self.messageTableView.addGestureRecognizer(tapGesture)
// Retrieve messages from Parse
self.retreiveMessages()
}
override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func sendButtonTapped(sender: UIButton) {
// Send button is tapped
// Call the end editing method for the text field
self.messageTextField.endEditing(true)
//Disable the send button and textfield
self.messageTextField.enabled = false
self.sendButton.enabled = false
// Create a PFObject
var newMessageObject:PFObject = PFObject(className: "Message")
// Set the Text key to the text of the messageTextField
newMessageObject["Text"] = self.messageTextField.text
// Save the PFObject
newMessageObject.saveInBackgroundWithBlock { (success:Bool, error:NSError!) -> Void in
if (success == true) {
//Message has been saved!
// TODO: Retrieve the latest messages and reload the table
NSLog("Message saved successfully.")
}
else {
// Something bad happened.
NSLog(error.description)
}
// Enable the textfield and send button
self.sendButton.enabled = true
self.messageTextField.enabled = true
self.messageTextField.text = ""
}
}
func retreiveMessages() {
// Create a new PFQuery
var query:PFQuery = PFQuery(className: "Message")
// Call findobjectsinbackground
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]!, error:NSError!) -> Void in
// clear the messageArray
self.messagesArray = [String]()
// Loop through the objects array
for messageObject in objects {
// Retrieve the Text column of each PFObject
let messageText:String? = (messageObject as PFObject)["Text"] as? String
// Assign it into our messagesArray
if messageText != nil {
self.messagesArray.append(messageText!)
}
}
// Reload the tableview
self.messageTableView.reloadData()
// Reload the tableview
}
}
func tableViewTapped() {
// Force the textfield to end editing
self.messageTextField.endEditing(true)
}
// MARK: Textfield Delegate Methods
func textFieldDidBeginEditing(textField: UITextField) {
// Perform an animation to grow the dockview
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.5, animations: {
self.dockViewHeightConstraint.constant = 350
self.view.layoutIfNeeded()
} , completion: nil)
}
func textFieldDidEndEditing(textField:UITextField) {
// Perform an animation to grow the dockview
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.5, animations: {
self.dockViewHeightConstraint.constant = 60
self.view.layoutIfNeeded()
}, completion: nil)
}
// MARK: TableView Delegate Methods
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return messagesArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Create a table cell
let cell = self.messageTableView.dequeueReusableCellWithIdentifier("MessageCell") as UITableViewCell
// Customize the cell
cell.textLabel?.text = self.messagesArray[indexPath.row]
//Return the cell
return cell
}
}
Copy from here.
And always make sure to call numberOfRowsInSection before cellForRowAtIndexPath.

XCode 6 - issue with registering a touch

So far I have this app that tracks the number of hits versus misses when the user touches a moving bug on the screen. I am able to register the touches for every time the bug is missed, however not when the bug is touched. Could someone help me understand what I am doing incorrectly and perhaps point me towards a possible solution. Thank you much.
import UIKit
class myViewController2: UIViewController {
#IBOutlet weak var lblBugAmount: UILabel!
var isBuggin = false
var hits = 0
var misses = 0
#IBOutlet weak var lblMissAmount: UILabel!
#IBOutlet weak var lblHitAmount: UILabel!
override func touchesBegan(touches: (NSSet!), withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event);
++misses
--hits
lblMissAmount.text = String(misses)
lblHitAmount.text = String(hits)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func btnStop(sender: UIButton) {
isBuggin = false
super.viewDidLoad()
}
#IBOutlet var bugs : UIImageView!
#IBOutlet weak var numberOfBugsSlider: UISlider!
#IBAction func btnAnimate(sender: UIButton) {
let numberOfBugs = Int(self.numberOfBugsSlider.value) //cast to Int, otherwise slider is decimal
for loopNumber in 0...numberOfBugs+3{
// constants for the animation
let duration = 1.0
let options = UIViewAnimationOptions.CurveLinear | UIViewAnimationOptions.Autoreverse
// randomly assign a delay of 0.3 to 1s
let delay = NSTimeInterval( ((Int(rand()) % 1000)+100.0) / 1000.0)
// constants for the bugs
let size : CGFloat = CGFloat( Int(rand()) % 80 + 100.0) //sizes
let yPosition : CGFloat = CGFloat( Int(rand()) % 200 + 20.0) + 80
// create the bugs
let bugs = UIImageView()
bugs.image = UIImage(named: "bug")
bugs.frame = CGRectMake(0-size, yPosition, size, size)
self.view.addSubview(bugs)
// define the animation
UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
// move the bugs
bugs.frame = CGRectMake(320, yPosition, size, size)
}, completion: { animationFinished in
// remove the bugs
bugs.removeFromSuperview()
})
}
}
#IBAction func bugs(outlet: UIView) {
++hits
--misses
lblHitAmount.text = String(hits)
lblMissAmount.text = String(misses)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
EDIT:
touchesBegan & touchesMoved
override func touchesBegan(touches: (NSSet!), withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event);
var touch : UITouch! = touches.anyObject() as UITouch
location = touch.locationInView(self.view)
self.bugs = touch.locationInView(self.view)
}
override func touchesMoved(touches: (NSSet!), withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event);
var touch : UITouch! = touches.anyObject() as UITouch
location = touch.locationInView(self.view)
bugs.center = location
}
User interaction is disabled by default for UIViews and its descendants, you have to explicitly enable it:
// create the bugs
let bugs = UIImageView()
bugs.image = UIImage(named: "bug")
bugs.frame = CGRectMake(0-size, yPosition, size, size)
bugs.userInteractionEnabled = true // <--
self.view.addSubview(bugs)

How i can place object in Scene? SpriteKit

File GameScene have class GameScene, class GameScene have CirclePhysicsDefault:
func circlePhysicsDefault() {
var Circle = SKShapeNode(circleOfRadius: 40)
Circle.position = CGPointMake(500, 500)
Circle.name = "defaultCircle"
Circle.strokeColor = SKColor.blackColor()
Circle.glowWidth = 10.0
Circle.fillColor = SKColor.yellowColor()
Circle.physicsBody = SKPhysicsBody(circleOfRadius: 40)
Circle.physicsBody.dynamic = true
self.addChild(Circle)
}
In file GameViewController i type:
#IBAction func addOneCircle(sender: AnyObject) {
GameScene().circlePhysicsDefault()
}
I linked this to button.
Run application, push the button - nothing happens.
If in GameScene function didMoveToView i call function circlePhysicsDefault, then app launch circle will be placed.
File GameViewController:
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
/* Pick a size for the scene */
let scene = GameScene(fileNamed:"GameScene")
// Configure the view.
let skView = self.view as SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
#IBAction func addOneCircle(sender: AnyObject) {
GameScene(fileNamed:"GameScene").circlePhysicsDefault()
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> Int {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return Int(UIInterfaceOrientationMask.AllButUpsideDown.toRaw())
} else {
return Int(UIInterfaceOrientationMask.All.toRaw())
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return false }
}
File GameScene:
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
circlePhysicsDefault()
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
func sceneSetting() {
self.backgroundColor = SKColor.grayColor()
self.physicsWorld.gravity = CGVectorMake(0.01, -2)
}
func circlePhysicsDefault() {
var Circle = SKShapeNode(circleOfRadius: 40)
Circle.position = CGPointMake(500, 500)
Circle.name = "defaultCircle"
Circle.strokeColor = SKColor.blackColor()
Circle.glowWidth = 10.0
Circle.fillColor = SKColor.yellowColor()
Circle.physicsBody = SKPhysicsBody(circleOfRadius: 40)
Circle.physicsBody.dynamic = true
self.addChild(Circle)
}
}
you are creating a new instance on key press, store a weak reference to the scene and call the method from the wished instance.
#IBAction func addOneCircle(sender: AnyObject) {
myGameSceneRef.circlePhysicsDefault()
}
So now please try the following:
#IBAction func addOneCircle(sender: AnyObject) {
let scene = ((self.view as SKScene).scene as GameScene)
scene.circlePhysicsDefault()
}
Or maybe change "let" to "var"

Resources