How to animate a flashing UIView until a stop button is pressed? - ios

I am trying to make a UIView flash a certain color until a stop button is pressed.
Any help in doing so would be greatly appreciated.

Take a look at the animation methods of UIView. Specifically look at methods like animateWithDuration:animations: and variants. The variants with options are what you want. There are options to repeat and/or auto-reverse the animation.
EDIT:
Actually, if you want the color to flash rather than cross-fade between colors then using a UIView animation might not be the best choice. That's going to cause smooth transitions between colors.
If you want the color to flash from one color to the next you might be better off using a timer and simply setting the background color.
I created a simple custom subclass of UIView that has a variable animateColor. Set it to true and it creates a timer that cycles through an array of background colors. Use 2 colors if you want it to cycle back and forth between colors. Use more if desired.
public class LiveView: UIView {
//Adjust this interval value if desired to get a different flash interval.
//Note that changing the interval will have no effect while the timer is running.
public var interval = 0.5
//Change the array of colors if you want different colors
public var backgroundColors = [UIColor.gray, UIColor.green, UIColor.blue, UIColor.red]
var colorIndex = 0
//Set this flag to true to animate between the colors. Set it to false to stop the animation.
public var animateColor: Bool = false {
didSet {
if animateColor {
colorTimer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true, block: {
timer in
self.colorIndex = (self.colorIndex + 1) % self.backgroundColors.count
self.setColor()
})
} else {
colorTimer?.invalidate()
}
}
}
private weak var colorTimer: Timer?
func setColor() {
backgroundColor = backgroundColors[colorIndex]
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setColor()
}
public override init(frame: CGRect) {
super.init(frame: frame)
setColor()
}
}

Related

IOS/SWIFT How to make the button highlight for a period of time with swift

How do I change the button background color when the button is highlighted with swift,then I also want to know . How can I make this background color last for a period of time instead of clicking it to disappear immediately? For example, I want it to disappear 2 seconds after clicking. I checked some information and couldn't find a way. All I can think of is to write a click event, then change the background color of the button and set a time to change it back
I found the method. As a novice, I can't fully understand it, but it can be used. Friends with similar problems can refer to it
class MyButton : UIButton {
#IBInspectable var normalBackgroundColor: UIColor? {
didSet {
backgroundColor = normalBackgroundColor
}
}
#IBInspectable var highlightedBackgroundColor: UIColor?
override var isHighlighted: Bool {
didSet {
if oldValue == false && isHighlighted {
highlight()
} else if oldValue == true && !isHighlighted {
unHighlight()
}
}
}
func highlight() {
animateBackground(to: highlightedBackgroundColor, duration: highlightDuration)
}
func unHighlight() {
animateBackground(to: normalBackgroundColor, duration: highlightDuration)
}
var highlightDuration: TimeInterval = 1
private func animateBackground(to color: UIColor?, duration: TimeInterval) {
guard let color = color else { return }
UIView.animate(withDuration: highlightDuration) {
self.backgroundColor = color
}
} }
You can create a new file and write the above code
Then bind the button class as shown in the figure
Finally, your button has the content you want in the right property panel
You can modify the animation time by changing the value of highlightduration

Accessibility Increment and Decrement not called for UISlider

I'm trying to make my app more accessible for Voice Over users. I have a slider that has numbers 1-100. If a user with Voice Over turned on swipes up or down to change the value, several numbers are being skipped. This means that an exact number is not able to be set. I'm following the suggestion from this site on subclassing UISlider and overriding accessibilityIncrement() and accessibilityDecrement() but they do not get called when the slider value changes. Below is my subclassed slider. Any idea why the methods are not getting called?
class FontSizeSlider: UISlider {
required init?(coder: NSCoder) {
super.init(coder: coder)
self.isAccessibilityElement = true
self.accessibilityTraits.insert(.adjustable)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func accessibilityIncrement() {
self.value += 1
self.sendActions(for: .valueChanged)
}
override func accessibilityDecrement() {
self.value -= 1
self.sendActions(for: .valueChanged)
}
}
This is something I need to know for work, so this was a fantastic exercise for me. Thank you for posting the question. Anyway, I got it to work after taking a peek at this page on Apple's website.
I could not get the increment/decrement methods to be called, either. I suspect they're stepper-specific. The value property, OTOH, gets called.
Here's the code I came up with to get it to work:
class FontSizeSlider: UISlider {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
isAccessibilityElement = true
accessibilityLabel = "Font Size Slider"
accessibilityIdentifier = "fontSizeSlider"
// accessibilityIdentifier = AccessibilityConstants.fontSizeSlider.rawValue
minimumValue = 0
maximumValue = 100
isContinuous = true
}
override var accessibilityValue: String? {
get {
return sliderValueString
}
set {
super.accessibilityValue = sliderValueString
}
}
override var accessibilityTraits: UIAccessibilityTraits {
get {
return .adjustable
}
set {
super.accessibilityTraits = newValue
}
}
// Nobody needs to know about this outside the class, so marked it private
private var sliderValueString: String {
let stringValue = String(Int(value))
return "The font size is \(stringValue)"
}
}
You'll notice I used the setup() method, which does the same stuff for both initializers. You can tweak your values as you see fit for the min/max values.
You'll note I added accessibilityLabel, so it doesn't read off that it's a generic slider. I added the accessibilityIdentifier in there, too. That's something that can be used for UI tests so the element can be identified.
You'll probably want to put the accessibilityIdentifier somewhere where "everyone" can see it. Perhaps an enum. Here's what the enum implementation would look like:
enum AccessibilityConstants: String {
case fontSizeSlider
}
// Usage
accessibilityIdentifier = AccessibilityConstants.fontSizeSlider.rawValue
I overrode the accessibilityValue with a custom setter and getter. Additionally, I created a computed var for the string that's read off when the accessibilityValue is updated. Here's the code for that portion of it. Note I made it private because nobody outside the class needs to know about it:
// I adapted this from Apple's accessibility page that I posted above
override var accessibilityValue: String? {
get {
return sliderValueString
}
set {
super.accessibilityValue = sliderValueString
}
}
private var sliderValueString: String {
let stringValue = String(Int(value))
return "The font size is \(stringValue)"
}
One last thing...you don't need self everywhere unless you're accessing a property of your custom UISlider inside a closure like an animation block or a completion block.
Update
Deleted...
Update 2
So let's say you're on your viewController, you could add a target action to the slider, like so:
slider.addTarget(self, action: #selector(doSomething), for: .valueChanged)
#objc func doSomething() {
print("How much wood could a wood chuck chuck if a wood chuck could chuck wood")
}
Whenever value changes, your selector will get called.

