【问题标题】:UILabel: background dependent colorUILabel:背景相关颜色
【发布时间】:2013-12-09 19:42:18
【问题描述】:

我试图寻找解决这个问题的方法,但我什至无法用我猜的词正确地表达出来。

基本上,我有一个在操作进行时填充颜色的条。我有一个带有相同颜色的进度百分比的标签具有填充颜色,因此当填充颜色位于背面时,我需要更改它。像这样的:

有没有可能达到这个结果?以防万一,怎么办?

【问题讨论】:

标签: ios objective-c colors uilabel


【解决方案1】:

Morten 回答的 Swift 4 版本:

class ProgressLabel: UIView {

    var progressBarColor = UIColor(red:108.0/255.0, green:200.0/255.0, blue:226.0/255.0, alpha:1.0)
    var textColor = UIColor.white
    var font = UIFont.boldSystemFont(ofSize: 42)


    var progress: Float = 0 {
        didSet {
            progress = Float.minimum(100.0, Float.maximum(progress, 0.0))
            self.setNeedsDisplay()
        }
    }

    override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()!

        // Set up environment.
        let size = self.bounds.size

        // Prepare progress as a string.
        let progressMessage = NSString(format:"%d %%", Int(progress))
        var attributes: [NSAttributedStringKey:Any] = [ NSAttributedStringKey.font : font ]
        let textSize = progressMessage.size(withAttributes: attributes)
        let progressX = ceil(CGFloat(progress) / 100 * size.width)
        let textPoint = CGPoint(x: ceil((size.width - textSize.width) / 2.0), y: ceil((size.height - textSize.height) / 2.0))

        // Draw background + foreground text
        progressBarColor.setFill()
        context.fill(self.bounds)
        attributes[NSAttributedStringKey.foregroundColor] = textColor
        progressMessage.draw(at: textPoint, withAttributes: attributes)

        // Clip the drawing that follows to the remaining progress' frame.
        context.saveGState()
        let remainingProgressRect = CGRect(x: progressX, y: 0.0, width: size.width - progressX, height: size.height)
        context.addRect(remainingProgressRect)
        context.clip()

        // Draw again with inverted colors.
        textColor.setFill()
        context.fill(self.bounds)
        attributes[NSAttributedStringKey.foregroundColor] = progressBarColor
        progressMessage.draw(at: textPoint, withAttributes: attributes)

        context.restoreGState()
    }
}

