Swift 3 changing the title of a UIButton - ios

I have been looking around the web and I am unable to find a solution for my problem. I want my "START" button text to change to "RESTART" once the game has ended. If any additional information is needed please let me know. Thanks, all help is appreciated. Below is my code.
class ViewController: UIViewController {
var gameOver = false
var stopFuncs = false
var gameTimer = Timer()
var counter = 10
var selected = "NONE"
var score = 0
var colour = "NONE"
#IBOutlet weak var colourLabel: UILabel!
let colourProvider = ColourProvider()
#IBOutlet weak var scoreLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
colour = colourProvider.randomColour()
print(colour)
colourLabel.text = colour
// 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.
}
#IBOutlet weak var counterLabel: UILabel!
func updateCounter() {
if counter >= 0 {
counterLabel.text = String(counter)
counter -= 1
}
}
#IBAction func startButton() {
gameOver = false
counter = 10
stopFuncs = false
var _ = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)
}
#IBAction func greenButton() {
if stopFuncs { return }
compareColours(selectedColour: "GREEN")
changeColourLabel()
colourLabel.textColor = UIColor.green
}
#IBAction func blueButton() {
if stopFuncs { return }
compareColours(selectedColour: "BLUE")
changeColourLabel()
colourLabel.textColor = UIColor.blue
}
#IBAction func yellowButton() {
if stopFuncs { return }
compareColours(selectedColour: "YELLOW")
changeColourLabel()
colourLabel.textColor = UIColor.yellow
}
#IBAction func pinkButton() {
if stopFuncs { return }
compareColours(selectedColour: "GREEN")
changeColourLabel()
colourLabel.textColor = UIColor.red
}
func compareColours(selectedColour: String) {
if gameOver == false && counter >= 1 {
if selectedColour == colour {
score += 1
let scoreString = String(score)
scoreLabel.text = scoreString
}
else {
gameOver = true
}
}
else {
stopFuncs = true
}
}
func changeColourLabel() {
colour = colourProvider.randomColour()
colourLabel.text = colour
print(colour)
}
}

You already have IBOutlets to some of your labels.
For buttons you may need to set up both an IBaction and an IBOutlet.
An IBOutlet is a thing. A noun. It's a reference to a view object.
An IBAction is a verb. An action. It's code that gets called when something happens to a UIControl (tapping a button, moving a slider, changing the selected value on a segmented control, etc.)
The IBaction is a function that gets called when the user interacts with a control (For buttons you almost always link the action to the .touchUpInside control event.)
Naming your actions with names like pinkButton is a bad idea, and leads to confusion. I suggest renaming your actions to verbs, like handlePinkButton (or perhaps "pinkButtonTapped", but I prefer action names to be verbs.)
Note that when you rename an IBAction and/or IBOutlet you have to go into IB (IB = Interface Builder), select the connections inspector, remove the now-incorrect IBOutlet/IBAction and control-drag from the object to the updated outlet/action.
If you don't do that you'll get very confusing crashes at runtime:
Renaming IBOutlets in code without also changing them in IB gives the error "this class is not key value coding-compliant for the key old_outlet_name" (where "old_outlet_name" will be the old name of your outlet.) when you try to load the view controller from the storyboard. Renaming actions )
Renaming IBActions in code without also changing them in IB gives an error "unrecognized selector sent to instance big_hex_number" when you try to tap the button (or trigger the action for other controls.)
You should open your storyboard in the main editor and open the source in the assistant editor, then control-drag from your button in IB into your source code just below your other outlet at the top of your class.

Your button needs to be an IBOutlet rather than an IBAction. When you ctrl-drag from Interface Builder to your code, make sure you select the 'Outlet' option as shown below:
Then you can change the button title like this:
else {
startButton.setTitle("Button Title", for: .normal)
stopFuncs = true
}

Related

Swift backgroundColor comparison not working

When programmatically adding background color to UIButton to system green sender.backgroundColor = UIColor.systemGreen it sets the backgroundColor to SystemGreen, yet when I check it with this if/else statement
if(sender.backgroundColor == UIColor.systemGreen)
{
doSomething()
}
else
{
otherThing()
}
doSomething() is not called, and code goes to the else statement. Why?
I tried this
Step 1: Set the background of UIButton in viewdidload
#IBOutlet weak var currentBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
currentBtn.backgroundColor = UIColor.systemBrown
}
step 2: compare the two colours with help of cgcolour in the button action, its works fine for me, please check your end too.
#IBAction func checkButton(_ sender: UIButton) {
if let getColour = sender.backgroundColor, getColour.cgColor == UIColor.systemBrown.cgColor{
print("comes here")
}else {
print("not here")
}
}