How to achieve .isHighlighted animation in a Custom UIButton?

Preamble (page down after code for the actual problem):
I have a custom UIButton class in which I replaced the ordinary UIButton isHighlighted animation behavior with this behavior:
When the user's finger is actually on the button (ie. highlighting the button), a stroked outline (square border) will appear around the button. When they are no longer touching the button, the outline disappears.
Also, I have replaced the normal isSelected behavior (background goes blue) with this:
An outline identical to the one used with isHighlighted is drawn, except it is slightly thicker and always there as long as isSelected = true, and it is not there when isSelected = false.
This works, and this is how I did it:
import UIKit
class CustomButton: UIButton {
// BUTTON TYPES:
// Gorsh, enums sure would be swell here. :T
// 1 : plus
// 2 : minus
// 3 : etc etc....
#IBInspectable
var thisButtonsType: Int = 1 { didSet { setNeedsDisplay() } }
#IBInspectable
var fillColor: UIColor = .black { didSet { setNeedsDisplay() } }
#IBInspectable
var strokeColor: UIColor = .black { didSet { setNeedsDisplay() } }
override var isHighlighted: Bool {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
let unitOfMeasure = bounds.width / 5
// draw outline in case we are selected / highlighted
if (isSelected || isHighlighted) {
let tempPath = BezierPathFactory.outline(totalWidth: bounds.width)
if (isSelected) {tempPath.lineWidth = 4.0}
strokeColor.setStroke()
tempPath.stroke()
}
// initialize path object
var path = UIBezierPath()
// get the path corresponding to our button type
switch thisButtonsType {
case 1:
path = BezierPathFactory.plus(gridSpacing: unitOfMeasure)
case 2:
path = BezierPathFactory.minus(gridSpacing: unitOfMeasure)
default: print("hewo!")
}
fillColor.setFill()
path.fill()
}
}
Once again, that code works but ...
What I would really like is if that isHighlighted border outline would gradually fade away after the touch finishes.
Note: In case you're wondering why I would do things this way... I plan to implement lots of different button types... all with different icons "printed" on them... but I want them all to follow these basic behaviors. Only a couple of them are "toggle" buttons that ever become selected, so there IS a use for the highlight fade.
I already know how to do animations... but it's just doing my head in trying to think how to do that in this context.
I wish I could get the UIButton source code.
Is there a way that the fade animation could be added relatively simply to my above code without completely changing the design pattern? Am I going to have to start using some other feature of core graphics like layers?
Thanks!
You might do the following:
Create a subclass of UIButton which adds and manages a sublayer of class CAShapeLayer for the outline the button.
Draw the outline the outline into the shape layer.
Ensure that the layer resizes with the view: Overwrite layoutSubviews of your view such that it updates the frame of the layer and updates the path for the outline.
You should observe or overwrite the state property of UIControl (which is an ancestor of UIButton) to notice the state changes.
Use property animations (CABasicAnimation) for the opacity of the shape layer to fade the outline in and out.

Any possible way to change iOS mobile app all UILabel colour at one place?

