Как настроить яркость экрана с помощью анимации затухания?
Можно ли анимировать изменение яркости экрана на iOS 5.1+? я использую [UIScreen mainScreen] setBrightness:(float)]
но я думаю, что резкие перемены ужасны.
5 ответов
Я не знаю, является ли это "анимируемым" каким-либо другим способом, но вы могли бы сделать это самостоятельно. Например, следующий пример кода был подключен к кнопкам "Full Bright" и "Half Bright" в пользовательском интерфейсе. Он использует executeSelector...afterDelay, чтобы изменять яркость на 1% каждые 10 мс, пока не будет достигнута целевая яркость. Вы бы выбрали соответствующую скорость изменения, основываясь на некоторых экспериментах. На самом деле частота обновления составляет, я думаю, 60 Гц, так что, вероятно, нет смысла вносить изменения с интервалом, меньшим 1/60 секунды (мой пример частоты был выбран, чтобы иметь хорошую математику). Хотя вы можете захотеть сделать это в потоке без пользовательского интерфейса, он не блокирует пользовательский интерфейс.
- (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];
}
}
Я столкнулся с проблемами с принятым ответом при попытке анимировать другое значение с предыдущей анимацией. Это решение отменяет текущую анимацию и выполняет анимацию с новым значением:
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 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)
}
}
}
}
Расширение 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)
}
}
}
Или вы можете использовать NSTimer вместо циклов while и executeSelector.
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
}
Основываясь на отличном ответе Чарли Прайса, вот метод для "анимации" изменения яркости экрана до любого желаемого значения.
- (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];
});
}
}
Вы можете использовать этот помощник, если вам нужно изменить яркость вашего конкретного 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
}
}
Вызовите ScreenBrightness.shared.brightenDisplay() в viewWillAppear, и если вы хотите изменить его, вызовите метод ScreenBrightness.shared.darkenDisplay(), который вернет яркость обратно