Why is my button not working in Swift Playgrounds? - ios

I am trying to make a playground and I have a button that says "Let's play!" and moves into a new view controller.
I looked at the code from this website and put it into my code:
http://lab.dejaworks.com/ios-swift-3-playground-uibutton-action/
This is all of my code (like, all of it):
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
override func loadView() {
//Introduction
let view = UIView()
view.backgroundColor = .red
//title
func labelCool() {
let label = UILabel()
label.frame = CGRect(x: 50, y: 300, width: 400, height: 100)
label.text = "Add-Add - A Wonderful Game!"
//label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
label.numberOfLines = 3
label.font = UIFont(name: "HelveticaNeue-Bold", size: 30)
UILabel.animate (withDuration: 10.0, animations:{
label.textColor = .black
})
UILabel.animate(withDuration: 5.0, animations:{
label.textColor = .blue
})
view.addSubview(label)
}
labelCool()
//subtitle
let subtitle = UILabel()
subtitle.frame = CGRect(x: 50, y: 400, width: 200, height: 50)
subtitle.text = "Curated and Created by Yours Truly, Adit Dayal!"
subtitle.numberOfLines = 4
self.view = view
view.addSubview(subtitle)
}
override func viewDidLoad() {
class Responder : NSObject {
#objc func action() {
print("Yay!")
}
}
let responder = Responder()
//next page
let button = UIButton(frame : CGRect(x: 0, y: 500, width: 200, height: 50))
button.setTitle("Let's Play!", for: .normal)
button.backgroundColor = .blue
button.addTarget(responder, action: #selector(Responder.action), for: .touchUpInside)
view.addSubview(button)
}
}
class gameViewController: UIViewController {
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
For now, I just want the button to display "Yay!" when clicked, but it is doing nothing!
Does anyone know why? (I'm on a bit of a time constraint)
Thank you so much,
Adit Dayal

Your Responder class is inside the viewDidLoad() function put the class outside like so
class Responder : NSObject {
#objc func action() {
print("Yay!")
}
}
override func viewDidLoad() {
let responder = Responder()
//next page
let button = UIButton(frame : CGRect(x: 0, y: 500, width: 200, height: 50))
button.setTitle("Let's Play!", for: .normal)
button.backgroundColor = .blue
button.addTarget(responder, action: #selector(responder.action), for: .touchUpInside)
view.addSubview(button)
}

The problem is that you are creating the responder object inside the viewDidLoad, as a local variable; this cause the object to be destroyed when the function ends (but we want that object alive even after). You have to retain that object, so instead of creating a local variable, create an instance variable by simply saving it as a class scope:
class Responder : NSObject {
#objc func action() {
print("Yay!")
}
}
let responder = Responder() // this is now outside the viewDidLoad, so it's an instance variable
override func viewDidLoad() {
//next page
let button = UIButton(frame : CGRect(x: 0, y: 500, width: 200, height: 50))
button.setTitle("Let's Play!", for: .normal)
button.backgroundColor = .blue
button.addTarget(responder, action: #selector(Responder.action), for: .touchUpInside)
view.addSubview(button)
}

Related

How to create Onboarding\Walkthrough swift

I'm trying to create a welcome onboarding for the first time users but none of the views are loafing in the simulator, all I'm getting is a red background when the onboardingVC gets presented. Can anyone see the issue as to why the titles, buttons, and images won't appear?
This is the message I'm getting in the console:
Warning: Attempt to present <EMA.WalkthroughVC: 0x7faa2401e5b0> on <EMA.HomeVC: 0x7faa22407e00> whose view is not in the window hierarchy!
FOUND ALL!!
let holderView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = true
view.backgroundColor = .darkGray
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
view.backgroundColor = UIColor.red
configure()
}
private func configure() {
let scrollView = UIScrollView(frame: holderView.bounds)
holderView.addSubview(scrollView)
let titles = ["Hi","Welcome","real nigga"]
for x in 0..<3 {
let pageView = UIView(frame: CGRect(x: CGFloat(x) * holderView.frame.size.width, y: 0, width: holderView.frame.size.width, height: holderView.frame.size.height))
scrollView.addSubview(pageView)
let label = UILabel(frame: CGRect(x: 10, y: 10, width: pageView.frame.size.width-20, height: 120))
let imageView = UIImageView(frame: CGRect(x: 10, y: 10+120+10, width: pageView.frame.size.width-20, height: pageView.frame.size.height - 60 - 130 - 15))
let button = UIButton(frame: CGRect(x: 10, y: pageView.frame.size.height - 60, width: pageView.frame.size.width-20, height: 50))
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
pageView.addSubview(label)
label.text = titles[x]
imageView.contentMode = .scaleAspectFill
imageView.image = UIImage(named: "BankCard\(x)")
pageView.addSubview(imageView)
button.setTitleColor(.red, for: .normal)
button.backgroundColor = .black
button.setTitle("Continue", for: .normal)
if x == 2 {
button.setTitle("Get Started", for: .normal)
}
button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
pageView.addSubview(button)
}
}
#objc func didTapButton(_ button: UIButton) {
}
}
"whose view is not in the window hierarchy"
you didn't add the views that you created to the main view try to add the subviews to the main by using this one
self.view.addSubview(holderView)
also don't forget to add the frame for the holder view like that
UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
view.translatesAutoresizingMaskIntoConstraints = true
and inside the view did load
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
self.view.addSubview(holderView)
}

