ios - Menos desenfoque con `Visual Effect View with Blur`?
objective-c ios8 (6)
El título prácticamente lo pregunta todo ...
Estoy jugando con la Vista de Visual Effect View with Blur
iOS8 Visual Effect View with Blur
. Se trata de un UIImageView
que muestra una foto de fondo seleccionable por el usuario. La vista que se coloca en el ContentView en sí es mi propia vista personalizada, muestra un tipo de gráfico / calendario. La mayor parte de dicho gráfico de calendario es transparente. El desenfoque que se aplica a la foto detrás de él es muy pesado. Me gustaría dejar pasar más detalles. Pero Apple solo parece dar tres valores enlatados:
typedef enum {
UIBlurEffectStyleExtraLight,
UIBlurEffectStyleLight,
UIBlurEffectStyleDark
} UIBlurEffectStyle;
He monjeado con diferentes alfas y colores de fondo de UIVisualEffectView
(aunque la documentación advierte contra eso), pero eso no hace más que empeorar las cosas.
Agregue un BlurEffectView a una vista con alfa <1 de view
func addBlurEffectView() -> Void {
if !UIAccessibilityIsReduceTransparencyEnabled() {
let viewContainer = UIView()
viewContainer.frame = self.view.bounds
viewContainer.alpha = 0.5
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.layer.zPosition = -0.5;
blurEffectView.frame = self.view.bounds;
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
viewContainer.addSubview(blurEffectView)
self.view.addSubview(viewContainer)
self.view.sendSubview(toBack: viewContainer)
}
}
Es una pena que Apple no haya proporcionado ninguna opción para el efecto de desenfoque. Pero esta solución funcionó para mí: animar el efecto de desenfoque y pausarlo antes de completarlo.
func blurEffectView(enable enable: Bool) {
let enabled = self.blurView.effect != nil
guard enable != enabled else { return }
switch enable {
case true:
let blurEffect = UIBlurEffect(style: .ExtraLight)
UIView.animateWithDuration(1.5) {
self.blurView.effect = blurEffect
}
self.blurView.pauseAnimation(delay: 0.3)
case false:
self.blurView.resumeAnimation()
UIView.animateWithDuration(0.1) {
self.blurView.effect = nil
}
}
}
y las extensiones UIView para pausar (con un retraso) y reanudar la animación de la vista
extension UIView {
public func pauseAnimation(delay delay: Double) {
let time = delay + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, time, 0, 0, 0, { timer in
let layer = self.layer
let pausedTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)
layer.speed = 0.0
layer.timeOffset = pausedTime
})
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes)
}
public func resumeAnimation() {
let pausedTime = layer.timeOffset
layer.speed = 1.0
layer.timeOffset = 0.0
layer.beginTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil) - pausedTime
}
}
Esta respuesta se basa en la excelente respuesta anterior de Mitja Semolic . Lo convertí en swift 3, agregué una explicación a lo que sucedía en los comentarios, lo convertí en una extensión de un UIViewController para que cualquier VC lo pueda llamar a voluntad, agregué una vista no difuminada para mostrar la aplicación selectiva y agregué un bloque de finalización para que el controlador de vista llamante puede hacer lo que quiera al completar el desenfoque.
import UIKit
//This extension implements a blur to the entire screen, puts up a HUD and then waits and dismisses the view.
extension UIViewController {
func blurAndShowHUD(duration: Double, message: String, completion: @escaping () -> Void) { //with completion block
//1. Create the blur effect & the view it will occupy
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.light)
let blurEffectView = UIVisualEffectView()//(effect: blurEffect)
blurEffectView.frame = self.view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
//2. Add the effect view to the main view
self.view.addSubview(blurEffectView)
//3. Create the hud and add it to the main view
let hud = HudView.getHUD(view: self.view, withMessage: message)
self.view.addSubview(hud)
//4. Begin applying the blur effect to the effect view
UIView.animate(withDuration: 0.01, animations: {
blurEffectView.effect = blurEffect
})
//5. Halt the blur effects application to achieve the desired blur radius
self.view.pauseAnimationsInThisView(delay: 0.004)
//6. Remove the view (& the HUD) after the completion of the duration
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
blurEffectView.removeFromSuperview()
hud.removeFromSuperview()
self.view.resumeAnimationsInThisView()
completion()
}
}
}
extension UIView {
public func pauseAnimationsInThisView(delay: Double) {
let time = delay + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, time, 0, 0, 0, { timer in
let layer = self.layer
let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil)
layer.speed = 0.0
layer.timeOffset = pausedTime
})
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
}
public func resumeAnimationsInThisView() {
let pausedTime = layer.timeOffset
layer.speed = 1.0
layer.timeOffset = 0.0
layer.beginTime = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
}
}
Confirmé que funciona tanto con iOS 10.3.1 como con iOS 11
Esto funciona para mí
Puse UIVisualEffectView
en una UIView
antes de agregar a mi vista.
Hago que esta función sea más fácil de usar. Puede usar esta función para hacer borrosa cualquier área en su vista.
func addBlurArea(area: CGRect, style: UIBlurEffectStyle) {
let effect = UIBlurEffect(style: style)
let blurView = UIVisualEffectView(effect: effect)
let container = UIView(frame: area)
blurView.frame = CGRect(x: 0, y: 0, width: area.width, height: area.height)
container.addSubview(blurView)
container.alpha = 0.8
self.view.insertSubview(container, atIndex: 1)
}
Por ejemplo, puede hacer borrosa toda su vista llamando:
addBlurArea(self.view.frame, style: UIBlurEffectStyle.Dark)
Puedes cambiar Dark
a tu estilo de desenfoque deseado y 0.8
al valor alpha deseado
La razón por la que está recibiendo un borroso intenso es que el estilo del efecto de desenfoque afecta el nivel de brillo de la imagen, no la cantidad de desenfoque aplicado.
Desafortunadamente, aunque Apple claramente tiene la capacidad de controlar la cantidad de desenfoque aplicado mediante programación, intente arrastrar lentamente en la plataforma de lanzamiento para ver la transición de difuminado de Spotlight. No veo ninguna API pública para pasar una cantidad de desenfoque a UIBlurEffect
.
Esta publicación afirma que ajustar el color de fondo alfa generará la cantidad de desenfoque. Merece la pena intentarlo, pero no veo dónde está documentado: ¿Cómo se desvanece un UIVisualEffectView y / o UIBlurEffect dentro y fuera?
Sí tu puedes.
Aquí hay un ejemplo de UIImageView con efecto de desenfoque. Recuerde agregar una imagen al UIImageView.
Ajuste la cantidad de desenfoque con blurEffectView.alpha = 0.8 (de 0 a 1)
import UIKit
class BlurEffectImageView: UIImageView {
override func awakeFromNib() {
addBlurEffect()
super.awakeFromNib()
}
private func addBlurEffect(){
let blurEffect = UIBlurEffect(style: .light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.alpha = 0.8
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
blurEffectView.translatesAutoresizingMaskIntoConstraints = false
addSubview(blurEffectView)
NSLayoutConstraint(item: blurEffectView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: blurEffectView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: blurEffectView, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: blurEffectView, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1.0, constant: 0).isActive = true
}
}