Coreplot Animation of a sequence of plots - core-plot

I have a number of plots, which depict (x,y) data at different time intervals, and wish to plot them in a sequence one after the other(like a gif file). My approach was generate all the plots, use a Timer.scheduledTimer and initially hide all plots, unhiding current plot and hiding previous plot at each fired schedule. The time between each plot hiding/unhiding shows a blank graph for more time than the plots are shown. Each plot has 32x32 data points. How can I speed this up, so I never see a blank graph? Another approach was to fade out one plot, whilst introducing the next, but I see the same effect.
#objc func tapAnimationButton(_ sender: Any) {
isAnimating = !isAnimating
plotSpacesUserInteraction = !plotSpacesUserInteraction
if let _animationButton = animationButton {
_animationButton.isSelected = isAnimating
previousAnimatedPlot = nil
if isAnimating {
animationCounter = 0
for i in 0..<plotDetails.count {
// fieldsplots[i].isHidden = true
fieldsplots[i].opacity = 0.0
}
animationTimer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(animateGraph(_:)), userInfo: nil, repeats: true)
if let _animationTimer = animationTimer {
animateGraph(_animationTimer)
}
}
else {
animationTimer?.invalidate()
animationTimer = nil
}
}
}
#objc func animateGraph(_ timer: Timer) {
if animationSeconds > 120.0 {
timer.invalidate()
self.animationTimer = nil
animationSeconds = 0.0
animationCounter = 0
previousAnimatedPlot = nil
}
else {
if let currentAnimatedPlot = self.graph.plot(at: animationCounter) {
// previousAnimatedPlot?.isHidden = true
// currentAnimatedPlot.isHidden = false
previousAnimatedPlot?.opacity = 1.0
let fadeOutAnimation = CABasicAnimation(keyPath: "opacity")
fadeOutAnimation.duration = 0.1
fadeOutAnimation.isRemovedOnCompletion = false
fadeOutAnimation.fillMode = CAMediaTimingFillMode.forwards
fadeOutAnimation.toValue = Float(0.0)
previousAnimatedPlot?.add(fadeOutAnimation, forKey: "animateOpacity")
currentAnimatedPlot.opacity = 0.0
let fadeInAnimation = CABasicAnimation(keyPath: "opacity")
fadeInAnimation.duration = 0.1
fadeInAnimation.isRemovedOnCompletion = false
fadeInAnimation.fillMode = CAMediaTimingFillMode.forwards
fadeInAnimation.toValue = Float(1.0)
currentAnimatedPlot.add(fadeInAnimation, forKey: "animateOpacity")
previousAnimatedPlot = currentAnimatedPlot
}
animationSeconds += 0.5
animationCounter += 1;
if animationCounter >= plotDetails.count {
animationCounter = 0
}
}
}

The fade in/out method actually works...not sure how I missed that.

As an add-on to answer, in order to produce a gif image one needs to hide/unhide the plots in sequence
for currentPlot in self.graph.allPlots() {
currentPlot.isHidden = true
}
var images: [UIImage] = []
var previousPlot: CPTPlot?
for currentPlot in self.graph.allPlots() {
if let _previousPlot = previousPlot {
_previousPlot.isHidden = true
}
currentPlot.isHidden = false
if let image = graph.imageOfLayer() {
images.append(image)
}
previousPlot = currentPlot
}
for currentPlot in self.graph.allPlots() {
currentPlot.isHidden = false
}
if images.count > 2 {
TwoDPlot_Utilities.GIFExport(with: images, plot: thisplot, plotIndex: plotIndex, frameDelay: 0.5)
}

Related

AudioKit playback cracks

