我试图为这个问题寻找解决方案,但我甚至无法用正确的语言说出来。
基本上我有一个在操作进行时会充满颜色的条形图。我有一个标签,其进度百分比具有相同颜色的填充颜色,所以我需要在填充颜色在背面时进行更改。像这样:
无论如何都可以实现这个结果吗?万一,怎么样?
答案 0 :(得分:7)
最简单的方法是创建一个UIView
子类,该子类具有progress
属性并覆盖-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];
}
您可以根据需要使用背景颜色,文本颜色,字体等属性扩展类
答案 1 :(得分:3)
两个UIViews。
让我们调用一个背景,另一个调用progressBar。 progressBar堆叠在背景之上,在其共同的超级视图上具有相同的原点。
他们都有一个UILabel作为子视图,两个标签在相同的原点相对于它们的父。 background有一个黑暗的backgroundColor,它的标签有light textColor,进度视图则反过来。
progressBar的帧宽比背景窄,并且有clipsToBounds == YES
诀窍是,视图的起源相同,标签的起源相同,而顶视图上的clipsToBounds,一切看起来都是正确的。
将这两个视图放入一个名为ReallyCoolProgressView的新UIView子类中,并为其提供一个公共方法:
-(void)setProgress:(float)progress
进度是一个从0.0到1.0的数字。该方法缩放progressBar宽度并设置标签的文本@“Progress%f”,progress * 100
答案 2 :(得分:2)
只是想一想“假装”你想要的效果。 您可以使用一个背景标签(白色和蓝色文本)创建UIView的子类,并在其前面创建带有蓝色背景颜色和白色文本的子视图。 您可以在前标签的宽度上为背景标签上的0到100%设置动画。您可能必须检查是否需要在子视图中填充标签以避免在增加宽度时移动文本。
答案 3 :(得分:2)
斯莫夫特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()
}
}
答案 4 :(得分:1)
为了更轻松地覆盖drawRect:
,您可以创建2个UIView来解决这个问题。
蓝色背景UIView(A)包含白色UILabel。 (剪切子视图打开)
白色背景UIView(B)包含蓝色UILabel。
A将叠加在B上。
注意:2个UILabels将具有相同的大小,相同的字体和相同的位置。
通过调整UIView A的宽度,您可以使处理栏按您的意愿工作。
答案 5 :(得分:0)
最好也是最干净的方法就是使用面具。 进度条的视图层次结构应如下所示:
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