Radio Button Group Swift 3 Xcode 8

I have searched various sources and could not find a clear and simple solution for creating the equivalent of a radio button group in Swift 3 with Xcode 8.3 for an iOS application.
For example if I have 3 buttons in one group and only one should be selected at a time. Currently I am implementing this by changing the state of 2 buttons in the group to not selected when the other one is selected and vice versa.
#IBAction func buttonA(_ sender: Any) {
buttonB.isChecked = false
buttonC.isChecked = false
}
#IBAction func buttonB(_ sender: Any) {
buttonA.isChecked = false
buttonC.isChecked = false
}
#IBAction func buttonC(_ sender: Any) {
buttonA.isChecked = false
buttonB.isChecked = false
}
However I would expect a more efficient way to do this.
Any help on a more efficient solution will be appreciated.
You can connect all your button's IBAction to one single method.
#IBAction func buttonClick(_ sender: UISwitch) { // you're using UISwitch I believe?
}
You should add all the buttons into an array:
// at class level
var buttons: [UISwitch]!
// in viewDidLoad
buttons = [buttonA, buttonB, buttonC]
Then, write the buttonClick method like this:
buttons.forEach { $0.isChecked = false } // uncheck everything
sender.isChecked = true // check the button that is clicked on
Alternatives:
Try using a UITableView. Each row contains one option. When a row is selected, change that row's accessoryType to .checkMark and every other row's to .none.
If you are too lazy, try searching on cocoapods.org and see what other people have made.
Just make a single selector for all three button's touchUpInside event, and set radio_off image for normal state and radio_on image for selected state in your IB, then only you have to connect btnClicked method to all button's touchUpInside event
class ViewController: UIViewController {
#IBOutlet weak var btnFirst:UIButton!
#IBOutlet weak var btnSecond:UIButton!
#IBOutlet weak var btnThird: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 btnClicked(sender:UIButton){
let buttonArray = [btnFirst,btnSecond,btnThird]
buttonArray.forEach{
$0?.isSelected = false
}
sender.isSelected = true
}
Depending on your UI, you could take multiple approaches.
UITableView - Use a UITableView with a checkmark decorator. If your layout for these radio buttons is fairly traditional, this is the correct paradigm. If the layout is a grid instead of a list, you could use UICollectionView.
You can use the func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) in UITableViewDelegate to capture the selection. You can call indexPathForSelectedRow on the tableView when you want to commit the change to determine which cell was selected.
Apple's tutorial on UITableView can be found at:
https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/CreateATableView.html
Manage a group of UIButtons - You could store an array of references to UIButton objects that are part of your radio button group.
protocol RadioButtonDelegate: class {
func didTapButton(_ button: UIButton)
}
class RadioButtonGroup {
private var buttons: [UIButton] = []
weak var delegate: RadioButtonDelegate?
var selectedButton: UIButton? { return buttons.filter { $0.isSelected }.first }
func addButton(_ button: UIButton) {
buttons.append(button)
}
#objc private func didTapButton(_ button: UIButton) {
button.isSelected = true
deselectButtonsOtherThan(button)
delegate?.didTapButton(button)
}
private func deselectButtonsOtherThan(_ selectedButton: UIButton) {
for button in buttons where button != selectedButton {
button.isSelected = false
}
}
}
class MyView: UIView {
private var radioButtonGroup = RadioButtonGroup()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let button1 = UIButton(type: .custom)
button1.setTitle("Eeeny", for: .normal)
let button2 = UIButton(type: .custom)
button2.setTitle("Meeny", for: .normal)
let button3 = UIButton(type: .custom)
button3.setTitle("Miny", for: .normal)
self.radioButtonGroup.addButton(button1)
self.radioButtonGroup.addButton(button2)
self.radioButtonGroup.addButton(button3)
addSubview(button1)
addSubview(button2)
addSubview(button3)
}
}
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var maleLB: UIButton!
#IBOutlet weak var femaleLB: UIButton!
#IBOutlet weak var otherLB: UIButton!
var gender = "Male"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if gender == "Male"{
femaleLB.isSelected = true
}
}
#IBAction func maleBtn(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
femaleLB.isSelected = false
otherLB.isSelected = false
}
else{
sender.isSelected = true
femaleLB.isSelected = false
otherLB.isSelected = false
}
}
#IBAction func femaleBtn(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
maleLB.isSelected = false
otherLB.isSelected = false
}
else{
sender.isSelected = true
maleLB.isSelected = false
otherLB.isSelected = false
}
}
#IBAction func otherBtn(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
maleLB.isSelected = false
femaleLB.isSelected = false
}
else{
sender.isSelected = true
maleLB.isSelected = false
femaleLB.isSelected = false
}
}
}