I want to analyze the microphone input frequency and then play the correct note which is near the frequency which was determined. I did that with of AudioKit.
This is working right now but since I implemented AudioKit to get the frequency feature the sound which plays after the frequency detection cracks sometimes during playback. Thats happened after I implemented AudioKit. Everything was fine before that...
var mic: AKMicrophone!
var tracker: AKFrequencyTracker!
var silence: AKBooster!
func initFrequencyTracker() {
AKSettings.channelCount = 2
AKSettings.audioInputEnabled = true
AKSettings.defaultToSpeaker = true
AKSettings.allowAirPlay = true
AKSettings.useBluetooth = true
AKSettings.allowHapticsAndSystemSoundsDuringRecording = true
mic = AKMicrophone()
tracker = AKFrequencyTracker(mic)
silence = AKBooster(tracker, gain: 0)
}
func deinitFrequencyTracker() {
AKSettings.audioInputEnabled = false
plotTimer.invalidate()
do {
try AudioKit.stop()
AudioKit.output = nil
} catch {
print(error)
}
}
func initPlotTimer() {
AudioKit.output = silence
do {
try AKSettings.setSession(category: .playAndRecord, with: [.defaultToSpeaker, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
try AudioKit.start()
} catch {
AKLog("AudioKit did not start!")
}
setupPlot()
plotTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updatePlotUI), userInfo: nil, repeats: true)
}
func setupPlot() {
let plot = AKNodeOutputPlot(mic, frame: audioInputPlot.bounds)
plot.translatesAutoresizingMaskIntoConstraints = false
plot.alpha = 0.3
plot.plotType = .rolling
plot.shouldFill = true
plot.shouldCenterYAxis = false
plot.shouldMirror = true
plot.color = UIColor(named: uiFarbe)
audioInputPlot.addSubview(plot)
// Pin the AKNodeOutputPlot to the audioInputPlot
var constraints = [plot.leadingAnchor.constraint(equalTo: audioInputPlot.leadingAnchor)]
constraints.append(plot.trailingAnchor.constraint(equalTo: audioInputPlot.trailingAnchor))
constraints.append(plot.topAnchor.constraint(equalTo: audioInputPlot.topAnchor))
constraints.append(plot.bottomAnchor.constraint(equalTo: audioInputPlot.bottomAnchor))
constraints.forEach { $0.isActive = true }
}
#objc func updatePlotUI() {
if tracker.amplitude > 0.3 {
let trackerFrequency = Float(tracker.frequency)
guard trackerFrequency < 7_000 else {
// This is a bit of hack because of modern Macbooks giving super high frequencies
return
}
var frequency = trackerFrequency
while frequency > Float(noteFrequencies[noteFrequencies.count - 1]) {
frequency /= 2.0
}
while frequency < Float(noteFrequencies[0]) {
frequency *= 2.0
}
var minDistance: Float = 10_000.0
var index = 0
for i in 0..<noteFrequencies.count {
let distance = fabsf(Float(noteFrequencies[i]) - frequency)
if distance < minDistance {
index = i
minDistance = distance
}
print(minDistance, distance)
}
// let octave = Int(log2f(trackerFrequency / frequency))
frequencyLabel.text = String(format: "%0.1f", tracker.frequency)
if frequencyTranspose(note: notesToTanspose[index]) != droneLabel.text {
momentaneNote = frequencyTranspose(note: notesToTanspose[index])
droneLabel.text = momentaneNote
stopSinglePlayer()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.03, execute: {
self.prepareSinglePlayerFirstForStart(note: self.momentaneNote)
self.startSinglePlayer()
})
}
}
}
func frequencyTranspose(note: String) -> String {
var indexNote = notesToTanspose.firstIndex(of: note)!
let chosenInstrument = UserDefaults.standard.object(forKey: "whichInstrument") as! String
if chosenInstrument == "Bb" {
if indexNote + 2 >= notesToTanspose.count {
indexNote -= 12
}
return notesToTanspose[indexNote + 2]
} else if chosenInstrument == "Eb" {
if indexNote - 3 < 0 {
indexNote += 12
}
return notesToTanspose[indexNote - 3]
} else {
return note
}
}
Appears that your implementation can be improved slightly by putting the multithreading principles of iOS into practice. Now, I'm not an expert in the subject, but if we look into the statement: "the sound which plays after the frequency detection cracks sometimes during playback".
I'd like to point out that the "frequency" of the "crack" is random or unpredictable and this happens during computation.
So, move code that doesn't need to be computed in the main thread to a background thread (https://developer.apple.com/documentation/DISPATCH)
While refactoring, you can test your implementation by increasing the frequency of calls to the callback computation of your Timer, so reduce the value to 0.05 for example. Which means that if you increase the frequency to, let's say 0.2, you'll probably hear less random crackles.
Now, this is easier said than done when considering concurrency but that's what you need to improve.