【讨论】:

    【解决方案2】:

    最好和最干净的方法是使用口罩。 进度条的视图层次结构应如下所示:

    • 基地
      • Subview at index #1查看进度
      • Subview at index #2 UILabel 文字颜色与底色相同
      • Subview at index #3 UILabel 文本颜色与显示进度的视图相同

    我们将为#3 应用掩码。一旦显示进度的视图到达#3 的框架,我们就开始应用遮罩。面具的框架必须跟随进度。当#3 逐渐被遮盖时,下面的标签就会显露出来,您可以轻松实现效果。 Here you are how to create masks with CALayers.

    【讨论】:

    • 我还认为面具在这种情况下会派上用场,但不知道如何准确地使用它们。我也会考虑这个解决方案,谢谢!您能同时解释一下为什么这应该是最好和最干净的吗?因为@Morten 推荐的那个看起来也很酷
    • 这个更简单,需要更少的代码,最重要的是——CALayers 是手工制作的。想象一下,当您将进度从 0.1 设置为 0.5 时,没有使用 Morten 解决方案的动画,它看起来相当糟糕。在这种情况下,CALayer(蒙版)的动画效果很好,您可以获得更好的用户体验。
    • @NicolaMiotto 如果您使用这种方法,请考虑接受我的回答。
    • 是的,我稍后会尝试所有方法并在完成后立即提供答案
    【解决方案3】:

    最简单的方法是创建一个具有progress 属性的UIView 子类并覆盖-drawRect:

    您需要的所有代码都是这样的:

    - (void)drawRect:(CGRect)rect {
    
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        // Set up environment.
        CGSize size = [self bounds].size;
        UIColor *backgroundColor = [UIColor colorWithRed:108.0/255.0 green:200.0/255.0 blue:226.0/255.0 alpha:1.0];
        UIColor *foregroundColor = [UIColor whiteColor];
        UIFont *font = [UIFont boldSystemFontOfSize:42.0];
    
        // Prepare progress as a string.
        NSString *progress = [NSString stringWithFormat:@"%d%%", (int)round([self progress] * 100)];
        NSMutableDictionary *attributes = [@{ NSFontAttributeName : font } mutableCopy];
        CGSize textSize = [progress sizeWithAttributes:attributes];
        CGFloat progressX = ceil([self progress] * size.width);
        CGPoint textPoint = CGPointMake(ceil((size.width - textSize.width) / 2.0), ceil((size.height - textSize.height) / 2.0));
    
        // Draw background + foreground text
        [backgroundColor setFill];
        CGContextFillRect(context, [self bounds]);
        attributes[NSForegroundColorAttributeName] = foregroundColor;
        [progress drawAtPoint:textPoint withAttributes:attributes];
    
        // Clip the drawing that follows to the remaining progress' frame.
        CGContextSaveGState(context);
        CGRect remainingProgressRect = CGRectMake(progressX, 0.0, size.width - progressX, size.height);
        CGContextAddRect(context, remainingProgressRect);
        CGContextClip(context);
    
        // Draw again with inverted colors.
        [foregroundColor setFill];
        CGContextFillRect(context, [self bounds]);
        attributes[NSForegroundColorAttributeName] = backgroundColor;
        [progress drawAtPoint:textPoint withAttributes:attributes];
    
        CGContextRestoreGState(context);
    }
    
    - (void)setProgress:(CGFloat)progress {
        _progress = fminf(1.0, fmaxf(progress, 0.0));
        [self setNeedsDisplay];
    }
    

    您可以根据需要使用背景颜色、文本颜色、字体等属性扩展该类。

    【讨论】:

    • 哇,这个解决方案看起来像是利用核心图形的最佳解决方案,没有 UIViews 的技巧。等我下班我也去试试,谢谢!
    【解决方案4】:

    两个 UIView。

    1. 我们称一个为背景,另一个为进度条。 progressBar 堆叠在背景之上,在它们共同的 superview 上具有相同的来源。

    2. 它们都有一个 UILabel 作为子视图,并且两个标签相对于它们的父级位于相同的原点。背景具有深色背景颜色,其标签具有浅色文本颜色,而进度视图则相反。

    3. progressBar 的帧宽度比背景窄,并且具有 clipsToBounds==YES

    诀窍是,视图的来源相同,标签的来源相同,顶视图上有 clipsToBounds,一切都会看起来正确。

    将这两个视图拖放到一个新的 UIView 子类中,称为 RealCoolProgressView,并为其提供一个公共方法:

    -(void)setProgress:(float)progress 
    

    进度是一个从 0.0 到 1.0 的数字。该方法缩放progressBar宽度并设置两个标签的文本@“Progress %f”,progress*100

    【讨论】:

    • 看起来是一个合法的解决方案,我稍后会试一试,谢谢!
    • @NicolaMiotto ok bro.. 试试吧,你会从我的回答中得到解决方案而不是接受它
    • 请不要复制粘贴other people's answers
    【解决方案5】:

    为了在不覆盖 drawRect: 的情况下更轻松,您可以创建 2 个 UIView 来解决这个问题。

    蓝色背景 UIView (A) 包含白色 UILabel。 (剪辑子视图开启)

    白色背景 UIView (B) 包含蓝色 UILabel。

    A 将覆盖在 B 上。

    注意:2 个 UILabel 将具有相同的大小、相同的字体和相同的位置。

    通过调整 UIView A 的宽度,您可以让进程栏按您的意愿工作。

    【讨论】:

      【解决方案6】:

      只是“伪造”您想要的效果的想法。 您可以使用一个背景标签(白色和蓝色文本)创建一个 UIView 的子类,并在它前面创建一个具有蓝色背景色和白色文本的子视图。 您可以在背景标签上从 0 到 100% 的前标签宽度之后进行动画处理。您可能需要检查是否需要在子视图中放置标签以避免文本在增加宽度时发生位移。

      【讨论】:

        猜你喜欢
        • 2023-03-03
        • 1970-01-01
        • 2011-04-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多