在新iOS的音乐应用程序中,我们可以看到一个模糊的视图后面有一个专辑封面。
这样的事情是如何完成的呢?我看了文件,但什么都没发现。
在新iOS的音乐应用程序中,我们可以看到一个模糊的视图后面有一个专辑封面。
这样的事情是如何完成的呢?我看了文件,但什么都没发现。
当前回答
你可以使用UIVisualEffectView来实现这个效果。这是一个本地API,经过了性能和电池寿命的微调,而且很容易实现。
迅速:
//only apply the blur if the user hasn't disabled transparency effects
if !UIAccessibility.isReduceTransparencyEnabled {
view.backgroundColor = .clear
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
//always fill the view
blurEffectView.frame = self.view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(blurEffectView) //if you have more UIViews, use an insertSubview API to place it where needed
} else {
view.backgroundColor = .black
}
objective - c:
//only apply the blur if the user hasn't disabled transparency effects
if (!UIAccessibilityIsReduceTransparencyEnabled()) {
self.view.backgroundColor = [UIColor clearColor];
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
//always fill the view
blurEffectView.frame = self.view.bounds;
blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:blurEffectView]; //if you have more UIViews, use an insertSubview API to place it where needed
} else {
self.view.backgroundColor = [UIColor blackColor];
}
如果你以模态方式呈现这个视图控制器来模糊底层内容,你需要将模态呈现风格设置为Over Current Context,并将背景颜色设置为clear,以确保底层视图控制器在顶部呈现时仍然可见。
其他回答
下面是一个简单的方法来添加自定义模糊,而不用与私有api讨价还价使用UIViewPropertyAnimator:
首先,声明class属性:
var blurAnimator: UIViewPropertyAnimator!
然后在viewDidLoad()中设置你的模糊视图:
let blurEffectView = UIVisualEffectView()
blurEffectView.backgroundColor = .clear
blurEffectView.frame = view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(blurEffectView)
blurAnimator = UIViewPropertyAnimator(duration: 1, curve: .linear) { [blurEffectView] in
blurEffectView.effect = UIBlurEffect(style: .light)
}
blurAnimator.fractionComplete = 0.15 // set the blur intensity.
注意:此解决方案不适用于UICollectionView/UITableView单元格
这个答案是基于Mitja Semolic之前出色的回答。我已经将它转换为swift 3,添加了一个解释,在评论中发生了什么,使它成为一个UIViewController的扩展,这样任何VC都可以随意调用它,添加了一个未模糊的视图来显示选择性应用,并添加了一个完成块,以便调用视图控制器可以在完成模糊时做任何它想做的事情。
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
}
}
我已经确认它适用于iOS 10.3.1和iOS 11
2019代码
下面是一个使用@AdamBardon技巧的更完整的例子。
@IBDesignable class ButtonOrSomethingWithBlur: UIButton {
var ba: UIViewPropertyAnimator?
private lazy var blurry: BlurryBall = { return BlurryBall() }()
override func didMoveToSuperview() {
super.didMoveToSuperview()
// Setup the blurry ball. BE SURE TO TEARDOWN.
// Use superb trick to access the internal guassian level of Apple's
// standard gpu blurrer per stackoverflow.com/a/55378168/294884
superview?.insertSubview(blurry, belowSubview: self)
ba = UIViewPropertyAnimator(duration:1, curve:.linear) {[weak self] in
// note, those duration/curve values are simply unusued
self?.blurry.effect = UIBlurEffect(style: .extraLight)
}
ba?.fractionComplete = live.largeplaybutton_blurfactor
}
override func willMove(toSuperview newSuperview: UIView?) {
// Teardown for the blurry ball - critical
if newSuperview == nil { print("safe teardown")
ba?.stopAnimation(true)
ba?.finishAnimation(at: .current)
}
}
override func layoutSubviews() { super.layoutSubviews()
blurry.frame = bounds, your drawing frame or whatever
}
{题外话:作为一个通用的iOS工程问题,didMoveToWindow可能比didMoveToSuperview更适合你。其次,您可以使用其他一些方法来执行拆卸操作,但是拆卸操作就是这里显示的两行代码。
bluryball只是一个UIVisualEffectView。注意视觉效果视图的初始值。如果你碰巧需要圆角或者其他东西,在这门课上做吧。
class BlurryBall: UIVisualEffectView {
override init(effect: UIVisualEffect?) { super.init(effect: effect)
commonInit() }
required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder)
commonInit() }
private func commonInit() {
clipsToBounds = true
backgroundColor = .clear
}
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = bounds.width / 2
}
}
公认的答案是正确的,但这里缺少一个重要的步骤,如果这个视图-您想要模糊的背景-是使用
[self presentViewController:vc animated:YES completion:nil]
默认情况下,这将抵消模糊,因为UIKit删除演示者的视图,这实际上是模糊的。为了避免这种删除,将这一行添加到前一行之前
vc。modalPresentationStyle = UIModalPresentationOverFullScreen;
或者使用其他Over样式。
以下是Swift 2.0解决方案的代码,已经在接受的答案中提供:
//only apply the blur if the user hasn't disabled transparency effects
if !UIAccessibilityIsReduceTransparencyEnabled() {
self.view.backgroundColor = UIColor.clearColor()
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.Dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
//always fill the view
blurEffectView.frame = self.view.bounds
blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
self.view.addSubview(blurEffectView) //if you have more UIViews, use an insertSubview API to place it where needed
} else {
self.view.backgroundColor = UIColor.blackColor()
}