How can I create an onscreen controller that works in multiple scenes in SpriteKit?

Working on a game in SpriteKit to learn. Its a platformer with an onscreen controller. I have this all working using touchesBegan and touchesEnded to know when the player is pushing the buttons or not. This works fine, however when i want to load the next scene for 'level 2' i need to implement the controller all over again. I could do a lot of copy and pasting but I feel this will lead to a lot of duplication of code. Every tutorial I've ever read said to try to adhere to the DRY principle.
Im sorry if this is simple, but I have <6 months programming experience and am trying to learn and improve. Im assuming I would need to create a separate class for the onscreen controller so it can be reused, but Im a little lost on where to start.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = (touch.location(in: playerCamera))
print("LocationX: \(location.x), LocationY: \(location.y)")
let objects = nodes(at: location)
print("\(objects)")
if rightButton.frame.contains(location) {
rightButtonPressed = true
playerFacingRight = true
playerFacingLeft = false
thePlayer.xScale = 1
let animation = SKAction(named: "running")!
let loopingAnimation = SKAction.repeatForever(animation)
thePlayer.run(loopingAnimation, withKey: "moveRight")
moveRight()
} else if leftButton.frame.contains(location) {
leftButtonPressed = true
playerFacingLeft = true
playerFacingRight = false
thePlayer.xScale = -1
let leftAnimation = SKAction(named: "running")!
let leftLoopingAnimation = SKAction.repeatForever(leftAnimation)
thePlayer.run(leftLoopingAnimation, withKey: "moveLeft")
moveLeft()
} else if upButton.frame.contains(location) {
upButtonPressed = true
print("upButton is pressed")
if playerAndButtonContact == true {
print("contact - player + button + upButtonPressed=true")
print("\(movingPlatform.position)")
button.texture = SKTexture(imageNamed: "switchGreen")
let moveRight = SKAction.moveTo(x: -150, duration: 3)
if movingPlatform.position == CGPoint(x: -355, y: movingPlatform.position.y) {
movingPlatform.run(moveRight)
thePlayer.run(moveRight)
button.run(moveRight)
}
}
if playerAndDoorSwitchContact == true {
let switchPressed = SKAction.run{
self.switchPressedSound()
self.doorSwitch.texture = SKTexture(imageNamed: "switchGreen")
self.door.texture = SKTexture(imageNamed: "DoorUnlocked")
}
let wait = SKAction.wait(forDuration: 2)
let doorOpen = SKAction.run {
let doorOpen = SKSpriteNode(imageNamed: "DoorOpen")
doorOpen.alpha = 0
doorOpen.position = self.door.position
doorOpen.size = self.door.size
doorOpen.size = self.door.size
self.door.zPosition = -2
doorOpen.zPosition = -1
let fadeIn = SKAction.fadeIn(withDuration: 0.5)
let start = SKAction.run {
self.addChild(doorOpen)
doorOpen.run(fadeIn)
}
let sound = SKAction.run {
self.doorOpeningSound()
}
let opening = SKAction.group([sound, start])
self.door.run(opening)
}
let sequence = SKAction.sequence([switchPressed, wait, doorOpen])
self.doorSwitch.run(sequence)
}
if playerAndDoorContact == true {
self.view?.presentScene(level1, transition: transition)
}
} else if downButton.frame.contains(location) {
}
else if shoot.frame.contains(location) {
shoot()
} else if jumpButton.frame.contains(location) {
self.pressed = true
let timerAction = SKAction.wait(forDuration: 0.05)
let update = SKAction.run {
if(self.force < Constants.maximumJumpForce) {
self.force += 2.0
} else {
self.jump(force: Constants.maximumJumpForce)
self.force = Constants.maximumJumpForce
}
}
let sequence = SKAction.sequence([timerAction, update])
let repeat_seq = SKAction.repeatForever(sequence)
self.run(repeat_seq, withKey: "repeatAction")
}
}
}

