【问题标题】:Simply mask a UIView with a rectangle只需用矩形遮罩 UIView
【发布时间】:2012-07-08 14:46:44
【问题描述】:

我想知道如何简单地掩盖任何类型的 UIView 的可见区域。到目前为止,我阅读的所有答案/教程都描述了使用图像、渐变或创建圆角进行遮罩,这比我所追求的要先进得多。

示例:我有一个边界为 (0, 0, 100, 100) 的 UIView,我想使用遮罩切除视图的右半部分。因此,我的蒙版框架将是 (0, 0, 50, 100)。

知道如何简单地做到这一点吗?我不想重写 drawrect 方法,因为这应该适用于任何 UIView。

我已经尝试过了,但它只会使整个视图不可见。

CGRect mask = CGRectMake(0, 0, 50, 100);
UIView *maskView = [[UIView alloc] initWithFrame:mask];
viewToMask.layer.mask = maskView.layer;

【问题讨论】:

  • 我不确定我是否理解,但你为什么不把你的视图框架改成蒙版呢?例如 viewToMask.frame = 掩码; (或者如果你想展示的话,反之亦然。)
  • 这是行不通的,因为视图可能有应该被切断的可拉伸图像,或者即使被屏蔽也应该仍然可用的控件。更改框架会更改图像拉伸或使控件无法使用。
  • 检查这是否有帮助 stackoverflow.com/questions/7241966/…
  • 它有帮助:) 添加我作为答案的方式。
  • 或者这个,逐个查看屏蔽stackoverflow.com/questions/6805444/masking-a-uiview

标签: ios uiview mask


【解决方案1】:

一个可选层,其 alpha 通道 用作掩码以进行选择 图层背景与合成结果之间 图层的内容及其过滤背景。

@property(retain) CALayer *mask

正确的方法是创建与viewToMask 相同帧(0、0、100、100)的maskView 要屏蔽哪个图层。然后,您需要为要使其不可见的路径设置 clearColor(这将阻止路径上的视图交互,因此请注意视图层次结构)。

【讨论】:

  • 感谢您的回答!我想我找到了一种不使用 alpha 的更简单的方法,所以我添加了自己的答案。
  • @Accatyyc 不错的解决方案,我通过将maskLayermaskRect 重命名为homeTeamMaskLayerhomeTeamMaskRect 对其进行了编辑,以便它编译:) 需要等待它被批准虽然并且感谢更新。
  • 啊,感谢您的编辑建议。我以相反的方式更新了它,所以它对我以外的其他项目有意义:)
【解决方案2】:

感谢 MSK 提供的链接,这是我采用的方法,效果很好:

// Create a mask layer and the frame to determine what will be visible in the view.
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
CGRect maskRect = CGRectMake(0, 0, 50, 100);

// Create a path with the rectangle in it.
CGPathRef path = CGPathCreateWithRect(maskRect, NULL);

// Set the path to the mask layer.
maskLayer.path = path;

// Release the path since it's not covered by ARC.
CGPathRelease(path);

// Set the mask of the view.
viewToMask.layer.mask = maskLayer;

【讨论】:

  • 感谢您花时间写下您自己的答案!它使学习过程变得更加简单。现在我们也是声望好友了! :)
  • 非常有用,我不知道你可以用路径制作图层,这正是我想要的。谢谢!
  • 非常感谢。达维拉说的。同样在这里-非常感谢您编写此示例。工作出色。 (我用它在集合视图上创建了一个动画蒙版,这样我就可以拉起集合视图并让它在另一个视图之上展开,这样它就可以接管全屏——最终结果非常漂亮:-) )
  • 非常感谢!我被过滤器问题困扰了好几天,我试图屏蔽 UIImage,但屏蔽 UIView 是一个更好的解决方案!我希望你能通过堆栈溢出发送啤酒!
  • 我整天都在找这个。爱你。
【解决方案3】:

根本不需要任何面具。 只需将其放入具有较小框架的包装视图,然后设置clipsToBounds

wrapper.clipsToBounds = true

