How to check backgroundColor of all buttons - ios

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
}
}
}

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.

Alternate UIView background between two colors by pressing a button

I'm trying to set up one button that each time pressed would alternate between two colours (black and white).
Initially the app loads with a black background, with the first button tap it swaps to a white background, with the second tap it swaps back to a black background and so fourth.
I imagine it would be a simple if else statement, however I don't know how to create a variable that is the current UI background colour.
#IBAction func background_toggle(_ sender: UIButton) {
self.view.backgroundColor = UIColor.white
}
The button swaps it to white, but there isn't any implementation to swap back to black when there is a second press.
You can use backgroundColor as a condition to check which one you should pick next.
Approach using a backgroundColor attribute
#IBAction func background_toggle(_ sender: UIButton) {
if self.view.backgroundColor == .white {
self.view.backgroundColor = .black
} else {
self.view.backgroundColor = .white
}
}
In other words: If backgroundColor is .white, then set it .black
Otherwise, set it .white
Tips:
Since backgroundColor is an UIColor, Swift infers the type, so you can just type .white or .black when assigning it, without having to specify UIColor.white or UIColor.black.
You can have a state variable like a Bool, UIColor or Enum. Then you compare to that instead of the backgroundColor of the view.
Approach using a Bool variable
var isWhite = true
#objc func handleOpenTermsAndConditions() {
if self.isWhite {
self.isWhite = false
self.view.backgroundColor = .black
} else {
self.isWhite = true
self.view.backgroundColor = .white
}
}
Approach using an UIColor variable
var currentBackgroundColor : UIColor = .white
#objc func handleOpenTermsAndConditions() {
if currentBackgroundColor == .white {
self.currentBackgroundColor = .black
self.view.backgroundColor = .black
} else {
self.currentBackgroundColor = .white
self.view.backgroundColor = .white
}
}
Approach using an Enum state
If you want to restrict colors you can create an Enum with available colors. I think it's overkill to use it with some logic that is as simple as .white | .black.
Step 1: Create an enum.
enum AvailableColor {
case white
case black
func currentUIColor() -> UIColor {
switch self {
case .white:
return UIColor.white
case .black:
return UIColor.black
}
}
}
Step 2: Instantiate a state variable and use the enum logic
var currentColorState : AvailableColor = .white
#objc func handleOpenTermsAndConditions() {
if currentColorState == .white {
currentColorState = .black
} else {
currentColorState = .white
}
self.view.backgroundColor = currentColorState.currentUIColor()
}
Don't try to use the contents of the view to determine the next state by comparing the colors.
Separate out your model from your view and keep a separate property that has the current state. You could use a simple boolean flag isBlack, or you could create an enumeration:
enum BackgroundState {
case black, white
}
which has the slight advantage of being easier to expand if you ever want another color/state. (CaseIterable might be helpful then as well.)

How does this code change a button's background color when clicked?

The following code gotten from this post supposedly changes a button's color when it is pressed.
override var highlighted: Bool {
didSet {
if highlighted {
backgroundColor = UIColor.lightGrayColor()
} else {
backgroundColor = UIColor.whiteColor()
}
}
}
However, I was wondering what the variable "highlighted" would corrospond too?
If I programatically added a button to my view like this:
let exampleButton = UIButton()
self.view.addSubview(exampleButton)
//Set constraints,title-text,etc...
How would I get this to work with exampleButton?

IOS UISearchBar Background Color In iOS 9

