簡體   English   中英

如何使用淡入淡出動畫設置屏幕亮度?

[英]How to set screen brightness with fade animations?

是否可以在 iOS 5.1+ 上為屏幕亮度變化設置動畫? 我正在使用[UIScreen mainScreen] setBrightness:(float)]但我認為突然的變化很難看。

當我嘗試使用正在進行的上一個動畫將動畫設置為另一個值時,我遇到了已接受答案的問題。 此解決方案取消正在進行的動畫並為新值設置動畫:

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

斯威夫特 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)
            }
        }
        
    }
}

我不知道這是否以其他方式“動畫化”,但你可以自己做。 例如,以下示例代碼連接到 UI 中的“全亮”和“半亮”按鈕。 它使用performSelector...afterDelay每 10 毫秒改變 1% 的亮度,直到達到目標亮度。 您將根據一些試驗選擇合適的變化率。 實際上,我認為刷新率是 60 hz,因此以小於 1/60 秒的間隔進行更改可能沒有意義(我選擇的示例速率具有很好的數學計算)。 盡管您可能希望在非 UI 線程上執行此操作,但它不會阻塞 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];
    }
}

一個 Swift 擴展:

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

基於 Charlie Price 的精彩回答,這里有一種方法可以將屏幕亮度的變化“動畫化”到任何所需的值。

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

或者您可以使用NSTimer代替 while 循環和 performSelector。

finalValue - 是您想要實現的價值。

計時器觸發 30 次,每次持續 0.02 秒(您可以選擇不同但平滑的內容)並更改亮度值。

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
}

如果您需要更改特定 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
    }
}

在 viewWillAppear 中調用 ScreenBrightness.shared.brightenDisplay() ,如果你想改變它,調用方法 ScreenBrightness.shared.darkenDisplay() 將改變亮度

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM