Cannot update UIButton.image after view loads - ios

I am attempting something relatively simple. I have a UIButton that loads with an image:
#IBOutlet var peer5Outlet: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
peer5Outlet.enabled = true
var img = UIImage(named: "camera")
peer5Outlet.setImage(UIImage(named: "camera"),forState: UIControlState.Normal) }
Once it is loaded, I simply want to update that image by calling a method:
func updateButtonImage() {
peer5Outlet.imageView!.image = UIImage(named: "connected")!
print("peer5Outlet.imageView!.image = \(peer5Outlet!.imageView!.image!)")
}
However, I am still unable to update the image; the original image never changes in the view.
Perhaps I am missing some sort of view reload method?

Update your updateButtonImage function to
func updateButtonImage() {
peer5Outlet.setImage(UIImage(named: "connected"), forState: .Normal)
print("peer5Outlet.imageView!.image = \(peer5Outlet!.imageView!.image!)")
}

Try
peer5Outlet.setBackgroundImage(UIImage(named: "connected"), forState: UIControlState.Normal)
Edit: In order to use the setImage method, you need to change the button's type to "Custom"...

You need to use the main thread whenever you're touching UIImage on UI
GCD - main vs background thread for updating a UIImageView
func updateButtonImage() {
dispatch_async(dispatch_get_main_queue()) {
// update image
}
}

Related

IOS/Swift: check for button image to toggle button image

I am just learning Swift and am trying to toggle a button based on a user action between two images. It would be nice to just check the name of the images showing and toggle to the other one.
I am able to get the image from the button but not necessarily it's name. My question is how to compare it to the image name in Swift.
func toggleImage(){
var img = self.sendButton.image(for: .normal)//NO ERROR
if img.isEqual(image-one) {
//ERROR HERE
//switch to image-two
} else {
//switch to image-one
}
}
Thanks in advance for any suggestions.
There is a better way. Treat the button like a checkbox. The unchecked state is image 1, the checked state is image 2.
To setup a UIButton to work like a checkbox, use the isSelected property.
sendButton.setImage(UIImage(named: "image1"), for: .normal)
sendButton.setImage(UIImage(named: "image2"), for: .selected)
// You may also need to set the image for the highlighted selected state.
sendButton.setImage(UIImage(named: "image2"), for: [.selected, .highlighted])
Now that the button knows about both images, you can switch between the to using the isSelected property.
func toggleImage() {
sendButton.isSelected = !sendButton.isSelected
}
Using ===
private let image-one = UIImage(named: "name1")
private let image-two = UIImage(named: "name2")
override func viewDidLoad() {
sendButton.setImage(image-one, for: .normal)
}
func toggle image() {
if self.sendButton.currentImage === image-one {
.....
}
}
Using flags (less elegant, but much safer):
enum WhichImage {
case image-one, image-two
}
private var whichImage: WhichImage = .image-one
Instead of checking images you check whichImage and update it when image is changed.
Set Images in Interface approach the just change state of button in code.
Here is the code to change the state
#IBAction func fastButtonAction(_ sender: Any) {
fastButton.isSelected = !fastButton.isSelected
}
You need to get image name and compare it like below
if self.sendButton.currentImage == UIImage(named: "image-one") {
//switch to image-two
}else {
//switch to image-one
}

Cosmic mind - how to change title bar button's tint color

