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

iOS自定义PDProgressView:如何将进度条文字白色改为透明

解决进度条文字镂空(透明显示背景)的问题

嘿,我明白你想要的效果——就是进度条上的文字能"镂空",透过文字看到进度条的背景色对吧?之前直接把文字颜色改成clearColor没用,是因为原来的绘制逻辑根本不是为这种镂空效果设计的,咱们换个思路就能搞定。

方案一:用混合模式快速实现(改动最小)

这个方法利用Core Graphics的混合模式,直接在前景色上"挖"出文字形状,透出下面的背景。修改你的drawRect:方法就行:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGSize size = self.bounds.size;
    
    // 先画整个进度条的背景色
    UIColor *backgroundColor = [UIColor greenColor];
    [backgroundColor setFill];
    CGContextFillRect(context, self.bounds);
    
    // 画已完成进度的前景色
    UIColor *foregroundColor = [UIColor whiteColor];
    [foregroundColor setFill];
    CGRect progressRect = CGRectMake(0, 0, self.progress * size.width, size.height);
    CGContextFillRect(context, progressRect);
    
    // 准备文字内容和样式
    NSString *progressText = [NSString stringWithFormat:@"%d", (int)round(self.progress * 100)];
    UIFont *font = [UIFont boldSystemFontOfSize:42.0];
    NSDictionary *textAttrs = @{
        NSFontAttributeName: font,
        // 这里颜色随便设,混合模式会忽略它,只取文字的形状
        NSForegroundColorAttributeName: [UIColor blackColor]
    };
    CGSize textSize = [progressText sizeWithAttributes:textAttrs];
    CGPoint textPos = CGPointMake(ceil((size.width - textSize.width)/2), ceil((size.height - textSize.height)/2));
    
    // 关键:用kCGBlendModeDestinationOut混合模式画文字,相当于挖空前景色
    CGContextSaveGState(context);
    CGContextSetBlendMode(context, kCGBlendModeDestinationOut);
    [progressText drawAtPoint:textPos withAttributes:textAttrs];
    CGContextRestoreGState(context);
}

方案二:用文字做遮罩(更直观的思路)

如果混合模式有点抽象,你可以用文字作为遮罩,让前景色只填充非文字的区域,这样文字区域就自然透出背景了:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGSize size = self.bounds.size;
    
    // 先画背景色
    UIColor *backgroundColor = [UIColor greenColor];
    [backgroundColor setFill];
    CGContextFillRect(context, self.bounds);
    
    // 准备文字内容
    NSString *progressText = [NSString stringWithFormat:@"%d", (int)round(self.progress * 100)];
    UIFont *font = [UIFont boldSystemFontOfSize:42.0];
    NSDictionary *textAttrs = @{NSFontAttributeName: font};
    CGSize textSize = [progressText sizeWithAttributes:textAttrs];
    CGPoint textPos = CGPointMake(ceil((size.width - textSize.width)/2), ceil((size.height - textSize.height)/2));
    
    // 把文字作为遮罩,后续绘制只会在非文字区域生效
    CGContextSaveGState(context);
    [progressText drawAtPoint:textPos withAttributes:textAttrs];
    CGContextClip(context);
    
    // 绘制进度前景色,此时只有非文字区域会被填充
    UIColor *foregroundColor = [UIColor whiteColor];
    [foregroundColor setFill];
    CGRect progressRect = CGRectMake(0, 0, self.progress * size.width, size.height);
    CGContextFillRect(context, progressRect);
    
    CGContextRestoreGState(context);
}

为啥之前的方法失效了?

你之前把foregroundColor改成clearColor后,第一步画的文字完全透明,等于没画;然后裁剪未完成区域画白色背景+绿色文字,最后整个进度条就变成了绿色背景加未完成部分的白色,自然看不到文字镂空的效果。而上面两种方案都是围绕"让文字区域透出背景"来设计的,完美匹配你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:08:50