You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift中UIView遮罩效果不符预期,如何实现目标遮罩?

如何用两个UIView实现目标遮罩效果?

背景

我尝试用以下代码通过两个UIView创建遮罩,遮罩功能已生效,但效果不符合预期。我想要实现图片中A所示的遮罩效果,实际得到的却是B的效果。

问题

如何通过两个UIView实现图片A那样的遮罩效果?

现有代码

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let redView = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
        redView.backgroundColor = .red
        view.addSubview(redView)
        
        let maskView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
        maskView.backgroundColor = .blue
        maskView.layer.cornerRadius = 100
        redView.mask = maskView
        
    }

}

效果对比图

效果对比图


解决方案

要实现图片A的遮罩效果,核心是利用UIView作为mask时,不透明区域显示被遮罩视图,透明区域隐藏的特性。你当前的代码是让maskView本身为圆形不透明,所以redView只显示圆形部分;而要实现中间圆形显示、周围被遮罩的效果,需要让maskView的中间区域透明,周围不透明。

方法一:通过图层混合模式实现

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let redView = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
        redView.backgroundColor = .red
        view.addSubview(redView)
        
        // 创建遮罩容器视图,尺寸与redView一致
        let maskContainer = UIView(frame: redView.bounds)
        // 容器背景设为不透明(颜色不影响,只要不透明即可)
        maskContainer.backgroundColor = .black
        
        // 创建中间圆形视图,作为要显示的透明区域
        let circleView = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
        circleView.layer.cornerRadius = 50
        circleView.backgroundColor = .clear
        maskContainer.addSubview(circleView)
        
        // 关键:用混合模式将圆形区域从容器中挖去
        circleView.layer.compositingFilter = "destinationOut"
        
        // 设置遮罩
        redView.mask = maskContainer
    }
}

方法二:通过CAShapeLayer组合路径实现

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let redView = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
        redView.backgroundColor = .red
        view.addSubview(redView)
        
        // 创建外层遮罩视图,尺寸与redView一致
        let outerMask = UIView(frame: redView.bounds)
        outerMask.backgroundColor = .black
        
        // 创建中间圆形区域的路径
        let maskLayer = CAShapeLayer()
        // 先绘制全屏矩形路径
        let fullPath = UIBezierPath(rect: outerMask.bounds)
        // 再绘制中间圆形路径,并从矩形中减去
        let circlePath = UIBezierPath(ovalIn: CGRect(x: 50, y: 50, width: 100, height: 100))
        fullPath.append(circlePath)
        fullPath.usesEvenOddFillRule = true
        maskLayer.path = fullPath.cgPath
        maskLayer.fillRule = .evenOdd
        
        // 将组合路径设为外层视图的遮罩
        outerMask.layer.mask = maskLayer
        // 设置redView的遮罩
        redView.mask = outerMask
    }
}

两种方法都能实现图片A的效果:redView仅中间圆形区域显示,周围被遮罩隐藏。


内容的提问来源于stack exchange,提问作者user4806509

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 16:22:47