Getting UIButton to stay highlighted after tap - ios

I'm trying to replicate the scroll selector at the bottom of the emoji keyboard, where you can select the category by tapping on the appropriate icon and it will also show you in which category you are if you scroll. However, I'm having trouble getting the selected button to appear highlighted for some reason. I can get the scroll to work fine, but when I click on the icon it won't stay highlighted. Is this to do with some property of the touchUpInside trigger and the highlighted property?
My Code
var categoryButtons = [UIButton]()
var categoryDistances = [CGFloat]()
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var curIndex = -1
for d in categoryDistances {
if (scrollView.contentOffset.x + 5 >= d) {
curIndex += 1
}
}
for b in categoryButtons {
b.isHighlighted = false
}
if (curIndex == -1) {
curIndex = 0
}
categoryButtons[curIndex].isHighlighted = true
}
func shortcutSelected(_ sender: UIButton) {
snapSelector.contentOffset.x = categoryDistances[categoryButtons.index(of: sender)!]
for b in categoryButtons {
b.isHighlighted = false
}
sender.isHighlighted = true
}

Got it to work the way I wanted by applying a tint color instead of using the isHighlighted or isSelected properties:
let tintedImg = origImg?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
let shortcut = UIButton()
shortcut.setBackgroundImage(tintedImg, for: .normal)
shortcut.tintColor = UIColor.gray

Related

Display color on different buttons

So I am making a quiz app, and I am using the following code to display to the user if the answer is correct or wrong.
The app looks like this:
Image here
This is the code to display:
#IBAction func checkAnswer(_ sender: UIButton) {
if let question = currentQuestion, let answer = sender.titleLabel?.text {
if (question.validateAnswer(to: answer)) {
score.incrementCorrectAnswers()
currentScore = currentScore + 1
feedbackLabel.textColor = UIColor(red:0.15, green:0.61, blue:0.61, alpha:1.0)
feedbackLabel.text = "Correct!"
scoreLabel.text = "\(currentScore)"
sender.backgroundColor = hexStringToUIColor(hex: "213F4B")
} else {
score.incrementIncorrectAnswers()
feedbackLabel.textColor = UIColor(red:0.82, green:0.40, blue:0.26, alpha:1.0)
feedbackLabel.text = "Wrong, correct answer is: \n\(currentQuestion!.getAnswer())"
sender.shake()
sender.backgroundColor = hexStringToUIColor(hex: "3F2F4B")
}
answer1Button.isEnabled = false
answer2Button.isEnabled = false
answer3Button.isEnabled = false
answer4Button.isEnabled = false
nextQuestionButton.isEnabled = true
feedbackLabel.isHidden = false
}
}
When using this, if the user tap the wrong button, the button turns red, and if the user taps the correct button, the button turns green. How can I make it so if the user taps the wrong button, the answer on the correct button turns green at the same time as the wrong one goes red? Let me know if any other code from project is necessarily.
You could loop through all UIButton's and check for sender.titleLabel?.text like this:
for view in self.view.subviews as [UIView] {
if let btn = view as? UIButton {
if btn.titleLabel?.text == currentQuestion!.getAnswer() {
btn.backgroundColor = hexStringToUIColor(hex: "213F4B") // Green Color
}
}
}
I'm not on my computer so won't be able to test it, so try it out and let me know how it works.

Swift change the position of a button

In the following piece of code I try to move a button and update the score label.
When I move the button the button moves exactly as I intended, but when I update the label as well the button just stays on the same coordinates.
In the piece of code below everything works great.
#IBAction func clickButtonTapped(_ sender: Any) {
if inGame == false {
segmentedControl.isHidden = true
inGame = true
score = 0
} else {
clickButton.isHidden = true
let height = arc4random_uniform(UInt32(screenHeight))
let width = arc4random_uniform(UInt32(screenWidth))
clickButton.center.x = CGFloat(width)
clickButton.center.y = CGFloat(height)
score += 1
clickButton.isHidden = false
}
}
But when I add this below score += 1 the button does not move anymore.
scoreDisplay.text = String(score)
How can I get the button to move and get to scoreDisplay updated?

How to hide uibutton if its title text is empty or unassigned?