Button playground swift

I'm just trying to add a button actions which create a view.
Someone can help me?
import UIKit
import PlaygroundSupport
class ViewController : UIViewController {
override func viewDidLoad() {
view.backgroundColor = UIColor.black
navigationController?.isNavigationBarHidden = true
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
button.backgroundColor = UIColor.white
view.addSubview(button)
class Button: ViewController {
#objc func fbtn () {
let newView = UIView()
newView.backgroundColor = UIColor.yellow
view.addSubview(newView)
}
}
button.addTarget(button, action: #selector(Button.fbtn), for: .touchUpInside)
}
}
PlaygroundPage.current.liveView = UINavigationController(rootViewController: ViewController())
There seems to be no point to your nested Button class. Just make fbtn a function of your ViewController class. And make self the target of the button action.
class ViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
navigationController?.isNavigationBarHidden = true
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
button.backgroundColor = .white
view.addSubview(button)
button.addTarget(self, action: #selector(fbtn), for: .touchUpInside)
}
#objc func fbtn() {
let newView = UIView()
newView.backgroundColor = .yellow
view.addSubview(newView)
}
}
Also, give newView a useful frame inside the fbtn function.

How can I get events to my (sub) UIView?

I'm new to Swift and have a hard time understand the event flow. The code below can be run directly in an xcode playground. I have a white UIView in the background. This view has a brown button and a red view as sub-views. Click on them and the events are logged in the controller, just as expected.
But the controller of this white view also adds another view, that has it's own controller class (SubviewController). SubviewController is green and has a blue subview with a black button. Question is... why don't I get any logs from the green, blue and black views/buttons?
import Foundation
import UIKit
import PlaygroundSupport
class TestViewController : UIViewController {
let playButton: UIButton = {
let playButton = UIButton(frame: CGRect(x: 155, y: 135, width: 160, height: 40))
playButton.setTitle("BROWN BUTTON", for: .normal)
playButton.backgroundColor = UIColor.brown
return playButton
}()
override func loadView() {
let viewWhite = UIView()
viewWhite.backgroundColor = UIColor.white
let viewRed = UIView()
viewRed.backgroundColor = UIColor.red
viewRed.frame = CGRect(x: 20, y: 20, width: 40, height: 10)
viewRed.clipsToBounds = true
let recognizer2 = UITapGestureRecognizer(target: self, action: #selector (self.handleTapRed(_:)))
viewRed.addGestureRecognizer(recognizer2)
let recognizer = UITapGestureRecognizer(target: self, action: #selector (self.handleTap(_:)))
viewWhite.addGestureRecognizer(recognizer)
playButton.addTarget(self, action: #selector (self.action) , for: .touchUpInside)
let catList = SubviewController()
viewWhite.addSubview(catList.view)
viewWhite.addSubview(playButton)
viewWhite.addSubview(viewRed)
self.view = viewWhite
}
func action() {
print("Brown button tapped")
}
func handleTap(_ sender:UITapGestureRecognizer){
print("WHITE VIEW (background view) TAPPED")
}
func handleTapRed(_ sender:UITapGestureRecognizer){
print("RED VIEW TAPPED")
}
}
class SubviewController: UIViewController {
let buttonBlack: UIButton = {
let button = UIButton(frame: CGRect(x: 40, y: 10, width: 170, height: 20))
button.backgroundColor = UIColor.black
button.setTitle("BLACK BUTTON", for: .normal)
return button
}()
let viewBlue: UIView = {
let v = UIView()
v.backgroundColor = UIColor.blue
v.frame = CGRect(x: 20, y: 40, width: 240, height: 60)
v.clipsToBounds = true
return v
}()
override func loadView() {
super.loadView()
self.view.backgroundColor = UIColor.green
buttonBlack.addTarget(self, action: #selector (self.blackKlick) , for: .touchUpInside)
self.view.addSubview(viewBlue)
self.view.frame = CGRect(x: 0, y: 40, width: 240, height: 60)
self.view.clipsToBounds = true
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector (self.handleTapGreen(_:))))
viewBlue.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector (self.handleTapBlue(_:))))
viewBlue.addSubview(buttonBlack)
}
func blackKlick() {
print("Black button tapped")
}
func handleTapBlue(_ sender:UITapGestureRecognizer){
print("BLUE VIEW TAPPED")
}
func handleTapGreen(_ sender:UITapGestureRecognizer){
print("GREEN VIEW TAPPED")
}
}
PlaygroundPage.current.liveView = TestViewController()
Thanks for any help!
This line in your current code:
let catList = SubviewController()
creates a local instance of SubvieController. As soon as you exit the loadView() func, that instance is gone.
So, you need a class-level variable to keep that instance around. Add this line:
class TestViewController : UIViewController {
var catList: SubviewController!
and then remove the let from the instantiation line in loadView():
catList = SubviewController()

Swift: Calling UIButton press from another class

I have my ViewController.class and a Menu.class
In the Menu.class I create and setup all the buttons and in the ViewController.class I add the Menu to the view. When I run the code everything is shown on the screen but I am not able to press the button.
This is how my ViewController looks like:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let menu = Menu()
menu.setupView(controller: self, width: 600, height: 120)
self.view.addSubview(menu)
// Do any additional setup after loading the view, typically from a nib.
}
}
And this is my Menu:
import Foundation
import UIKit
class Menu: UIView{
func setupView(controller: ViewController, width: CGFloat, height: CGFloat){
let newGame = UIButton(frame: CGRect(x: controller.view.center.x, y: 300, width: width, height: height))
newGame.center = CGPoint(x: controller.view.center.x, y: 300)
newGame.setTitle("New Game", for: .normal)
newGame.backgroundColor = UIColor.gray
newGame.titleLabel?.font = UIFont(name: "Helvetica", size: 42)
newGame.setTitleColor(UIColor.black, for: .normal)
newGame.addTarget(self, action: #selector(Menu.newGame), for: .touchUpInside)
self.addSubview(newGame)
}
func newGame(){
print("New Game")
}
}
What is my mistake. Do I need to do more initializing so it is able to detect a press?
This is how you should do it. Repeat the operation for buttonTwo and label. Setup the view in viewDidLoad() and setup the frames in viewDidLayoutSubviews.
If you subclass any UIView you should setup the frames in layoutSubviews()
If you want to display a tableView when you click on newGame then create a new UIViewController. Add a UITableView in it, the same way you did add Button and Label in ViewController
import UIKit
class ViewController: UIViewController {
let buttonOne = UIButton()
let buttonTwo = UIButton()
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
buttonOne.backgroundColor = UIColor.gray
buttonOne.setTitle("New Game", for: .normal)
buttonOne.titleLabel?.font = UIFont(name: "Helvetica", size: 42)
buttonOne.setTitleColor(UIColor.black, for: .normal)
buttonOne.addTarget(self, action: #selector(newGame), for: .touchUpInside)
view.addSubview(buttonOne)
view.addSubview(buttonTwo)
view.addSubview(label)
}
override func viewDidLayoutSubviews() {
buttonOne.frame = CGRect(x: 0, y: 300, width: 600, height: 120)
buttonOne.center.x = self.view.center.x
}
func newGame(sender: UIButton?) {
print("New Game")
}
}

Swift 3: How do I increase a variable being displayed as a UILabel, and then update the UILabel programmatically?

I have a label that is supposed to display a score, and a button that is supposed to increase that score each time it's pressed. My problem is that I get an error no matter where I put my function.
If I have the function above the viewDidLoad class then I get an error because it comes before my label, but if I put it anywhere inside viewDidLoad I get an error because I can't call a local function, and if I put it anywhere after, then my button calling the function comes before the function.
Where am I supposed to put these things? Is there a better way of doing this all together? This was supposed to be so simple...
import UIKit
class ViewController: UIViewController {
let phrase = "Your score: "
var increasingNum = 0
func scoreGoUp (sender: UIButton){
increasingNum += 1
label.text = "\(phrase) \(increasingNum)"
}
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: CGRect(x: self.view.frame.size.width / 2 - 100, y: self.view.frame.size.height / 2 - 10, width: 200, height: 20))
label.textAlignment = .center
label.text = "\(phrase) \(increasingNum)"
self.view.addSubview(label)
let button = UIButton(frame: CGRect(x: self.view.frame.size.width / 2 - 150, y: 100, width: 300, height: 50))
button.backgroundColor = UIColor.cyan
button.addTarget(self, action: #selector(scoreGoUp), for: .touchUpInside)
self.view.addSubview(button)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I have modified your code. Hope this help you.
class ViewController: UIViewController {
var label:UILabel!
let phrase = "Your score: "
var increasingNum = 0
override func viewDidLoad() {
super.viewDidLoad()
label = UILabel(frame: CGRect(x: self.view.frame.size.width / 2 - 100, y: self.view.frame.size.height / 2 - 10, width: 200, height: 20))
label.textAlignment = .center
label.text = "\(phrase) \(increasingNum)"
self.view.addSubview(label)
let button = UIButton(frame: CGRect(x: self.view.frame.size.width / 2 - 150, y: 100, width: 300, height: 50))
button.backgroundColor = UIColor.cyan
button.addTarget(self, action: #selector(scoreGoUp), for: .touchUpInside)
self.view.addSubview(button)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func scoreGoUp (sender: UIButton){
increasingNum += 1
label.text = "\(phrase) \(increasingNum)"
}
}
Here is the output
You need to define your label outside of viewDidLoad (like increasingNum), at the moment, your label variable is only visible inside viewDidLoad
var label:UILabel!
I have cleared up your code. The problem was that, you are not keeping track of you UILabel. Just declare a label to be visible in the class.
import UIKit
class ViewController: UIViewController {
let phrase = "Your score: "
var increasingNum = 0
var label: UILabel?
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: CGRect(x: self.view.frame.size.width / 2 - 100, y: self.view.frame.size.height / 2 - 10, width: 200, height: 20))
label.textAlignment = .center
label.text = "\(phrase) \(increasingNum)"
self.view.addSubview(label)
self.label = label
let button = UIButton(frame: CGRect(x: self.view.frame.size.width / 2 - 150, y: 100, width: 300, height: 50))
button.backgroundColor = UIColor.cyan
button.addTarget(self, action: #selector(scoreGoUp), for: .touchUpInside)
self.view.addSubview(button)
}
func scoreGoUp (sender: UIButton){
increasingNum += 1
self.label?.text = "\(phrase) \(increasingNum)"
}
}
Hope this helps!

Resources