how to add a delay when you tap when firing a bullet on my game

i need help on this issue, in my game when a node is tapped a bullet is fired, but the problem is that i can tap continually and a lot of bullets fire, i would like to add some kind of delay to the shot.
here is my touches began code
for touch: AnyObject in touches{
let pointOfTouch = touch.location(in:self)
if player1.contains(pointOfTouch) {
fireBullet1()
}
if player2.contains(pointOfTouch) {
fireBullet2()
}
if player3.contains(pointOfTouch) {
fireBullet3()
}
}
}
}
func fireBullet1() {
let bullet = SKSpriteNode(imageNamed: "b")
bullet.position = player1.position
bullet.zPosition = 1
self.addChild(bullet)
let moveBullet = SKAction.moveTo(y: self.size.height + bullet.size.height, duration: 1)
let deleteBullet = SKAction.removeFromParent()
let bulletSequence = SKAction.sequence([moveBullet, deleteBullet])
bullet.run(bulletSequence)
}
func fireBullet2 () {
let bullet2 = SKSpriteNode(imageNamed: "b")
bullet2.position = player2.position
bullet2.zPosition = 1
self.addChild(bullet2)
let moveBullet = SKAction.moveTo(y: self.size.height + bullet2.size.height, duration: 1)
let deleteBullet = SKAction.removeFromParent()
let bulletSequence = SKAction.sequence([moveBullet, deleteBullet])
bullet2.run(bulletSequence)
}
func fireBullet3() {
let bullet3 = SKSpriteNode(imageNamed: "b")
bullet3.position = player3.position
bullet3.zPosition = 1
self.addChild(bullet3)
let moveBullet = SKAction.moveTo(y: self.size.height + bullet3.size.height, duration: 1)
let deleteBullet = SKAction.removeFromParent()
let bulletSequence = SKAction.sequence([moveBullet, deleteBullet])
bullet3.run(bulletSequence)
}
Declare flags to disable multiple firing immediatly
let minFireDelay = 0.5
var allowsFire1 = true
var allowsFire2 = true
var allowsFire3 = true
Update touches began
for touch: AnyObject in touches {
let pointOfTouch = touch.location(in:self)
if allowsFire1 && player1.contains(pointOfTouch) {
fireBullet1()
// disable firing temporarily
allowsFire1 = false
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + minFireDelay) {
allowsFire1 = true
}
}
if allowsFire2 && player2.contains(pointOfTouch) {
fireBullet2()
// disable firing temporarily
allowsFire2 = false
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + minFireDelay) {
allowsFire2 = true
}
}
if allowsFire3 && player3.contains(pointOfTouch) {
fireBullet3()
// disable firing temporarily
allowsFire3 = false
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + minFireDelay) {
allowsFire3 = true
}
}
}
Look up Timer (NSTimer in Swift 2 and Objective-C.)
The idea is as follows:
Have a gunXEnabled Bool for each player's gun. Set each Bool to true initially.
Have your fireBullet1() method check gun1Enabled. If false, do nothing.
If gun1Enabled == true, fire the gun, set gun1Enabled = false, and start a timer that will re-enable the gun once it fires:
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) {
(timer) -> Void) in
gun1Enabled = true
}
I gave you the unfamiliar part, creating the timer. See if you can work out the rest, and if not, post your code with info about what's not working.

Swift - Animate dynamically created UIImageView