【讨论】:

  • 如果你想剪切一个控件,它实际上不起作用,因为它不会响应其父框架之外的触摸。此外,这基本上与设置蒙版的作用相同,只是现在您需要考虑一个相对框架。
  • 我认为它的性能更高,因为这可能只在引擎盖下调整纹理坐标,但应用蒙版可能会进行 alpha 混合。
  • 您始终可以覆盖 -pointInside: 以获取框架外的响应。不过,这可能真的是一笔开销。
  • 更简单的方法!谢谢。
【解决方案4】:

设置MaskToBounds 是不够的,例如,在UIImageView 位于RelativeLayout 内部的情况下。如果您将UIImageView 放在布局的顶部边缘附近,然后旋转您的UIImageView,它将超过布局并且不会被裁剪。如果您将该标志设置为 true,它将被裁剪是,但如果 UIImageView 位于布局的中心,它也会被裁剪,这不是您想要的。

因此,确定maskRect 是正确的方法。

【讨论】:

    【解决方案5】:

    Swift ViewController 中非常简单的示例,基于公认的答案:

    import UIKit
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let redView = UIView(frame: view.bounds)
            view.addSubview(redView)
    
            view.backgroundColor = UIColor.green
            redView.backgroundColor = UIColor.red
    
            mask(redView, maskRect: CGRect(x: 50, y: 50, width: 50, height: 50))
        }
    
        func mask(_ viewToMask: UIView, maskRect: CGRect) {
            let maskLayer = CAShapeLayer()
            let path = CGPath(rect: maskRect, transform: nil)
            maskLayer.path = path
    
            // Set the mask of the view.
            viewToMask.layer.mask = maskLayer
        }
    }
    

    输出

    【讨论】:

      【解决方案6】:

      谢谢大家的回答。

      如果有人在这个问题上找不到合适的答案,就像我刚刚做的那样,我已经在 Swift 2.2 中为masking/clipping UIViewCGRect 组装了一个工作要点/UIBezierPath

      https://gist.github.com/Flar49/7e977e81f1d2827f5fcd5c6c6a3c3d94

      extension UIView {
      
          func mask(withRect rect: CGRect, inverse: Bool = false) {
              let path = UIBezierPath(rect: rect)
              let maskLayer = CAShapeLayer()
      
              if inverse {
                  path.append(UIBezierPath(rect: self.bounds))
                  maskLayer.fillRule = kCAFillRuleEvenOdd
              }
      
              maskLayer.path = path.cgPath
      
              self.layer.mask = maskLayer
          }
      
          func mask(withPath path: UIBezierPath, inverse: Bool = false) {
              let path = path
              let maskLayer = CAShapeLayer()
      
              if inverse {
                  path.append(UIBezierPath(rect: self.bounds))
                  maskLayer.fillRule = kCAFillRuleEvenOdd
              }
      
              maskLayer.path = path.cgPath
      
              self.layer.mask = maskLayer
          }
      }
      

      用法:

      let viewSize = targetView.bounds.size
      let rect = CGRect(x: 20, y: 20, width: viewSize.width - 20*2, height: viewSize.height - 20*2)
      
      // Cuts rectangle inside view, leaving 20pt borders around
      targetView.mask(withRect: rect, inverse: true)
      
      // Cuts 20pt borders around the view, keeping part inside rect intact
      targetView.mask(withRect: rect)
      

      希望它会在未来为某人节省一些时间:)

      【讨论】:

      • 经过几个小时的搜索,我找到了你,我的救星。非常感谢! :)
      【解决方案7】:

      Swift 5,感谢@Dan Rosenstark

      class ViewController: UIViewController {
      
          override func viewDidLoad() {
              super.viewDidLoad()
              let red = UIView(frame: view.bounds)
              view.addSubview(red)
              view.backgroundColor = UIColor.cyan
              red.backgroundColor = UIColor.red
              red.mask(CGRect(x: 50, y: 50, width: 50, height: 50))
          }
      }
      
      extension UIView{
          func mask(_ rect: CGRect){
              let mask = CAShapeLayer()
              let path = CGPath(rect: rect, transform: nil)
              mask.path = path
              // Set the mask of the view.
              layer.mask = mask
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-30
        • 1970-01-01
        • 2012-12-10
        • 1970-01-01
        • 2017-02-11
        • 2014-11-17
        相关资源
        最近更新 更多