Could not cast value of type 'UIView' (0x10d54a4c0) to 'UIButton' (0x10d552120)

there was a question like this already made but I tried the suggestions and it didn't work for me still. :/
I am trying to make a quiz app using this tutorial: https://www.youtube.com/watch?v=KNAQ3Y8PGkM&t=1s
Here is a link to download my project: https://www.dropbox.com/s/bwvg6fyrrzudued/kat%20quiz.zip?dl=0
Everything is perfect except I get the error:
Could not cast value of type 'UIView' (0x10d54a4c0) to 'UIButton' (0x10d552120)
I'd really appreciate some help. I tried everything in my knowledge and searching, thank you. :)
import UIKit
class ViewController: UIViewController {
let questions = ["What color is Courage the Cowardly Dog?", "What is the name of the woman that lives with Courage?", "What is the name of the man that lives with Courage?"]
let answers = [["Purple","Grey","Orange"],["Muriel", "Angela", "Elizabeth"], ["Eustace", "Robert", "Ezio"]]
//Variables
var currentQuestion = 0
var rightAnswerPlacement:UInt32 = 0
var points = 0
//Label
#IBOutlet weak var lbl: UILabel!
//Button
#IBAction func action(_ sender: AnyObject) {
if (sender.tag == Int(rightAnswerPlacement))
{
print ("RIGHT!")
points += 1
}
else
{
print ("WRONG!!!!!!")
}
if (currentQuestion != questions.count)
{
newQuestion()
}
else{
performSegue(withIdentifier: "showScore", sender: self)
}
}
override func viewDidAppear(_ animated: Bool) {
newQuestion()
}
//Function that displays new question
func newQuestion(){
lbl.text = questions[currentQuestion]
rightAnswerPlacement = arc4random_uniform(3)+1
//Create a button
var button:UIButton = UIButton()
var x = 1
for i in 1...3
{
//Create a button
button = view.viewWithTag(i) as! UIButton
if (i == Int(rightAnswerPlacement))
{
button.setTitle(answers[currentQuestion][0], for: .normal)
}
else
{
button.setTitle(answers[currentQuestion][x], for: .normal)
x = 2
}
}
currentQuestion += 1
}
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.
}
}
Did you create UI Button in your Story Board ??
In your youtube video, watch 1:45
And remember to set your 3 UI Button's tag to 1, 2 and 3
watch 3:20
Your problem occurs because you've set your View's tag = 1.
You can fix it easily by change View's tag value to a number != 1, 2 and 3
Because your ViewController have 2 view with the same tag = 1. (view and UI Button).
So when you use view.viewWithTag(i), It accidentally select view not UI Button. So it can not convert to UI Button type
P/s: next time, if you want to select your Button directly, you can make an #IBOutlet for that Button as you make with your Label. It will not cause confusing error like that

(Xcode 8 Swift 3). Using Custom Keyboard Extension with a particular Text Field