Initially I had this code working when I was just animating the one UIImageView that I had. But then I changed it to animate several dynamically created UIImageViews, however since they are dynamically created inside a for loop, I'm finding it difficult to animate them as I did the initial one.
override func viewDidLoad() {
super.viewDidLoad()
var sprite: UIImage = UIImage(named: "sprites/areaLocatorSprite.png")!
var locations:NSArray = animal[eventData]["locations"] as NSArray
for var i = 0; i < locations.count; i++ {
println(locations[i]["locationx"])
var locationx = locations[i]["locationx"] as String
var locationy = locations[i]["locationy"] as String
let x = NSNumberFormatter().numberFromString(locationx)
let y = NSNumberFormatter().numberFromString(locationy)
let cgfloatx = CGFloat(x!)
let cgfloaty = CGFloat(y!)
var mapSprite: UIImageView
mapSprite = UIImageView(image: sprite)
mapSprite.frame = CGRectMake(cgfloatx,cgfloaty,10,10)
townMap.addSubview(mapSprite)
timer = NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: Selector("flash"), userInfo: nil, repeats: true)
}
}
func flash() {
var mapSprite:UIImageView?
if mapSprite?.alpha == 1 {
mapSprite?.alpha = 0
} else {
mapSprite?.alpha = 1
}
}
This does not work as the mapSprite in the flash function is different to the one in the for loop. How can I refer to the one in the for loop and then animate it? Or would there be a better alternative to what I'm currently doing?
Many thanks!
EDIT
Using Xcode 6.2
You need to store the views into a property and then enumerate that property each time your timer event is fired
var sprites: [UIImageView]?
override func viewDidLoad() {
super.viewDidLoad()
var sprite = UIImage(named: "sprites/areaLocatorSprite.png")!
var locations:NSArray = animal[eventData]["locations"] as NSArray
self.sprites = map(locations) {
var locationx = $0["locationx"] as String
var locationy = $0["locationy"] as String
let x = NSNumberFormatter().numberFromString(locationx)
let y = NSNumberFormatter().numberFromString(locationy)
let cgfloatx = CGFloat(x!)
let cgfloaty = CGFloat(y!)
var mapSprite = UIImageView(image: sprite)
mapSprite.frame = CGRectMake(cgfloatx,cgfloaty,10,10)
townMap.addSubview(mapSprite)
return mapSprite
}
timer = NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: Selector("flash"), userInfo: nil, repeats: true)
}
func flash() {
if let sprites = self.sprites {
for sprite in sprites {
sprite.alpha = sprite.alpha == 0 ? 1 : 0
}
}
}

How to set screen brightness with fade animations?

