How to set screen brightness with fade animations?

本小妞迷上赌 提交于 2020-01-10 19:31:18

问题


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.


回答1:


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];
    }
}



回答2:


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
}()



回答3:


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)
            }
        }

    }
}



回答4:


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)
        }
    }
}



回答5:


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];
        });
    }
}



回答6:


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
}


来源:https://stackoverflow.com/questions/15840979/how-to-set-screen-brightness-with-fade-animations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!