蒙版 UIVisualEffectView 在 iOS 10 上不起作用 [英] Masked UIVisualEffectView does not work on iOS 10

查看:76
本文介绍了蒙版 UIVisualEffectView 在 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