Hi Im trying to change the text color of a UILabel in the case when the labels rect intersects an UIView, i was thinking maybe there is a property or something i can use. L
Built an example in Swift for anyone that's looking for a practical application. Great guidance on this danh - thanks!
import UIKit
class CDSlideView: UIView {
var leftBackView: UIView!
var leftBackLabel: UILabel!
var leftFrontView: UIView!
var leftFrontLabel: UILabel!
var rightBackView: UIView!
var rightBackLabel: UILabel!
var rightFrontView: UIView!
var rightFrontLabel: UILabel!
var foregroundView: UIView!
var backgroundView: UIView!
var slideGesture: UIPanGestureRecognizer!
let lightColor: UIColor = UIColor.whiteColor()
let darkColor: UIColor = UIColor.blueColor()
let leftText: String = "Search"
let rightText: String = "New"
var viewWidth: CGFloat!
var viewHeight: CGFloat!
var leftOrigin: CGFloat!
var rightOrigin: CGFloat!
var foregroundPadding: CGFloat = 4
override init(frame: CGRect) {
super.init(frame: frame)
// Init variables variables
viewWidth = self.frame.size.width
viewHeight = self.frame.size.height
leftOrigin = foregroundPadding / 2
rightOrigin = (viewWidth - foregroundPadding) / 2 + foregroundPadding / 2
backgroundView = UIView()
backgroundView.frame = CGRectMake(0, 0, viewWidth, viewHeight)
backgroundView.layer.cornerRadius = backgroundView.frame.size.height / 2
self.addSubview(backgroundView)
leftBackView = UIView()
leftBackView.frame = CGRectMake(0, 0, backgroundView.frame.size.width / 2, backgroundView.frame.size.height)
self.backgroundView.addSubview(leftBackView)
leftBackLabel = UILabel()
leftBackLabel.frame = CGRectMake(0, 0, leftBackView.frame.size.width, leftBackView.frame.size.height)
leftBackLabel.font = UIFont.systemFontOfSize(13, weight: UIFontWeightSemibold)
leftBackLabel.backgroundColor = UIColor.clearColor()
leftBackLabel.lineBreakMode = .ByClipping
leftBackLabel.textAlignment = .Center
self.leftBackView.addSubview(leftBackLabel)
rightBackView = UIView()
rightBackView.frame = CGRectMake(backgroundView.frame.size.width / 2, 0, backgroundView.frame.size.width / 2, backgroundView.frame.size.height)
self.backgroundView.addSubview(rightBackView)
rightBackLabel = UILabel()
rightBackLabel.frame = CGRectMake(0, 0, rightBackView.frame.size.width, rightBackView.frame.size.height)
rightBackLabel.font = UIFont.systemFontOfSize(13, weight: UIFontWeightSemibold)
rightBackLabel.backgroundColor = UIColor.clearColor()
rightBackLabel.lineBreakMode = .ByClipping
rightBackLabel.textAlignment = .Center
self.rightBackView.addSubview(rightBackLabel)
foregroundView = UIView()
foregroundView.frame = CGRectMake(foregroundPadding / 2, foregroundPadding / 2, (backgroundView.frame.size.width - foregroundPadding) / 2, backgroundView.frame.size.height - foregroundPadding)
foregroundView.clipsToBounds = true
foregroundView.layer.cornerRadius = (foregroundView.frame.size.height - foregroundPadding / 2) / 2
self.addSubview(foregroundView)
slideGesture = UIPanGestureRecognizer(target: self, action: #selector(CDSlideView.slideAction))
self.foregroundView.addGestureRecognizer(slideGesture)
leftFrontView = UIView()
leftFrontView.frame = CGRectMake(0, 0, backgroundView.frame.size.width / 2, backgroundView.frame.size.height)
self.foregroundView.addSubview(leftFrontView)
leftFrontLabel = UILabel()
leftFrontLabel.font = UIFont.systemFontOfSize(13, weight: UIFontWeightSemibold)
leftFrontLabel.backgroundColor = UIColor.clearColor()
leftFrontLabel.translatesAutoresizingMaskIntoConstraints = false
leftFrontLabel.lineBreakMode = .ByClipping
leftFrontLabel.textAlignment = .Center
self.leftFrontView.addSubview(leftFrontLabel)
let leftFrontLabelLeadingConstraint = NSLayoutConstraint(item: leftFrontLabel, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1, constant: self.backgroundView.frame.origin.x)
self.addConstraint(leftFrontLabelLeadingConstraint)
let leftFrontLabelTopConstraint = NSLayoutConstraint(item: leftFrontLabel, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: self.backgroundView.frame.origin.y)
self.addConstraint(leftFrontLabelTopConstraint)
let leftFrontLabelWidthConstraint = NSLayoutConstraint(item: leftFrontLabel, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: leftFrontView.frame.size.width)
self.addConstraint(leftFrontLabelWidthConstraint)
let leftFrontLabelHeightConstraint = NSLayoutConstraint(item: leftFrontLabel, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: leftFrontView.frame.size.height)
self.addConstraint(leftFrontLabelHeightConstraint)
rightFrontView = UIView()
rightFrontView.frame = CGRectMake(backgroundView.frame.size.width / 2, 0, backgroundView.frame.size.width / 2, backgroundView.frame.size.height)
self.foregroundView.addSubview(rightFrontView)
rightFrontLabel = UILabel()
rightFrontLabel.font = UIFont.systemFontOfSize(13, weight: UIFontWeightSemibold)
rightFrontLabel.backgroundColor = UIColor.clearColor()
rightFrontLabel.translatesAutoresizingMaskIntoConstraints = false
rightFrontLabel.lineBreakMode = .ByClipping
rightFrontLabel.textAlignment = .Center
self.rightFrontView.addSubview(rightFrontLabel)
let rightFrontLabelTrailingConstraint = NSLayoutConstraint(item: self, attribute: .Trailing, relatedBy: .Equal, toItem: rightFrontLabel, attribute: .Trailing, multiplier: 1, constant: self.backgroundView.frame.origin.x)
self.addConstraint(rightFrontLabelTrailingConstraint)
let rightFrontLabelTopConstraint = NSLayoutConstraint(item: rightFrontLabel, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: self.backgroundView.frame.origin.y)
self.addConstraint(rightFrontLabelTopConstraint)
let rightFrontLabelWidthConstraint = NSLayoutConstraint(item: rightFrontLabel, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: rightFrontView.frame.size.width)
self.addConstraint(rightFrontLabelWidthConstraint)
let rightFrontLabelHeightConstraint = NSLayoutConstraint(item: rightFrontLabel, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: rightFrontView.frame.size.height)
self.addConstraint(rightFrontLabelHeightConstraint)
let leftTapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(CDSlideView.leftTap(_:)))
self.leftBackView.addGestureRecognizer(leftTapGesture)
let rightTapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(CDSlideView.rightTap(_:)))
self.rightBackView.addGestureRecognizer(rightTapGesture)
self.setLabelText(leftText, rightText: rightText)
self.setLightColor(lightColor)
self.setDarkColor(darkColor)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: Setup
func setLightColor(lightColor: UIColor) {
let lightColor = lightColor
self.foregroundView.backgroundColor = lightColor
self.leftBackLabel.textColor = lightColor
self.rightBackLabel.textColor = lightColor
}
func setDarkColor(darkColor: UIColor) {
let darkColor = darkColor
self.backgroundView.backgroundColor = darkColor
self.leftFrontLabel.textColor = darkColor
self.rightFrontLabel.textColor = darkColor
}
func setLabelText(leftText: String, rightText: String) {
self.leftFrontLabel.text = leftText
self.leftBackLabel.text = leftText
self.rightFrontLabel.text = rightText
self.rightBackLabel.text = rightText
}
// MARK: Actions
func slideAction(sender: UIPanGestureRecognizer) {
if sender.state == .Began || sender.state == .Changed {
let translation = sender.translationInView(self)
// Calculate where the user is trying to drag
var newCenter: CGPoint = CGPointMake(sender.view!.center.x + translation.x, sender.view!.center.y)
// Limit bounds & update center
newCenter.x = max(self.frame.size.width * 0.25 + foregroundPadding / 2, newCenter.x)
newCenter.x = min(self.frame.size.width * 0.75 - foregroundPadding / 2, newCenter.x)
// Set new center
sender.view!.center = newCenter
sender.setTranslation(CGPointMake(0,0), inView: self)
} else if sender.state == .Ended {
let senderVCX = sender.view?.center.x
// Snap to side
if senderVCX <= viewWidth / 2 {
print("called left")
sender.view?.frame.origin.x = self.leftOrigin
} else {
print("called right")
sender.view?.frame.origin.x = self.rightOrigin
}
}
}
func leftTap(sender: UITapGestureRecognizer) {
UIView.animateWithDuration(0.05) {
self.foregroundView.frame.origin.x = self.leftOrigin
}
}
func rightTap(sender: UITapGestureRecognizer) {
UIView.animateWithDuration(0.05) {
self.foregroundView.frame.origin.x = self.rightOrigin
}
}
}
I would suggest you to have a look at these methods:
You may check how much of your string overlaps with the view by checking NSString's size, with this method:
[yourString sizeWithFont:yourFont constrainedToSize:maximumAllowedSize];
Then you can use a NSMutableAttributedString for setting part of the label's strings to one color and the latter part with another color.
//Just an example usage
//It sets the color of characters starting from 3 to the end to blue
[str addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(3, str.length)];
//Now you have to set your string as attributed text just like below
//UILabels now support attributed strings by default which is quite handy
[yourLabel setAttributedString:str];
Good puzzle! Here's what I would do:
origin
on their common superview
.backgroundColor
and it's label has light textColor
and the progress view has things the other way around.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
Take a look at this tutorial for creating alpha masks with text. Using this technique you can implement a standard progress bar that moves across both the foreground and the background view to achieve the effect you want.