蒙版 UIVisualEffectView 在 iOS 10 上不起作用 [英] Masked UIVisualEffectView does not work on iOS 10
问题描述
我创建了一个使用 UIBlurEffectView
的应用程序,它在 iOS 9 及更低版本上运行良好,但是当我升级我的设备(其中一些,而不仅仅是 1 个设备)时,模糊消失了,而是出于某种原因,在模糊中有一个半透明的视图.
这门课有什么变化吗?有谁知道为什么?
我的代码(视图是我使用 PocketSVG API 获得的 SVG 文件中的一个形状):
让模糊: UIBlurEffect = UIBlurEffect(style: .Light)让 ev: UIVisualEffectView = UIVisualEffectView(effect: blur)ev.translatesAutoresizingMaskIntoConstraints = falseself.addSubview(ev)ev.rightAnchor.constraintEqualToAnchor(self.rightAnchor).active = trueev.bottomAnchor.constraintEqualToAnchor(self.bottomAnchor).active = trueev.leftAnchor.constraintEqualToAnchor(self.leftAnchor).active = trueev.heightAnchor.constraintEqualToAnchor(self.heightAnchor, multiplier: 1.5).active = true让我的路径:CGPathRef = PocketSVG.pathFromSVGFileNamed("CategoriesBar").takeUnretainedValue()var 变换:CGAffineTransform = CGAffineTransformMakeScale(self.frame.size.width/754.0, self.frame.size.height/220.0)让transformedPath:CGPathRef = CGPathCreateMutableCopyByTransformingPath(myPath, &transform)!让 myShapeLayer = CAShapeLayer()myShapeLayer.path = 变换路径self.layer.mask = myShapeLayer
Leo Natan 的回答代码:
你的建议不起作用,这是代码
覆盖 func layoutSubviews() {让模糊:UIBlurEffect = UIBlurEffect(style: .Light)让 ev: UIVisualEffectView = UIVisualEffectView(effect: blur)ev.translatesAutoresizingMaskIntoConstraints = falseself.addSubview(ev)ev.rightAnchor.constraintEqualToAnchor(self.rightAnchor).active = trueev.bottomAnchor.constraintEqualToAnchor(self.bottomAnchor).active = trueev.leftAnchor.constraintEqualToAnchor(self.leftAnchor).active = trueev.heightAnchor.constraintEqualToAnchor(self.heightAnchor, multiplier: 1.5).active = true让我的路径:CGPathRef = PocketSVG.pathFromSVGFileNamed("CategoriesBar").takeUnretainedValue()var 变换:CGAffineTransform = CGAffineTransformMakeScale(self.frame.size.width/754.0, self.frame.size.height/220.0)让transformedPath:CGPathRef = CGPathCreateMutableCopyByTransformingPath(myPath, &transform)!让 myShapeLayer = CAShapeLayer()myShapeLayer.path = 变换路径self.layer.mask = myShapeLayer让 myMaskedView = UIView(frame: ev.frame)myMaskedView.layer.mask = myShapeLayerev.maskView = myMaskedView}
Konrad Siemczyk 答案代码
override func layoutSubviews() {让模糊:UIBlurEffect = UIBlurEffect(style: .Light)让 ev: UIVisualEffectView = UIVisualEffectView(effect: blur)ev.frame = self.boundsev.translatesAutoresizingMaskIntoConstraints = falseself.addSubview(ev)ev.rightAnchor.constraintEqualToAnchor(self.rightAnchor).active = trueev.bottomAnchor.constraintEqualToAnchor(self.bottomAnchor).active = trueev.leftAnchor.constraintEqualToAnchor(self.leftAnchor).active = trueev.heightAnchor.constraintEqualToAnchor(self.heightAnchor, multiplier: 1.5).active = true让我的路径:CGPathRef = PocketSVG.pathFromSVGFileNamed("CategoriesBar").takeUnretainedValue()var 变换:CGAffineTransform = CGAffineTransformMakeScale(self.frame.size.width/754.0, self.frame.size.height/220.0)让transformedPath:CGPathRef = CGPathCreateMutableCopyByTransformingPath(myPath, &transform)!让 myShapeLayer = CAShapeLayer()myShapeLayer.path = 变换路径//self.layer.mask = myShapeLayermyShapeLayer.fillRule = kCAFillRuleEvenOdd让 myMaskedView = UIView(frame: self.frame)myMaskedView.backgroundColor = UIColor.blackColor()myMaskedView.layer.mask = myShapeLayerev.maskView = myMaskedView}
嘿,在实施这个之前......
TLDR:请先检查此解决方案:
游乐场版本
视图控制器版本
I have an app I created that uses UIBlurEffectView
that worked perfect on iOS 9 and under, but when I upgraded my device (a few of them, not just 1 device) the blur disappeared and instead of the blur there is a half-transperant view for some reason.
Does anything changed in this class? Anyone knows why?
My code (The view is a shape from SVG file that I'm getting using PocketSVG API):
let blur: UIBlurEffect = UIBlurEffect(style: .Light)
let ev: UIVisualEffectView = UIVisualEffectView(effect: blur)
ev.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(ev)
ev.rightAnchor.constraintEqualToAnchor(self.rightAnchor).active = true
ev.bottomAnchor.constraintEqualToAnchor(self.bottomAnchor).active = true
ev.leftAnchor.constraintEqualToAnchor(self.leftAnchor).active = true
ev.heightAnchor.constraintEqualToAnchor(self.heightAnchor, multiplier: 1.5).active = true
let myPath: CGPathRef = PocketSVG.pathFromSVGFileNamed("CategoriesBar").takeUnretainedValue()
var transform: CGAffineTransform = CGAffineTransformMakeScale(self.frame.size.width / 754.0, self.frame.size.height / 220.0)
let transformedPath: CGPathRef = CGPathCreateMutableCopyByTransformingPath(myPath, &transform)!
let myShapeLayer = CAShapeLayer()
myShapeLayer.path = transformedPath
self.layer.mask = myShapeLayer
Leo Natan's answer code:
What you've suggested doesn't work, here is the code
override func layoutSubviews() {
let blur: UIBlurEffect = UIBlurEffect(style: .Light)
let ev: UIVisualEffectView = UIVisualEffectView(effect: blur)
ev.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(ev)
ev.rightAnchor.constraintEqualToAnchor(self.rightAnchor).active = true
ev.bottomAnchor.constraintEqualToAnchor(self.bottomAnchor).active = true
ev.leftAnchor.constraintEqualToAnchor(self.leftAnchor).active = true
ev.heightAnchor.constraintEqualToAnchor(self.heightAnchor, multiplier: 1.5).active = true
let myPath: CGPathRef = PocketSVG.pathFromSVGFileNamed("CategoriesBar").takeUnretainedValue()
var transform: CGAffineTransform = CGAffineTransformMakeScale(self.frame.size.width / 754.0, self.frame.size.height / 220.0)
let transformedPath: CGPathRef = CGPathCreateMutableCopyByTransformingPath(myPath, &transform)!
let myShapeLayer = CAShapeLayer()
myShapeLayer.path = transformedPath
self.layer.mask = myShapeLayer
let myMaskedView = UIView(frame: ev.frame)
myMaskedView.layer.mask = myShapeLayer
ev.maskView = myMaskedView
}
Konrad Siemczyk answer code
override func layoutSubviews() {
let blur: UIBlurEffect = UIBlurEffect(style: .Light)
let ev: UIVisualEffectView = UIVisualEffectView(effect: blur)
ev.frame = self.bounds
ev.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(ev)
ev.rightAnchor.constraintEqualToAnchor(self.rightAnchor).active = true
ev.bottomAnchor.constraintEqualToAnchor(self.bottomAnchor).active = true
ev.leftAnchor.constraintEqualToAnchor(self.leftAnchor).active = true
ev.heightAnchor.constraintEqualToAnchor(self.heightAnchor, multiplier: 1.5).active = true
let myPath: CGPathRef = PocketSVG.pathFromSVGFileNamed("CategoriesBar").takeUnretainedValue()
var transform: CGAffineTransform = CGAffineTransformMakeScale(self.frame.size.width / 754.0, self.frame.size.height / 220.0)
let transformedPath: CGPathRef = CGPathCreateMutableCopyByTransformingPath(myPath, &transform)!
let myShapeLayer = CAShapeLayer()
myShapeLayer.path = transformedPath
//self.layer.mask = myShapeLayer
myShapeLayer.fillRule = kCAFillRuleEvenOdd
let myMaskedView = UIView(frame: self.frame)
myMaskedView.backgroundColor = UIColor.blackColor()
myMaskedView.layer.mask = myShapeLayer
ev.maskView = myMaskedView
}
Hey, before implementing this one...
TLDR: Please check this solution first:
https://stackoverflow.com/a/67939549/2829540
... even though these examples work on older versions of iOS, looks like newer ones require a layer instead of a view, this answer might not work as expected. You might need to implement this solution for older versions and the linked one for newer ones.
For ObjectiveC users out there.
Here is a working example for iOS 10. I also attached the resulting view at the end. I am adding the white border on top later. The cropped circle masking is in the code, if you like it use it as is.
// "self" in here is an UIView that contains some images inside.
{
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *blurredEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
CGRect frame = self.frame;
frame.origin = CGPointMake (0, 0);
blurredEffectView.frame = frame;
[self addSubview:blurredEffectView];
UIView *maskView = [[UIView alloc] initWithFrame:frame];
maskView.backgroundColor = [UIColor blackColor];
__weak UIView *weak = self;
maskView.layer.mask = ({ // This mask draws a rectangle and crops a circle inside it.
__strong UIView *strong = weak;
CGRect roundedRect = CGRectMake (
0,
0,
strong.frame.size.width * 0.8f,
strong.frame.size.width * 0.8f
);
roundedRect.origin.x = strong.frame.size.width / 2 - roundedRect.size.width / 2;
roundedRect.origin.y = strong.frame.size.height / 2 - roundedRect.size.height / 2;
CGFloat cornerRadius = roundedRect.size.height / 2.0f;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.bounds];
UIBezierPath *croppedPath = [UIBezierPath bezierPathWithRoundedRect:roundedRect cornerRadius:cornerRadius];
[path appendPath:croppedPath];
[path setUsesEvenOddFillRule:YES];
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = path.CGPath;
mask.fillRule = kCAFillRuleEvenOdd;
mask;
});
blurredEffectView.maskView = maskView;
}
So, this is same code as Swift 3 for testing in playground.
This is using a try while downloading the url, so it is synchronous
import UIKit
import PlaygroundSupport
let generalFrame = CGRect(x: 0, y: 0, width: 500, height: 500)
let containerView = UIView(frame: generalFrame)
containerView.backgroundColor = UIColor.black;
PlaygroundPage.current.liveView = containerView
let parentView = UIView(frame: generalFrame)
containerView.addSubview(parentView)
let url = URL(string: "https://static.pexels.com/photos/168066/pexels-photo-168066-large.jpeg")
let data = try Data(contentsOf: url!);
let imageView = UIImageView(frame:parentView.bounds)
imageView.image = UIImage(data: data)
imageView.contentMode = .scaleAspectFill
let maskView = UIView(frame:parentView.bounds)
maskView.backgroundColor = UIColor.black
maskView.layer.mask = {() -> CALayer in
var roundedRect = CGRect (
x: 0.0,
y: 0.0,
width: parentView.bounds.size.width * 0.5,
height: parentView.bounds.size.width * 0.5
);
roundedRect.origin.x = parentView.frame.size.width / 2 - roundedRect.size.width / 2;
roundedRect.origin.y = parentView.frame.size.height / 2 - roundedRect.size.height / 2;
let cornerRadius = roundedRect.size.height / 2.0;
let path = UIBezierPath(rect:parentView.bounds)
let croppedPath = UIBezierPath(roundedRect: roundedRect, cornerRadius: cornerRadius)
path.append(croppedPath)
path.usesEvenOddFillRule = true
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath;
maskLayer.fillRule = kCAFillRuleEvenOdd
return maskLayer
}()
let blurView = UIBlurEffect(style: .light)
let effectView = UIVisualEffectView(effect: blurView)
effectView.frame = generalFrame
effectView.mask = maskView
parentView.addSubview(imageView)
parentView.addSubview(effectView)
And working example in a view controller:
This one downloads an image first then appends the blur effect.
import UIKit
class ViewController: UIViewController {
func addTheBlurView(data :Data) {
let generalFrame = self.view.bounds;
let parentView = UIView(frame: generalFrame)
self.view.addSubview(parentView)
let imageView = UIImageView(frame: parentView.bounds)
imageView.image = UIImage(data: data)
imageView.contentMode = .scaleAspectFill
let maskView = UIView(frame: parentView.bounds)
maskView.backgroundColor = UIColor.black
maskView.layer.mask = {
() -> CALayer in
var roundedRect = CGRect(
x: 0.0,
y: 0.0,
width: parentView.bounds.size.width * 0.5,
height: parentView.bounds.size.width * 0.5
);
roundedRect.origin.x = parentView.frame.size.width / 2 - roundedRect.size.width / 2;
roundedRect.origin.y = parentView.frame.size.height / 2 - roundedRect.size.height / 2;
let cornerRadius = roundedRect.size.height / 2.0;
let path = UIBezierPath(rect: parentView.bounds)
let croppedPath = UIBezierPath(roundedRect: roundedRect, cornerRadius: cornerRadius)
path.append(croppedPath)
path.usesEvenOddFillRule = true
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath;
maskLayer.fillRule = kCAFillRuleEvenOdd
return maskLayer
}()
let blurView = UIBlurEffect(style: .light)
let effectView = UIVisualEffectView(effect: blurView)
effectView.frame = generalFrame
effectView.mask = maskView
parentView.addSubview(imageView)
parentView.addSubview(effectView)
}
override func viewDidLoad() {
debugPrint("Running...")
super.viewDidLayoutSubviews();
// Lets load an image first, so blur looks cool
let url = URL(string: "https://static.pexels.com/photos/168066/pexels-photo-168066-large.jpeg")
URLSession.shared.dataTask(with: url!) {
(data, response, error) in
if error != nil {
print(error)
return
}
DispatchQueue.main.async(execute: {
self.addTheBlurView(data: data!)
})
}.resume()
}
}
OBJECTIVEC VERSION
PLAYGROUND VERSION
VIEWCONTROLLER VERSION
这篇关于蒙版 UIVisualEffectView 在 iOS 10 上不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!