The code and question represents an Xcode project in Swift. I have a a group of buttons that display options according to which text is presented on a label.
The label text is derived from the keys of a dictionary and the button texts are derived from the values of that same dictionary. The dictionary type is [String: [String]. The keys and values are both placed in arrays. I currently display the correct data but some values differ in length than others.
For example one key has 3 values and another key has 5. I want to hide the buttons if there is not text to send to it. So if a key is presented in a label and has 3 values I only want to display 3 buttons and so. What would be the best way to achieve this functionality? Here is my code that is not achieving want I want to accomplish:
func startSurvey() {
if surveyQuestions.isEmpty {
surveyQuestions = Array(SampleSurvey().surveyquestions.keys)
print(surveyQuestions)
}
let rand = Int(arc4random_uniform(UInt32(surveyQuestions.count)))
questionTitle.text = surveyQuestions[rand]
var choices = SampleSurvey().surveyquestions[surveyQuestions[rand]]!
print(choices)
print(choices.count)
surveyQuestions.remove(at: rand)
var button = UIButton()
var x = 0
// var choicePool = choices.count
if choices.count == 2 {
for index in 1...2 {
button = view.viewWithTag(index) as! UIButton
button.setTitle(choices[x], for: .normal)
x += 1
if button.titleLabel?.text.isEmpty == true {
button.isHidden = true
}
}
}
else if choices.count == 4 {
for index in 1...4 {
button = view.viewWithTag(index) as! UIButton
button.setTitle(choices[x], for: .normal)
x += 1
if button.titleLabel?.text.isEmpty == true {
button.isHidden = true
}
}
}
Here is a screenshot of the simulator, as you can see this particular key has only 2 values so there are 3 blank buttons, I want to hide the buttons that are blank:
UPDATE: The following code has granted me the functionality I was aiming for:
var button = UIButton()
var x = 0
let buttonTags = [0,1,2,3,4]
if choices.count == 2 {
for idx in buttonTags {
button = surveyChoices[idx]
if idx < choices.count {
button.setTitle(choices[x], for: .normal)
x += 1
} else {
button.isHidden = true
}
}
}
If the text in the button's titleLabel is nil, then your condition will become false.
Try to revise your code like this:
for index in 1...4 {
button = view.viewWithTag(index) as! UIButton
button.setTitle(choices[x], for: .normal)
x += 1
if (button.titleLabel?.text ?? "").isEmpty == true {
button.isHidden = true
}
}
This will check if the text is nil then it will return a "" which is empty.
You can try this:
SWIFT 4
button.isHidden = button.titleLabel?.text == nil || button.titleLabel?.text == ""
Personally I would add the buttons dynamically, one for each choice in the survey. You could easily do this using any of UITableView, UICollectionView or UIStackView by adding a row/cell that contains a button (tableView or collectionView) or just by adding a button to a vertical stack view.
For your specific code, your only iterating over the number of choices, So in the example below (from your code) you are only working on two buttons and not touching the others
if choices.count == 2 {
for index in 1...2 {
button = view.viewWithTag(index) as! UIButton
button.setTitle(choices[x], for: .normal)
x += 1
if button.titleLabel?.text.isEmpty == true {
button.isHidden = true
}
}
}
for index in 1...2... your not doing anything with the other 3.
You should loop through all buttons and if there is a choice for it, set the title, otherwise hide the button
Here is a working example in a Playground:
let question = ["are you expecting a child": ["yes", "no"]]
let choices = question["are you expecting a child"]!
let buttonTags = [0, 1, 2, 3, 4]
let buttons = [
UIButton(),
UIButton(),
UIButton(),
UIButton(),
UIButton()
]
for idx in buttonTags {
let button = buttons[idx]
if idx < choices.count {
button.setTitle(choices[idx], for: .normal)
} else {
button.isHidden = true
}
}
buttons.map {
print($0.titleLabel?.text)
print($0.isHidden)
}
OUPUT
Optional("yes")
false
Optional("no")
false
nil
true
nil
true
nil
true

How to check backgroundColor of all buttons

I want to be able to check if all buttons' background color is UIColor.whiteColor. I'm determining whether a view is in search mode or in normal mode by the button state.
I want to do something similar with the following but contains() checks if array contains certain value. It wouldn't work in my case because UIColor.whiteColor is a property of UIButton.
if contains(categoryScrollView.subviews, UIColor.whiteColor) {
inSearchMode = false
}
Then if I put it in the following way, I do not know how I can make sure all button's background color is white as it will pass validation as soon as any button's background color is white which is not what I need.
for button in categoryScrollView.subviews {
if button.backgroundColor == UIColor.whiteColor() {
inSearchMode = false
}
}
How can I check is background color of all buttons?
I'd enclose this check in a function, like this (note that I'm including a check that each view is a button):
func allWhiteButtons(view: UIView)-> Bool{
for view in view.subViews {
if let button = view as? UIButton {
if button.backgroundColor != UIColor.whiteColor() {
return false
}
}
}
return true
}
var allWhite = true
for button in categoryScrollView.subviews {
if button.backgroundColor != UIColor.whiteColor() {
allWhite = false
}
}
inSearchMode = !allWhite
But IMHO, this is not a good way to do it at all. You should have a code to do state transition and make the buttons white or not white based on this state.
If you don't have a lot of UIButtons and that they are already declared as IBOutlets you can create a function that loops through all your UIButtons :
for button in [yourButton1, yourButton2, yourButton2] {
if button.backgroundColor == UIColor.whiteColor {
// Do something
} else {
// Do something else
}
}
Or you can also loop through all the buttons of your self.view :
for view in self.view.subviews as [UIView] {
if let button = view as? UIButton {
if button.backgroundColor == UIColor.whiteColor {
// Do something
} else {
// Do something else
}
}
}
Add a counter like whiteBtnCount in the loop where you are checking the backgroundcolor.Increment that counter if it matches the color and break the loop once counter reaches the button count. Voila,now you know whether all buttons are white color or not.
var whiteBtnCount: Int = 0
for button in categoryScrollView.subviews {
if button.backgroundColor == UIColor.whiteColor() {
whiteBtnCount += 1
if whiteBtnCount == btnCount { //ensure btnCount variable holds the number of buttons
inSearchMode = false
break
}
}
}

UIButton not reacting to first press in Swift

I am working on a simple (ok, it should be simple) calculator that estimates risk based on a few inputs (toggle on/off)
Everything is working properly, except that the UIButtons need to be tapped 2 times to toggle initially. After that, the UIButtons work as expected.
Here is the code (contained within viewDidLoad())
#IBOutlet weak var confusionButton: UIButton!
var counter = 0
var confusionToggle = 0
and here is the action
#IBAction func pressConfusion(sender: UIButton) {
if confusionToggle == 0 {
confusionButton.backgroundColor = UIColor.clearColor()
confusionButton.alpha = 1;
confusionToggle++;
counter++;
} else {
confusionButton.backgroundColor = UIColor.grayColor()
confusionButton.alpha = 0.5;
confusionToggle = 0
counter--;
}
}
Any thoughts on this one? My Swift skills are very limited (my first attempt with Swift)
Think your just getting yourself confused. Use print statements to first understand what is happening, then do all your fancy button UI changes.
#IBAction func tapButton(sender: UIButton) {
// user println to help debug
println(confusionToggle)
if confusionToggle == 0 {
sender.backgroundColor = UIColor.grayColor()
sender.alpha = 0.5;
confusionToggle++;
counter++;
}
else {
// RESET
sender.backgroundColor = UIColor.clearColor()
sender.alpha = 1;
confusionToggle = 0
counter--;
}
}
I don't know what you trying to do.
Just let you know that confusionToggle will be 0 at first time. So, when you click on the button your first condition will be called, It will clear the background color and increase the value of confusionToggle to 1 then after it's because of 1 it will not go to the first condition. So, it goes to else part and give the background color to the gray. confusionToggle again goes to 0.
And it will iterate every time like 0 - 1 - 0 - 1 ...
If you want to do gray color to the button when you tap then you have to change your logic.
if confusionToggle == 0 {
confusionButton.backgroundColor = UIColor.grayColor()
confusionButton.alpha = 0.5;
confusionToggle = 1;
counter++;
} else {
confusionButton.backgroundColor = UIColor.clearColor()
confusionButton.alpha = 1;
confusionToggle = 0
counter--;
}
Hope it helps to you.

Resources