I have to change all UILabel colour at one place whenever application loads. I know that there is a way to change the colour for UILabel separately by setting textColor. As this is time taking process to change all UILabel individual programatically or by using StoryBoard.
I need to know the way to make it simple by adding textColor in one place to change the label color. Even for changing Controller label colour is fineSimilar eg. By the means of UILabel categories.
Any snippet will helpful for me to achieve this. Code for individual Controller's UIlabel colour is fine.
There are various ways to handle this. You probably shouldn't use the tintColor property, since Apple intends that as a visual cue for items that are tappable.
I'd suggest creating a custom subclass of UILabel. Let's call it ColorChangingLabel. Define a NotificationCenter notification name labelColorChanged, and when you broadcast that notifictation, add a key/value pair textColor to the notification's userInfo that contains your new text color. You could also add an optional background color key/value pair if you want to be able to change that. (In fact, you could add a whole suite of different key/value pairs that would let you change different properties of your custom labels.)
In your custom UILabel subclass:
Define a function addLabelColorChangedObserver(). Have that
function call the NotificationCenter to add an observer for your
labelColorChanged notification that looks for a textColor in the notification's userInfo and uses that color to change the label's text color.
Override init(frame:) and init(coder:) and have those methods
call your addLabelColorChangedObserver() function.
Implement a deinit method for your UILabel subclass that removes its
observer.
In your app, when you want labels to change their colors, post a notification with a userInfo dictionary containing the new text color.
Once you've done all that, go through all of your app's storyboards select each label, and use the "identity inspector" to change the class of the object to your custom ColorChangingLabel class. That should do it.
Edit:
If you want to be able to target color changes on a view controller by view controller basis, you could set up your labels to have an owningViewController property, and when it's set, they would add the owningViewController as the object parameter when they add themselves as observers of the labelColorChanged notification. Then, to tell a single view controller's labels to change their color, you'd send a notification with the target view controller as the object parameter.
The tricky bit here would be setting the owningViewController property on the labels. You'd want a method to be able to set that up automatically when your view controller's views are loaded. Perhaps in your view controller's viewDidLoad method you'd call a method that would recursively walk the view controller hierarchy, setting itself as the owningViewController for all ColorChangingLabels.
EDIT 2:
I implemented a CustomLabel class as described above. Here's the code:
//
// CustomLabel.swift
// CustomLabel
//
// Created by Duncan Champney on 4/20/17.
// Copyright © 2017 Duncan Champney. All rights reserved.
//
import UIKit
let labelColorChangedNotice: NSNotification.Name = NSNotification.Name("labelColorChangedNotice")
let textColorKey = "textColor"
let backgroundColorKey = "backgroundColor"
class CustomLabel: UILabel {
static var classLabelColorChangeObserver: Any!
static var startingTextColor: UIColor?
static var startingTextBGColor: UIColor?
override class func initialize() {
//Have the CustomLabel class add an observer to record changes to the text color and/or background color even if there are no CustomLabel instances on-screen.
classLabelColorChangeObserver = NotificationCenter.default.addObserver(forName: labelColorChangedNotice,
object: nil,
queue: nil ) {
notification in
if let textColor = notification.userInfo?[textColorKey] as? UIColor {
CustomLabel.startingTextColor = textColor
}
if let backgroundColor = notification.userInfo?[backgroundColorKey] as? UIColor {
CustomLabel.startingTextBGColor = backgroundColor
}
}
}
var labelColorChangeObserver: Any?
override init(frame: CGRect) {
super.init(frame: frame)
labelColorChangeObserver = addLabelColorChangedObserver()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
labelColorChangeObserver = addLabelColorChangedObserver()
}
deinit {
if let labelColorChangeObserver = labelColorChangeObserver {
NotificationCenter.default.removeObserver(observer: labelColorChangeObserver)
}
}
func addLabelColorChangedObserver() {
if let startingTextColor = CustomLabel.startingTextColor {
self.textColor = startingTextColor
}
if let startingTextBGColor = CustomLabel.startingTextBGColor {
self.backgroundColor = startingTextBGColor
}
labelColorChangeObserver = NotificationCenter.default.addObserver(forName: labelColorChangedNotice,
object: nil,
queue: nil ) {
[weak self] //Use a capture list to avoid a retain cycle
notification in
//Once we're in the notification's closure, capture self strongly, or bail if it's nil.
guard let strongSelf = self else {
return
}
//If we've been given a textColor, install it in the label.
if let textColor = notification.userInfo?[textColorKey] as? UIColor {
strongSelf.textColor = textColor
}
//If we've been given a backgroundColor, install it in the label.
if let backgroundColor = notification.userInfo?[backgroundColorKey] as? UIColor {
strongSelf.backgroundColor = backgroundColor
}
}
}
}

How to make custom uibutton darker when pressed in cg?

i need to make my custom buttom which is made in cg to be darker when user pressed it, just like original uibutton highlighted state. I came up with making alpha 50% but then background view is visible and i don't want that. Here is my code for that:
func unhighlightButton(){
self.color = someColor
self.setNeedsDisplay()
}
override var isHighlighted: Bool {
didSet{
if isHighlighted == true{
self.gradientColor = someColor.withAlphaComponent(0.5)
self.setNeedsDisplay()
self.perform(#selector(unhighlightButton), with: nil, afterDelay: 0.1)
}
}
}

Resources