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

如何通过代码为带圆形子视图的UIView创建青蓝色遮罩?

实现青蓝色遮罩的两种实用方案

嘿,我来帮你搞定这个青蓝色遮罩的需求!根据你的描述,你需要在带红色边框的主UIView上,给非圆形区域加上青蓝色遮罩,只透出渐变圆形的部分对吧?下面给你两种直接能用的实现方法~

方案一:用CAShapeLayer做遮罩层(最灵活)

核心思路是:先创建一个铺满主视图的青蓝色视图,然后给它加一个「挖空圆形区域」的遮罩,这样青蓝色就只会显示在圆形以外的地方。

Swift 代码示例

// 假设你的主视图叫 containerView,circleViews 是包含5个圆形子视图的数组
// 1. 创建青蓝色遮罩视图
let maskOverlay = UIView(frame: containerView.bounds)
maskOverlay.backgroundColor = UIColor(red: 0/255, green: 180/255, blue: 216/255, alpha: 0.7) // 可调整颜色和透明度
maskOverlay.tag = 100 // 方便后续更新时快速定位
containerView.addSubview(maskOverlay)
maskOverlay.autoresizingMask = [.flexibleWidth, .flexibleHeight] // 适配主视图大小变化

// 2. 创建遮罩路径(实现挖空圆形的效果)
let maskLayer = CAShapeLayer()
maskLayer.frame = maskOverlay.bounds
maskLayer.fillRule = .evenOdd // 关键规则:偶数次覆盖的区域会透明,奇数次保留

// 先添加整个主视图的矩形路径
let fullRectPath = UIBezierPath(rect: maskOverlay.bounds)
maskLayer.path = fullRectPath.cgPath

// 逐个添加圆形路径(用来挖空)
for circleView in circleViews {
    // 把圆形的坐标转换到遮罩视图的坐标系
    let circleFrameInOverlay = containerView.convert(circleView.frame, to: maskOverlay)
    let circlePath = UIBezierPath(ovalIn: circleFrameInOverlay)
    maskLayer.path = maskLayer.path?.copy(byAppending: circlePath.cgPath)
}

// 3. 给遮罩视图应用遮罩
maskOverlay.layer.mask = maskLayer

Objective-C 代码示例

// 假设 containerView 和 circleViews 已初始化完成
// 1. 创建青蓝色遮罩视图
UIView *maskOverlay = [[UIView alloc] initWithFrame:containerView.bounds];
maskOverlay.backgroundColor = [UIColor colorWithRed:0/255.0 green:180/255.0 blue:216/255.0 alpha:0.7];
maskOverlay.tag = 100;
[containerView addSubview:maskOverlay];
maskOverlay.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

// 2. 创建遮罩路径
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = maskOverlay.bounds;
maskLayer.fillRule = kCAFillRuleEvenOdd;

UIBezierPath *fullRectPath = [UIBezierPath bezierPathWithRect:maskOverlay.bounds];
maskLayer.path = fullRectPath.CGPath;

for (UIView *circleView in circleViews) {
    CGRect circleFrameInOverlay = [containerView convertRect:circleView.frame toView:maskOverlay];
    UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:circleFrameInOverlay];
    maskLayer.path = CGPathCreateCopyByAppendingPath(maskLayer.path, circlePath.CGPath);
}

// 3. 应用遮罩
maskOverlay.layer.mask = maskLayer;

方案二:适配AutoLayout的动态更新

如果你的主视图会随着屏幕旋转、布局变化而改变大小,记得在layoutSubviews里更新遮罩路径,保证遮罩始终贴合主视图:

Swift 示例(主视图子类中)

class CustomContainerView: UIView {
    var circleViews: [UIView] = [] // 存储你的圆形子视图
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // 找到之前添加的遮罩视图
        guard let maskOverlay = subviews.first(where: { $0.tag == 100 }),
              let maskLayer = maskOverlay.layer.mask as? CAShapeLayer else {
            return
        }
        
        // 更新遮罩层的frame和路径
        maskLayer.frame = maskOverlay.bounds
        let fullRectPath = UIBezierPath(rect: maskOverlay.bounds)
        maskLayer.path = fullRectPath.cgPath
        
        for circleView in circleViews {
            let circleFrame = convert(circleView.frame, to: maskOverlay)
            let circlePath = UIBezierPath(ovalIn: circleFrame)
            maskLayer.path = maskLayer.path?.copy(byAppending: circlePath.cgPath)
        }
    }
}

关键细节说明

  • fillRule = .evenOdd是核心:我们先画了整个矩形(填充次数1),每个圆形又叠加一次(填充次数2),所以圆形区域因为是偶数次填充会变成透明,刚好透出下面的渐变圆形。
  • 颜色和透明度可以根据需求调整,修改alpha值就能控制遮罩的深浅。
  • 如果需要反过来(青蓝色覆盖圆形,其他区域透明),只需要把fillRule改成.nonZero就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:52:16