I'm currently working through one of Angela Yu's udemy courses in which one has to develop a working xylophone app.
The final aim was that the buttons (red, blue, green etc.) should change their opacity while pressed, as in the following code:
#IBAction func noteButton(_ sender: UIButton) {
playSound(soundName: sender.currentTitle!)
sender.alpha = 0.5
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
sender.alpha = 1
}
Is there a possibility to not only change the opacity but also the background color as a whole - e.g. grey (pressed) - back to its original color - after the delay?
I guess you'd have to store the button's original background color somehow but I don't know how.
Well one way would be to set the backgroundColor like so:
sender.backgroundColor = .white
You could also override the isHighlighted function if you are working with a UIButton class that you overrode. like so
override open var isHighlighted: Bool {
didSet {
backgroundColor = isHighlighted ? .black :.white
}
}
Obviously this would have to have to be overridden in a child class of UIButton.
you can store the original in a variable like this
#IBAction func noteButton(_ sender: UIButton) {
playSound(soundName: sender.currentTitle!)
let oldColor = sender.backgroundColor
sender.alpha = 0.5
sender.backgroundColor = .white
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
sender.alpha = 1
sender.backgroundColor = oldColor
}
Related
(Swift, macOS, storyboard)
I have an NSView in a transparent window
I have this in the viewDidLoad. To make the window transparent and the NSView blue:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2){
self.view.window?.isOpaque = false
self.view.window?.backgroundColor = NSColor.clear
}
view1.wantsLayer = true
view1.layer?.backgroundColor = NSColor.green.cgColor
I want to change the width with code when I click a button.
If it has constraints:
#IBAction func button1(_ sender: NSButton) {
view1Width.constant = 74
}
I tried without constraints and different ways to change the width. They all give the same results:
view1.frame = NSRect(x:50, y:120, width:74, height:100)
But there is still a border and a shadow where the old shape was. Why does it happen and how to solve it?
It only happens in specific circumstances:
If the window is transparent (and macOS)
I change the width and do not change the position y
The window must be active. If it is not (If I click to anywhere else) it looks as it should: the shadow around the changed NSView green.
(I have simplified the case to try to find a solution. I have created a new document and there is only this code and I am sure there is no other element)
Since the window is transparent you need to invalidate the shadows.
Apple states about invalidateShadow()
Invalidates the window shadow so that it is recomputed based on the current window shape.
Complete Self-Contained Test Program
It sets up the UI pogrammatically instead of using a storyboard. Other than that, the code is very close to your example.
Note the line:
view.window?.invalidateShadow()
in the onChange method.
import Cocoa
class ViewController: NSViewController {
private let view1 = NSView()
private let changeButton = NSButton()
private var view1Width: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2){
self.view.window?.isOpaque = false
self.view.window?.backgroundColor = NSColor.clear
}
view1.wantsLayer = true
view1.layer?.backgroundColor = NSColor.green.cgColor
}
#objc private func onChange() {
view1Width?.constant += 32
view.window?.invalidateShadow()
}
private func setupUI() {
changeButton.title = "change"
changeButton.bezelStyle = .rounded
changeButton.setButtonType(.momentaryPushIn)
changeButton.target = self
changeButton.action = #selector(onChange)
self.view.addSubview(view1)
self.view.addSubview(changeButton)
self.view1.translatesAutoresizingMaskIntoConstraints = false
self.changeButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view1.centerXAnchor.constraint(equalTo: view.centerXAnchor),
view1.centerYAnchor.constraint(equalTo: view.centerYAnchor),
view1.heightAnchor.constraint(equalToConstant: 128),
changeButton.topAnchor.constraint(equalTo: view1.bottomAnchor, constant:16),
changeButton.centerXAnchor.constraint(equalTo: view1.centerXAnchor)
])
view1Width = view1.widthAnchor.constraint(equalToConstant: 128)
view1Width?.isActive = true
}
}
Result
The desired result with an update of the shadows is accomplished:
I am trying to change NSTextField text color with fade animation by using NSAnimationContext. But it's not working. Please help me to solve this issue. Thanking you all!
Code:
override func viewDidLoad() {
super.viewDidLoad()
label!.animator().textColor = NSColor.black
}
#IBAction func changeColor(_ sender: NSButton){
NSAnimationContext.runAnimationGroup { (context) in
context.duration = 1.0
label!.animator().textColor = NSColor.red
}
}
Here is the outline of one possible solution:
Subclass NSAnimation, say with TextColorAnimation
Have the init take the NSTextField and final NSColor
Override currentProgress as per NSAnimation docs to (a) call the super implementation and (b) set the intermediate color and display the NSTextField
Use NSColor.blend(...) to determine the intermediate color
start this NSAnimation
You should get a nice smooth color transition. HTH
Update the color and alpha value in the completion handler:
#IBAction func changeColor(_ sender: NSButton){
NSAnimationContext.runAnimationGroup({ [self] context in
context.duration = 1.0
context.timingFunction = CAMediaTimingFunction(name: .easeOut)
label.animator().alphaValue = 0.0
label.animator().textColor = NSColor.black
}, completionHandler: { [self] in
NSAnimationContext.runAnimationGroup({ [self] context in
context.duration = 1.0
context.timingFunction = CAMediaTimingFunction(name: .easeIn)
label.animator().alphaValue = 1.0
label.animator().textColor = NSColor.red
}, completionHandler: {
})
})
}
I want to change the alpha when the user pressed the button. I have used the below code and it works.
However, I am having to write this line of code for every button I connect to the assistance.
Is there any way that I can create a method/class/function to enable all buttons to have this function?
#IBAction func sundayButton(_ sender: UIButton) {
sender.alpha = 0.5
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {sender.alpha = 1.0
}
}
You can write extention on Button and call that on every button
extension UIButton {
func setAlpha() {
self.alpha = 0.5
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
self.alpha = 1.0
}
}
}
call it this way:
myButton.setAlpha()
This is in switft code. I would like to change the background color a button that is currently red to blue. However it tapped again I would like it to change from blue to red. How I normally would do this would be.
var counter = 0
var button = UIButton()
func switch(){
if counter % 2 == 0 {
button.backgroundcolor = .blue
}
else {
button.backgroundcolor = .red }
counter += 1}
I am writing this question because although what I am doing is working. I am thinking there has to be a more efficient way to write code instead of declaring a var and diving it.
As there are only two states declare counter as Bool
var backgroundColorIsBlue = false
In the switch function – which doesn't compile because switch is a reserved word – just toggle (invert) the Bool and set the background color. The ternary operator uses the value after the ? if backgroundColorIsBlue is true otherwise the value after the :.
#objc func switchAction(_ sender : UIButton) {
backgroundColorIsBlue.toggle()
sender.backgroundColor = backgroundColorIsBlue ? .blue : .red
}
I'm trying to create a flashlight app for school and I wanted to add a slider to change the background from black to white. I can't seem to be able to figure it out.
I've tried some basic things, but nothing I've seen online works. It's either out of date or I'm just not understanding something.
So first you should get slidder value by creating an #IBAction for its value change and then using it to adjust the color of the background
override func viewDidLoad() {
slider.minimumValue = 0.0
slider.maximumValue = 255.0
}
#IBAction func sliderValueChanged(_ sender: UISlider) {
let currentValue = Int(sender.value)
let backgroundColor = UIColor(
red: CGFloat(currentValue),
green: CGFloat(currentValue),
blue: CGFloat(currentValue),
alpha:1.0
)
self.view.backgroundColor = backgroundColor
}
Assuming you want to use a switch. You can make an if-else statement and change the color of the view based on if the switch is enabled or not. This would be an instant change, not a gradual change.
#IBAction func `switch`(_ sender: Any) {
if ((sender as AnyObject).isOn == true){
view.backgroundColor = UIColor.white
} else {
view.backgroundColor = UIColor.black
}
}