import UIKit
import Material
class MyVC: UITableViewController {
fileprivate var deleteButton: IconButton!
override func viewDidLoad() {
super.viewDidLoad()
prepareDeleteButton()
navigationItem.rightViews = [deleteButton]
}
// other delegates of UITableView
}
extension MyVC {
fileprivate func prepareDeleteButton() {
deleteButton = IconButton(image: UIImage(named: "Trash"))
deleteButton.tintColor = Color.red.base
deleteButton.addTarget(self, action: #selector(doSomething), for: .touchUpInside)
}
#objc
fileprivate func doSomething() {
print("delete accessory")
}
}
Note that MyVC is pushed from another ViewController.
In MyVC, I want my trash can icon to be at the upper right corner of the screen, which is navigationItem.rightViews = [deleteButton], and to have red base color deleteButton.tintColor = Color.red.base.
But it does not work in the code above, the trash can is still black. How can I change its tint color?
It seems that my trash icon is a little bigger then other Cosmic Mind icons at the same rightViews although it has the same size as Cosmic Mind icons (24x24 #1x). Is it true? How to make it a little smaller?
Regards,
The issue with your code is that you are not using the correct rendering mode. Try this:
deleteButton = IconButton(image: UIImage(named: "Trash")!.withRenderingMode(.alwaysOriginal))
All the best!

UIButton's animating images doesn't show swift

This is driving me nuts. I've spent two days following all documentation I can find on how to animate UIImageview. But no animating images on the UIButton are shown when I run the app and code (called in viewDidLoad).
The last if-statement even prints out "yes, it running". But nothing is shown in the simulator or on device.
Update: Have added the func setImage(_ image: UIImage?, for state: UIControlState): function. Now the first images loads and is shown, but still no animating...
Have also tried giving the button a separate Outlet - same result...
I'm really stuck now.
var Cowboy:[UIImage] = [UIImage(named: "Cowboy__000")!, UIImage(named: "Cowboy__001")!,UIImage(named: "Cowboy__002")!,UIImage(named: "Cowboy__003")!,UIImage(named: "Cowboy__004")!,UIImage(named: "Cowboy__005")!,UIImage(named: "Cowboy__006")!,UIImage(named: "Cowboy__007")!,UIImage(named: "Cowboy__008")!, UIImage(named: "Cowboy__009")!]
var currentAnimationImages = [UIImage]
for i in 0..<Cowboy.count {
currentAnimationImages.append(Cowboy[i])
}
//buttons stored in outlet collection
print("currentAnimationImages", currentAnimationImages) //the array contains the images!
buttons[0].setImage(currentAnimationImages.first, for: .normal) //is shown
//nothing happens...
buttons[0].imageView!.animationImages = currentAnimationImages
buttons[0].imageView!.animationDuration = 0.2
buttons[0].imageView!.animationRepeatCount = 10
buttons[0].imageView!.startAnimating()
if buttons[0].imageView!.isAnimating == true {
print("yes, running") //this is printed out!
} else {
print("no, not running")
}
All help is needed and appreciated.
You have to call func setImage(_ image: UIImage?, for state: UIControlState): get the image to show before animating it.
For example:
buttons[0]. setImage(currentAnimationImages[0], forState: .Normal)
// Now you can start animating
buttons[0].imageView!.animationImages = currentAnimationImages
buttons[0].imageView!.animationDuration = 0.2
buttons[0].imageView!.animationRepeatCount = 10
buttons[0].imageView!.startAnimating()

UIButton's backgroundImage's content mode not respected

I'm putting the finishing touches on an app I'm about to publish and I've enountered difficulty getting the contentMode of a UIButton's background image to be respected. Regardless of the contentMode I specify, the image just gets plopped in the background with no regard for the contentMode setting.
I've looked at a post covering this topic, but it doesn't appear to do anything in my circumstance.
This is called in from viewDidLoad:
// I tried putting the contentMode lines here...
myButton.imageView!.contentMode = .scaleAspectFit
myButton.contentMode = .scaleAspectFit
myButton.setBackgroundImage(UIImage(named: "myImage.png"), for: .normal)
// ...and here
// myButton.imageView!.contentMode = .scaleAspectFit
// myButton.contentMode = .scaleAspectFit
// I threw this in for S's & G's to see if it would work...it didn't
myButton.translatesAutoresizingMaskIntoConstraints = false
myButton.imageView?.translatesAutoresizingMaskIntoConstraints = true
I'm not sure what I'm missing, but I rest assured it will be something startling stupid on my part. I welcome suggestions on how I can get the contentMode of a UIButton's background image to be respected. Thank you for reading.
Update
The button is typed as a custom button, not a system button.
The problem is that you add an image using setBackgroundImage() method. This adds your image to some private UIImageView that you can't reach directly like myButton.imageView!. In your code, you're applying contentType for you button instead of its background image.
If you want to reach this background UIImageView you need to use subviews array. But if you try to do this inside your viewDidLoad() method, you'll find that background UIImageView hasn't been added yet because your buttons layout method wasn't called. There are 2 ways to fix that.
Solution 1 – call layoutIfNeeded explicitly:
override func viewDidLoad() {
super.viewDidLoad()
myButton.setBackgroundImage(UIImage(named: "myImage"), for: .normal)
myButton.layoutIfNeeded()
myButton.subviews.first?.contentMode = .scaleAspectFit
}
Solution 2 – move contentMode setup at viewDidAppear method.
override func viewDidLoad() {
super.viewDidLoad()
myButton.setBackgroundImage(UIImage(named: "myImage"), for: .normal)
myButton.setTitle("Some title", for: .normal)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
myButton.subviews.first?.contentMode = .scaleAspectFit
}
Hope it helps you.
To simplify the accepted answer, all you need to do is layout the subviews and your setup code can be done in one place.
override func viewDidLoad() {
super.viewDidLoad()
myButton.setBackgroundImage(UIImage(named: "myImage.png"), for: .normal)
myButton.layoutIfNeeded()
myButton.subviews.first?.contentMode = .scaleAspectFill
}
A button's imageView property and backgroundImage property are two separate things.
Unlike the accepted answer, you can use the imageView property instead.
override func viewDidLoad() {
super.viewDidLoad()
myButton.setImage(UIImage(named: "myImage.png"), for: .normal)
myButton.imageView?.contentMode = .scaleAspectFill
}

How to add property to UIButton?

thanks for all help:)! fixed it using iboutlet collection and add properies on viewDidLoad
I'm trying to add properties to keyboard keys like layer.shadowColor or layer.shadowRadius.
I got an error
'Value of type '(UIButton)' -> () has no member 'layer'
how to fix this ?
this is my code keyboardViewController.swift
import UIKit
class KeyboardViewController: UIInputViewController {
var newKeyboardView: UIView!
#IBAction func keyPressed(sender: UIButton) {
}
#IBOutlet var nextKeyboardButton: UIButton!
override func updateViewConstraints() {
super.updateViewConstraints()
// Add custom view sizing constraints here
}
override func viewDidLoad() {
super.viewDidLoad()
loadInterface()
}
func loadInterface() {
// load the nib file
let keyboardNib = UINib(nibName: "newKeyboard", bundle: nil)
// instantiate the view
newKeyboardView = keyboardNib.instantiateWithOwner(self, options: nil)[0] as! UIView
// add the interface to the main view
view.addSubview(newKeyboardView)
// copy the background color
view.backgroundColor = newKeyboardView.backgroundColor
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated
}
override func textWillChange(textInput: UITextInput?) {
// The app is about to change the document's contents. Perform any preparation here.
}
override func textDidChange(textInput: UITextInput?) {
// The app has just changed the document's contents, the document context has been updated.
var textColor: UIColor
let proxy = self.textDocumentProxy
if proxy.keyboardAppearance == UIKeyboardAppearance.Dark {
textColor = UIColor.whiteColor()
} else {
textColor = UIColor.blackColor()
}
self.nextKeyboardButton.setTitleColor(textColor, forState: .Normal)
}
}
I think that in order to apply some style to the button, you need an outlet to this button.
Right now, from what I can understand, you are trying to apply styles to the button from the #IBAction to the sender, which is not the proper way to do it.
Try to make an outlet to the button in the view controller and then to apply the styles from within the viewDidLoad method.
I hope this is clear, but if you want a more specific answer you need to show us what you tried, for example pasting the code you have in the view controller
EDIT:
Based on the code you post, the keyboard is a Nib you instantiate from loadInterface(). I don't have a clear vision of the whole thing with only this piece of code, but it seems to me that you are trying to apply some styles to every key button of a keyboard view. Unfortunately this really depends on how the keyboard is implemented, can you provide some more details?
Anyway, from what I see I think you didn't write this code: probably you are following a tutorial or maintaining someone else's code. That's ok, but I suggest you to follow a an introduction course to iOS development with Swift, like the Udacity's one, which is fantastic IMHO (https://www.udacity.com/course/intro-to-ios-app-development-with-swift--ud585)
If you try to format your UIButton with QuartzCore framework, you'll need to import it first:
import QuartzCore
Then you will be able to access those members.
For example (latest swift3 code):
#IBAction func keyPressed(sender: UIButton) {
let button = sender as UIButton!
button?.backgroundColor = UIColor.red
button?.layer.shadowColor = UIColor.black.cgColor
button?.layer.shadowRadius = 1.0
button?.layer.cornerRadius = 4.0
}
In case you need to apply your styles sooner, try to consider to put this code into viewDidLoad or viewDidAppear methods:
self.nextKeyboardButton.backgroundColor = UIColor.red
self.nextKeyboardButton.layer.shadowColor = UIColor.black.cgColor
self.nextKeyboardButton.layer.shadowRadius = 1.0
self.nextKeyboardButton.layer.cornerRadius = 4.0
Seems like you're trying to "add property" not to a button, but rather to a closure which accepts a button as an argument.
Make it like this:
nextKeyboardButton.layer.shadowColor = UIColor.redColor.cgColor
nextKeyboardButton.layer.shadowRadius = 5.0

Resources