Is it possible to animate the screen brightness change on iOS 5.1+? I am using [UIScreen mainScreen] setBrightness:(float)] but I think that the abrupt change is ugly.
I ran into issues with the accepted answer when attempting to animate to another value with a previous animation in progress. This solution cancels an in-progress animation and animates to the new value:
extension UIScreen {
func setBrightness(_ value: CGFloat, animated: Bool) {
if animated {
_brightnessQueue.cancelAllOperations()
let step: CGFloat = 0.04 * ((value > brightness) ? 1 : -1)
_brightnessQueue.add(operations: stride(from: brightness, through: value, by: step).map({ [weak self] value -> Operation in
let blockOperation = BlockOperation()
unowned let _unownedOperation = blockOperation
blockOperation.addExecutionBlock({
if !_unownedOperation.isCancelled {
Thread.sleep(forTimeInterval: 1 / 60.0)
self?.brightness = value
}
})
return blockOperation
}))
} else {
brightness = value
}
}
}
private let _brightnessQueue: OperationQueue = {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
return queue
}()
Swift 5
import UIKit
extension UIScreen {
public func setBrightness(to value: CGFloat, duration: TimeInterval = 0.3, ticksPerSecond: Double = 120) {
let startingBrightness = UIScreen.main.brightness
let delta = value - startingBrightness
let totalTicks = Int(ticksPerSecond * duration)
let changePerTick = delta / CGFloat(totalTicks)
let delayBetweenTicks = 1 / ticksPerSecond
let time = DispatchTime.now()
for i in 1...totalTicks {
DispatchQueue.main.asyncAfter(deadline: time + delayBetweenTicks * Double(i)) {
UIScreen.main.brightness = max(min(startingBrightness + (changePerTick * CGFloat(i)),1),0)
}
}
}
}
I don't know if this is "animatable" in some other way, but you could do it yourself.
For instance the following example code was hooked up to "Full Bright" and "Half Bright" buttons in the UI. It uses performSelector...afterDelay to change the brightness by 1% every 10ms till the target brightness is reached. You would pick an appropriate change rate based on some experimenting. Actually the refresh rate is, I think, 60 hz so there is probably no point in doing a change at an interval smaller than 1/60th of a second (My example rate was chosen to have nice math). Although you might want to do this on a non-UI thread, it doesn't block the UI.
- (IBAction)fullBright:(id)sender {
CGFloat brightness = [UIScreen mainScreen].brightness;
if (brightness < 1) {
[UIScreen mainScreen].brightness += 0.01;
[self performSelector:#selector(fullBright:) withObject:nil afterDelay:.01];
}
}
- (IBAction)halfBright:(id)sender {
CGFloat brightness = [UIScreen mainScreen].brightness;
if (brightness > 0.5) {
[UIScreen mainScreen].brightness -= 0.01;
[self performSelector:#selector(halfBright:) withObject:nil afterDelay:.01];
}
}
A Swift extension:
extension UIScreen {
private static let step: CGFloat = 0.1
static func animateBrightness(to value: CGFloat) {
guard fabs(UIScreen.main.brightness - value) > step else { return }
let delta = UIScreen.main.brightness > value ? -step : step
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
UIScreen.main.brightness += delta
animateBrightness(to: value)
}
}
}
Based on Charlie Price's great answer, here's a method for "animating" a change in screen brightness to any value desired.
- (void)graduallyAdjustBrightnessToValue:(CGFloat)endValue
{
CGFloat startValue = [[UIScreen mainScreen] brightness];
CGFloat fadeInterval = 0.01;
double delayInSeconds = 0.01;
if (endValue < startValue)
fadeInterval = -fadeInterval;
CGFloat brightness = startValue;
while (fabsf(brightness-endValue)>0) {
brightness += fadeInterval;
if (fabsf(brightness-endValue) < fabsf(fadeInterval))
brightness = endValue;
dispatch_time_t dispatchTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(dispatchTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[UIScreen mainScreen] setBrightness:brightness];
});
}
}
Or you can use NSTimer instead of while loops and performSelector.
finalValue - is value you want to achieve.
Timer fires 30 times with duration 0.02 second for each (you can choose something different but smoothly) and changes brightness value.
weak var timer: NSTimer?
var count = 1
let maxCount = 30
let interval = 0.02
timer = NSTimer
.scheduledTimerWithTimeInterval(interval,
target: self,
selector: #selector(changeBrightness),
userInfo: nil,
repeats: true)
func changeBrightness()
{
guard count < maxCount else { return }
let currentValue = UIScreen.mainScreen().brightness
let restCount = maxCount - count
let diff = (finalValue - currentValue) / CGFloat(restCount)
let newValue = currentValue + diff
UIScreen.mainScreen().brightness = newValue
count += 1
}
You can use this helper if you need to change brightness of your specific ViewController
import Foundation
import UIKit
final class ScreenBrightness {
private var timer: Timer?
private var brightness: CGFloat?
private var isBrighteningScreen = false
private var isDarkeningScreen = false
private init() { }
static let shared = ScreenBrightnessHelper()
//Увеличение яркости экрана до максимального уровня
func brightenDisplay() {
resetTimer()
isBrighteningScreen = true
if #available(iOS 10.0, *), timer == nil {
brightness = UIScreen.main.brightness
timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { (timer) in
UIScreen.main.brightness = UIScreen.main.brightness + 0.01
if UIScreen.main.brightness > 0.99 || !self.isBrighteningScreen {
self.resetTimer()
}
}
}
timer?.fire()
}
//Затемнение экрана до предыдущего уровня
func darkenDisplay() {
resetTimer()
isDarkeningScreen = true
guard let brightness = brightness else {
return
}
if #available(iOS 10.0, *), timer == nil {
timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { (timer) in
UIScreen.main.brightness = UIScreen.main.brightness - 0.01
if UIScreen.main.brightness <= brightness || !self.isDarkeningScreen {
self.resetTimer()
self.brightness = nil
}
}
timer?.fire()
}
}
private func resetTimer() {
timer?.invalidate()
timer = nil
isBrighteningScreen = false
isDarkeningScreen = false
}
}
Call ScreenBrightness.shared.brightenDisplay() in viewWillAppear and if you wanna change it back call method ScreenBrightness.shared.darkenDisplay() that will change brightness back

Resources