Since standard Number Pad keyboard has "empty" button, but doesn't have "+/-" button, I decided to create my own Keyboard Extension. I've done it.
But I don't know how to link (and invoke) it with a particular Text Field while other Text Fields using usual keyboards.
Is there any opportunity to apply custom keyboardType like my own custom Keyboard?
I found solution based on simular question: How to input text using the buttons of an in-app custom keyboard
import UIKit
protocol KeyboardDelegate: class {
func keyWasTapped(text: String)
}
class KeyboardView: UIView {
// This variable will be set as the view controller so that
// the keyboard can send messages to the view controller.
weak var delegate: KeyboardDelegate?
// MARK:- keyboard initialization
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initializeSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
initializeSubviews()
}
func initializeSubviews() {
let xibFileName = "KeyboardView" // xib extention not included
let view = Bundle.main.loadNibNamed(xibFileName, owner: self, options: nil)?[0] as! UIView
self.addSubview(view)
view.frame = self.bounds
}
// MARK:- Button actions from .xib file
#IBAction func keyTapped(_ sender: UIButton) {
// When a button is tapped, send that information to the
// delegate (ie, the view controller)
self.delegate?.keyWasTapped(text: sender.titleLabel!.text!) // could alternatively send a tag value
}
}
/* when error: "Could not load NIB in bundle"
Could not load NIB in bundle
Visit the properties of the .xib files in the file inspector ,the property "Target Membership" pitch on the select box ,then your xib file was linked with your target
*/
In main ViewController.swift
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, KeyboardDelegate {
#IBOutlet weak var text1: UITextField!
#IBOutlet weak var text2: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// initialize custom keyboard
let keyboardView = KeyboardView(frame: CGRect(x: 0, y: 0, width: 375, height: 165))
keyboardView.delegate = self // the view controller will be notified by the keyboard whenever a key is tapped
// replace system keyboard with custom keyboard
text1.inputView = keyboardView //accessoryView
text1.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// required method for keyboard delegate protocol
func keyWasTapped(text character: String) {
if Int(character) != nil{
text1.insertText(character)
}
if character == "⌫" {
if !(text1.text?.isEmpty)! {
let beforeText = text1.text!
let truncated = beforeText.substring(to: beforeText.index(before: beforeText.endIndex))
text1.text = truncated
}
}
if character == "±" {
let beforeText = text1.text!
if var number = Int(beforeText) {
number = -number
text1.text = "\(number)"
}
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
/*
if (textField == self.text1) {
//textField.inputView = keyboardView
}
*/
}
}
I have coded a calculator for metric/imperial system. For that, I have coded my own keyboard, too.
I have set up the keyboard as UIButtons stacked within a Stack View.
The Buttons seem to be unknown for Xcode since I have just upgraded to Xcode 8 and the project is still in Swift 2.2.
Then I have set a UITextField and filled its text property using my buttons. This is for example the function for the Button 1 on my keyboard.
#IBOutlet weak var inputField: UITextField!
var numberStr:String = "0"
inputField.text = numberStr
#IBAction func oneKeyboardAction(sender: AnyObject) {
if numberStr == "0" {
numberStr = String(numberStr.characters.dropLast())
}
let newStr:String = numberStr + String("1")
numberStr = newStr
let dotToCommaString = newStr.stringByReplacingOccurrencesOfString(".", withString: ",")
inputField.text = dotToCommaString
}
Also I have deactivated user interaction with the TextField, so the "original Keyboard" will not show.
Edit
Like mentioned in the comment section and to have my answer better fit your needs. You could set my custom keyboard into a UIView overlapping your UIViewController inside the Interface Builder. Set it as MyKeyboardView.hidden = true inside the viewDidLoad().
Then you have your TextField where you want the custom Keyboard to be visible instead of the system one:
func textFieldDidBeginEditing(_ textField: UITextField) {
if (textField == self.yourDesiredTextField) { //the one where you want to use the custom keyboard
MyKeyboardView.hidden = false
}
}
Then you add a gesture recognizer like that:
override func viewDidLoad() {
super.viewDidLoad()
MyKeyboardView.hidden = true
let tap = UITapGestureRecognizer(target: self, action: #selector(gesture))
tap.numberOfTapsRequired = 1
view.addGestureRecognizer(tap)
}
func gesture() {
UIView.animateWithDuration(0.2) {
self.MyKeyboardView.hidden = true
}
}
To have it little more smooth, I have added animateWithDuration when hiding the keyboard.

Adding UIView back to View

I have multiple subviews in my main view controller, I am using a delete button to remove one subview at a time. I am trying to allow the user to bring back the view that was deleted, but the view is not coming back. Any thoughts? In Swift.
#IBOutlet var tornView: UIView!
var deleted = 1
// Delete Button
#IBAction func deleteViewButton(sender: AnyObject) {
if deleted == 1 {
tornView.removeFromSuperview()
deleted = 2
}
}
// Brings View to Screen
#IBAction func showTornAnnotation(sender: AnyObject) {
if toggleState == 1 {
firstSlider.hidden = false
tornView.hidden = false
toggleState = 2
if deleted == 2 {
view.addSubview(tornView)
}
}
else {
firstSlider.hidden = true
tornView.hidden = true
toggleState = 1
}
}
If you want IBOutlet to be removed from the superView and get it added back then you should always use strong references to your IBOutlet. Being said you should also keep the position of the removed view so that you can use it when you are ready to add it back.
Edit: Sample code
#IBOutlet var customView: UIView!
var customViewFrame: CGRect?
override func viewDidLoad() {
super.viewDidLoad()
customView.backgroundColor = UIColor.blueColor()
}
#IBAction func remove(sender: AnyObject) {
customViewFrame = customView.frame
customView.removeFromSuperview()
}
#IBAction func add(sender: AnyObject) {
if let rect = customViewFrame {
customView = UIView.init(frame: rect)
customView.backgroundColor = UIColor.blueColor()
view.addSubview(customView)
view.bringSubviewToFront(customView)
}
}

Resources