How to set screen brightness with fade animations?

后端 未结 7 1536
梦如初夏
梦如初夏 2021-01-02 11:32

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 i

相关标签:
7条回答
  • 2021-01-02 12:09

    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
    }()
    
    0 讨论(0)
  • 2021-01-02 12:19

    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)
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-02 12:23

    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
    }
    
    0 讨论(0)
  • 2021-01-02 12:24

    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];
        }
    }
    
    0 讨论(0)
  • 2021-01-02 12:26

    Swift 5

    import Foundation
    
    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)
                }
            }
    
        }
    }
    
    0 讨论(0)
  • 2021-01-02 12:28

    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];
            });
        }
    }
    
    0 讨论(0)
提交回复
热议问题