I have been search a while for this issue , I want my search bar display like BBC News App
I try all related method
for view in searchBar.subviews {
if view.isKindOfClass(NSClassFromString("UISearchBarBackground")!) {
view.removeFromSuperview()
break;
}
}
self.searchBar.tintColor = UIColor.clearColor()
self.searchBar.backgroundColor = UIColor.clearColor()
self.searchBar.translucent = true
here is my output
Am I miss something ??? Please Help me , thx !
Swift 3
To remove the background altogether, set backgroundImage to an empty image:
searchBar.backgroundImage = UIImage()
To set a custom background color, use barTintcolor property:
searchBar.barTintColor = .green
Thx all , I solve the question by setting the background image to 'nil' , which is a nonexistent image in my app
my final output
==================== Update Final Solution ====================
After read more documents . Finally I found a better solution ,
for subView in searchBar.subviews {
for view in subView.subviews {
if view.isKindOfClass(NSClassFromString("UINavigationButton")!) {
let cancelButton = view as! UIButton
cancelButton.setTitle("取消", forState: UIControlState.Normal)
cancelButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
}
if view.isKindOfClass(NSClassFromString("UISearchBarBackground")!) {
let imageView = view as! UIImageView
imageView.removeFromSuperview()
}
}
}
==================== Update Swift4 ====================
for subView in searchBar.subviews {
for view in subView.subviews {
if view.isKind(of: NSClassFromString("UINavigationButton")!) {
let cancelButton = view as! UIButton
cancelButton.setTitleColor(.white, for: .normal)
cancelButton.setTitle("取消", for: .normal)
}
if view.isKind(of: NSClassFromString("UISearchBarBackground")!) {
let imageView = view as! UIImageView
imageView.removeFromSuperview()
}
}
}
Alternate version as an extension
extension UISearchBar {
func removeBackgroundImageView(){
if let view:UIView = self.subviews.first {
for curr in view.subviews {
guard let searchBarBackgroundClass = NSClassFromString("UISearchBarBackground") else {
return
}
if curr.isKind(of:searchBarBackgroundClass){
if let imageView = curr as? UIImageView{
imageView.removeFromSuperview()
break
}
}
}
}
}
}
In my case it helped:
searchView.backgroundImage = UIImage()
searchView.searchTextField.backgroundColor = .white
The current answers will cause runtime errors if run within iOS 13:
Terminating app due to uncaught exception 'NSGenericException', reason:
'Missing or detached view for search bar layout. The application must not remove
<UISearchBarBackground: 0x102d05050; frame = (0 0; 414 56); alpha = 0; hidden = YES;
userInteractionEnabled = NO; layer = <CALayer: 0x280287420>> from the hierarchy.'
If the code must be run by devices between iOS 9 and iOS 13, then the below is a possible solution.
First, create an extension that allows for the recursive finding of a subview based on a class name:
extension UIView {
/// Find the first subview of the specified class.
/// - Parameter className: The class name to search for.
/// - Parameter usingRecursion: True if the search should continue through the subview tree until a match is found; false otherwise
/// - Returns: The first child UIView of the specified class
func findSubview(withClassName className: String, usingRecursion: Bool) -> UIView? {
// If we can convert the class name until a class, we look for a match in the subviews of our current view
if let reflectedClass = NSClassFromString(className) {
for subview in self.subviews {
if subview.isKind(of: reflectedClass) {
return subview
}
}
}
// If recursion was specified, we'll continue into all subviews until a view is found
if usingRecursion {
for subview in self.subviews {
if let tempView = subview.findSubview(withClassName: className, usingRecursion: usingRecursion) {
return tempView
}
}
}
// If we haven't returned yet, there was no match
return nil
}
}
Then, instead of removing the subview, make it fully transparent. The backgroundColorView view is the color that shows up directly underneath the text, but adjusting it is not a necessary part of the solution.
// On iOS 9, there is still an image behind the search bar. We want to remove it.
if let backgroundView = searchBar.findSubview(withClassName: "UISearchBarBackground", usingRecursion: true) {
backgroundView.alpha = 0
}
// The color on iOS 9 is white. This mimics the newer appearance of the post-iOS 9
// search controllers
if let backgroundColorView = searchBar.findSubview(withClassName: "_UISearchBarSearchFieldBackgroundView", usingRecursion: true) as? UIImageView {
backgroundColorView.backgroundColor = UIColor.lightGray
backgroundColorView.layer.cornerRadius = 8
backgroundColorView.alpha = 0.3
backgroundColorView.image = nil
}

How to loop through all UIButtons in my Swift view?

How would I loop through all UIButtons in my view in Swift? I would want to set all the titles to "", but my for-loop in Swift is giving an error.
for btns in self.view as [UIButton] {
// set the title to ""
}
This code should work:
for view in self.view.subviews as [UIView] {
if let btn = view as? UIButton {
btn.setTitleForAllStates("")
}
}
You need to iterate through the subViews array.
Shortened and updated for Swift 3 & 4
for case let button as UIButton in self.view.subviews {
button.setTitleForAllStates("")
}
Looping over subview works, but it's sometimes a little ugly, and has other issues.
If you need to loop over some specific buttons, for example to add corner radius or change tint or background color, you can use an array of IBOutlets and then loop over that.
var buttons = [SkipBtn, AllowBtn]
for button in buttons as! [UIButton] {
button.layer.cornerRadius = 5
}
Swift 4:
let subviewButtons = self.view.subviews.filter({$0.isKind(of: UIButton.self)})
for button in subviewButtons {
//do something
}
To add some context for a common use case, suppose the buttons were in a scroll view and you wanted to highlight the tapped button and de-highlight the other buttons. In this situation, you would direct all buttons to one action method:
#objc private func buttonAction(_ button: UIButton) {
for case let b as UIButton in view.scrollView.subviews {
if b == button {
b.setTitleColor(UIColor.green, for: []) // highlight
} else {
b.setTitleColor(UIColor.black, for: []) // de-highlight
}
}
}
This code seems to be quite useful for iterating over any object within a view, just change UIButton for any other subview type such as UIView or UIImageView, etc.
let filteredSubviews = self.view.subviews.filter({
$0.isKindOfClass(UIButton)})
for view in filteredSubviews {
//Do something
}
Used some of the offered questions out there and created my own. I believe is the most efficient when you want to programmatically set up the title of various UIButtons(in my case I am building a quiz)
By randomising my array list and with just a for loop I printing the item at index to the button title
for view in self.viewForButtons.subviews{
if view.isKindOfClass(UIButton)
{
let button : UIButton = view as! UIButton
button.setTitle("item[i]", forState: .Normal)
}
}
If you have UIView's within self.view then you need to loop through the subviews while searching for UIButton. Using the accepted answer, I made this little function to do so:
Swift 4 + :
func findButton(`in` view: UIView){
for view in view.subviews as [UIView] {
if let button = view as? UIButton {
// Do something with 'button'
}else{
// Loop through subview looking for buttons
findButton(in: view)
}
}
}
Usage:
override func viewDidLoad() {
findButton(in: self.view)
}
Hope this helps!
Here's a short way in Swift if you know the subview only has buttons:
myView.subviews.map {
($0 as? UIButton)!.enabled = false
}

Resources