UILabel: background dependent color
The easiest way is to create a UIView
subclass that has a progress
property and overwrites -drawRect:
.
All the code you need is this:
- (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];
}
You can expand the class as needed with properties for background color, text color, font, etc.
iOS UILabel use negative background color as text color
If I were to do this I would probably create a custom UIView
class with an API similar to UILabel
(with just the parts I needed) plus a property to indicate what portion of the text should be reversed.
Then I would implement the drawRect:
method to draw the text twice using two different clipping regions. For each half I would set the proper colors for the text and background fill.
It's possible this could be done by subclassing UILabel
with the one additional property plus the custom drawRect:
method.
Changing the background color of a UILabel within a UITableViewCell
Your code snippet works fine for me, but it must be done after the cell has been added to the table and shown, I believe. If called from the initWithFrame:reuseIdentifier:
, you'll get an exception, as the UILabel
subview has not yet been created.
Probably the best solution is to add your own UILabel
, configured to your standards, rather than relying on this (very rickety) path to the built-in one.
Inverse UIlabel text color when its frame intersects an UIView
Good puzzle! Here's what I would do:
- Two UIViews. Let's call one the background and the other the progressBar. progressBar is stacked on top of background with the same
origin
on their commonsuperview
. - They both have a UILabel as subview, and both labels at the same origin relative to their parent. background has a dark
backgroundColor
and it's label has lighttextColor
and the progress view has things the other way around. - progressBar has a narrower frame width than background and has
clipsToBounds==YES
The trick is, with the views' origins the same and the labels' origins the same, and clipsToBounds on the top view, everything is going to look right.
Drop those two views into a new UIView subclass called ReallyCoolProgressView, and give it one public method:
-(void)setProgress:(float)progress
progress is a number from 0.0 to 1.0. The method scales the progressBar width and sets both label's text @"Progress %f", progress*100
UIProgressBar: How to Change UILabel Color according to Background Color
If you want an answer in swift, here is the code(changed from objc to swift) from this post, which should be exactly what you need:
This is swift 4
class MyProgressView: UIView {
var progress: CGFloat = 0 {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
// Set up environment.
let size = bounds.size
let backgroundColor = UIColor(red: 108/255, green: 200/255, blue: 226/255, alpha: 1)
let foregroundColor = UIColor.white
let font = UIFont.boldSystemFont(ofSize: 42)
// Prepare progress as a string.
let progress = NSString(format: "%d%%", Int(round(self.progress * 100))) // this cannot be a String because there are many subsequent calls to NSString-only methods such as `size` and `draw`
var attributes: [NSAttributedString.Key: Any] = [.font: font]
let textSize = progress.size(withAttributes: attributes)
let progressX = ceil(self.progress * size.width)
let textPoint = CGPoint(x: ceil((size.width - textSize.width) / 2), y: ceil((size.height - textSize.height) / 2))
// Draw background + foreground text
backgroundColor.setFill()
context?.fill(bounds)
attributes[.foregroundColor] = foregroundColor
progress.draw(at: textPoint, withAttributes: attributes)
// Clip the drawing that follows to the remaining progress's frame
context?.saveGState()
let remainingProgressRect = CGRect(x: progressX, y: 0, width: size.width - progressX, height: size.height)
context?.addRect(remainingProgressRect)
context?.clip()
// Draw again with inverted colors
foregroundColor.setFill()
context?.fill(bounds)
attributes[.foregroundColor] = backgroundColor
progress.draw(at: textPoint, withAttributes: attributes)
context?.restoreGState()
}
}
Tested with playground
UIAppearance of UILabel whithin UICollectionViewCell - selected/unselected
Finally found a Workaround for this issue. I post my solution it may help someone.
first I define the color for both textColor
and highlightedTextColor
UILabel.appearance(whenContainedInInstancesOf: [MyCollectionViewCell.self]).textColor = colorScheme.color1
UILabel.appearance(whenContainedInInstancesOf: [MyCollectionViewCell.self]).highlightedTextColor = colorScheme.color2
Then in MyCollectionViewCell
I "bind" the isSelected
to UILabel isHighlighted
:
class MyCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var myLabel: UILabel!
override var isSelected: Bool {
didSet {
self.myLabel.isHighlighted = isSelected
}
}
}
Works flawlessly.
Hope this can help someone
Related Topics
Is the Current Location/Compass Heading Button Available in the iOS Sdk
Share Video on Twitter with Fabric API Without Composer iOS
Dragging Scnnode in Arkit Using Scenekit
How to Retrieve Messages Logged with Os_Log from iPad/Iphone
Trouble Creating Xmpp Muc Room: Code 503 (Service Unavailable)
How to Activate Tcp Keepalive on Apple iOS Devices
How to Add a Character at a Particular Index in String in Swift
Swift Add Footer View in Uitableview
Ios/Ipados Safari Push API Support
Customize Navigation Bar with Title View
How to Get the Result Value of Alamofire.Request().Responsejson in Swift 2
How to Detect a Dual Core CPU on iOS
How to Easily Support Light and Dark Mode with a Custom Color Used in My App
iPad iOS7 - Uiimagepickercontroller in Uipopovercontroller Has Wrong Preview Image