Как мне оживить эффект gaussian blur в iOS?
Для всего iOS 7 я хочу применить эффект размытия к определенной части экрана, чтобы запутать его, но я не хочу просто бросать размытие сразу, я хочу анимировать его и оживить его так пользователь почти видит эффект размытия.
Почти так же, как если бы в Photoshop вы поменяли значение gaussian blur по биту от 0 до 10, вместо 0 до 10 за один раз.
Я пробовал несколько решений для этого, самым популярным предложением было просто поместить размытое представление поверх не-размытого представления, а затем снизить альфа-значение размытого представления.
Это работает нормально, но не очень приятно, так как нет перехода, это просто оверлей. Пример:
Что было бы лучшим способом добиться такого эффекта? Я знаком с GPUImage, но не знаю, как это сделать с этим.
Было бы здорово, если бы я мог контролировать, какой процент от размытия, в котором он находится, поэтому он может применяться в интерактивном режиме от пользователя. (например: пользователь перетаскивается на полпути, размытие применяется наполовину и т.д.)
Ответы
Ответ 1
С iOS 9 и выше вы можете анимировать эффект визуальных эффектов:
[UIView animateWithDuration:0.3 animations: ^ {
visualEffectView.effect = blurEffect;
} completion:nil];
Это позволит достичь ожидаемого эффекта оживления радиуса размытия.
Я думаю, что если вы аниматируете кроссфейд из не-размытого вида → размытый вид, он будет достаточно приятным. Вам нужно анимировать отображение размытия в верхней части не-размытого вида.
Пусть предположим, что blurView
- это вид, содержащий эффект размытия.
Вот два примера того, как выполнить анимированный переход:
[UIView transitionWithView:self.view duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations: ^ {
[self.view addSubview:blurView];
} completion:nil];
Здесь я предполагаю, что blurView
уже настроен и просто blurView
добавление как subview в анимацию.
Вы также можете достичь этого по-другому:
blurView.alpha = 0.0f;
[UIView animateWithDuration:0.3 animations: ^ {
blurView.alpha = 1.0f;
} completion:nil];
Здесь я делаю вид размытия прозрачным и оживляю его внешний вид. Обратите внимание, что использование этого метода не будет работать со hidden
, поэтому вы хотите использовать свойство alpha
.
Если вы хотите контролировать количество размытия в интерактивном режиме, вот пример того, как достичь:
Сначала создайте образ вида, который вы хотите размыть:
UIGraphicsBeginImageContextWithOptions(nonBlurredView.bounds.size, NO, self.view.window.screen.scale);
[nonBlurredView drawViewHierarchyInRect:nonBlurredView.bounds afterScreenUpdates:NO];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
Сохраните это изображение. Вы просто хотите перерисовать аналогичным образом, если вид был изменен. В противном случае вы должны повторно использовать это изображение, так как это дорого стоить иерархии.
Теперь, когда вам нужно размыть, используйте следующий код:
CIImage *imageToBlur = [CIImage imageWithCGImage:snapshotImage.CGImage];
CIFilter *gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"];
[gaussianBlurFilter setValue:imageToBlur forKey: @"inputImage"];
[gaussianBlurFilter setValue:@10 forKey: @"inputRadius"]; //Here you input the blur radius - the larger, the
CIImage *resultImage = [gaussianBlurFilter valueForKey: @"outputImage"];
UIImage *endImage = [[UIImage alloc] initWithCIImage:resultImage];
Вход inputRadius
дает настройку количества выполняемого размытия. Если вы оживите это, вы достигнете интерактивного ощущения.
Но я по-прежнему считаю, что прежний метод намного проще и будет очень приятным для пользователя.
Ответ 2
Это легко сделать на OS X, где одно представление может CIFilter воздействовать на представление позади него и где процессор является мощным и быстрым. Однако на iOS нет фильтров для компоновки изображений, и размытие занимает некоторое время: вы не можете делать это многократно, живите так же быстро, как и в кадрах анимации. Поэтому необходима некоторая форма компромисса.
Если вы заранее знаете заранее, что хотите размыть, вы можете подготовить серию изображений, используя градацию размытия: не размытие, небольшое размытие, немного более размытие и т.д. Затем вы собираете изображения и воспроизводите их как "кадры" анимационного UIImageView.
Это, однако, не то, что я бы на самом деле посоветовал. То, что я сделал бы, это подготовить изображение размытия и не размытое изображение и использовать CIDissolveTransition для растворения от не-размытого до размытого изображения. Нет, это не то же самое, что постепенно применять размытие, но оно является недорогостоящим и является лучшим "растворяющим" эффектом в панели инструментов.
Ответ 3
Я редко предлагаю решения на полке для проблем с кодированием. Тем не менее, в этом случае я бы всем сердцем рекомендовал LiveFrost. Это действительно солидный подкласс UIView, ориентированный исключительно на репликацию популярного эффекта размытия iOS 7 gaussian.
Я также призываю вас прочитать блог автора относительно его проектных решений для этого класса. Я сделал много исследований специально в этой теме с момента выпуска iOS 7, и у меня есть буквально ZERO COMPLAINTS об этом коде.
Он даже размывает анимацию из коробки! Удачи тебе :)
Ответ 4
Я разработал небольшой проект, который использует GPUImage для живого размытия с переменным размытием и частотой кадров (MSLiveBlur) - это похоже на то, что вам нужно.
В примере приложения у меня есть ползунок, который увеличивает/уменьшает уровень размытия в ответ на действие пользователя, как вы упомянули в своем вопросе. Если вы хотите анимировать его без взаимодействия с пользователем, вы можете сделать таймер, который медленно увеличивает радиус размытия до достижения конечного значения. Однако вы не сможете использовать CoreAnimation с этим решением.
[[MSLiveBlurView sharedInstance] setBlurInterval:0.2];
[[MSLiveBlurView sharedInstance] blurRect:someView.frame];
// Count x from 0 to your final radius
[MSLiveBlurView sharedInstance].blurRadius = x;
Ответ 5
Здесь функция, которую вы можете использовать для анимации размытия с предварительно вычисленными изображениями. Вы говорите, что знакомы с GPUImage, поэтому я использовал его (но он может работать и с простым алгоритмом размытия).
С этим вы можете оживить реальное размытие в реальном времени со стоимостью 1-2% CPU
// configuration
let imageCount: Int = 10
let blurMax: Float = 40.0
// keep images in memory
var currentIdx: Int = 0
var imgs: [UIImage] = []
// func that create the precomputed images with GPUImage (call it in the viewDidLoad for example)
func initBlur() {
let blur = GaussianBlur()
let myImage: UIImage = UIImage(named: "your_image")!
let pictureInput = PictureInput(image: myImage)
let pictureOutput = PictureOutput()
pictureOutput.onlyCaptureNextFrame = false
pictureOutput.imageAvailableCallback = { image in
self.imgs.append(image)
}
pictureInput --> blur --> pictureOutput
for i in 0...imageCount {
blur.blurRadiusInPixels = (Float(i) / Float(imageCount)) * blurMax
pictureInput.processImage(synchronously: true)
}
}
// function that return the correct image from the image set with a blur percentage from a value between 0 and 1 where 0 = no blur and 1 full blurred.
func getBlurredImage(value: Float) -> UIImage? {
// return nil if there isn't precompiled images
if imgs.count == 0 {
return nil
}
// get the desired blurred image index
let idx = Int(value * Float(imageCount - 1))
// if the index changed, check the correctness of the index
if currentIdx != idx {
if idx < 0 {
currentIdx = 0
}
else if idx >= imgs.count {
currentIdx = imageCount - 1
}
else {
currentIdx = idx
}
}
return imgs[currentIdx]
}
И это он, затем вы можете использовать его, например, с помощью таймера или в функции scrollViewDidScroll, например:
imageView.image = getBlurredImage(value: yOffset / height)