Change UILabel attributed String color multiple times - swift

I am new to Swift 5 and am doing my first project.
I want to change the color of some texts inside my label, this is what my label looks like:
"You need to pay attention to blue texts, and even more to red texts. Try again so there is no more blue / red texts"
I want to change all the "blue" to blue, and all the "red" to red. Did some research and this is what I found:
extension NSMutableAttributedString {
func setColor(color: UIColor, forText stringValue: String) {
let range: NSRange = self.mutableString.range(of: stringValue, options: .caseInsensitive)
self.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: range)
}
}
let mainString = popUpLabel.text!
let blueString = "màu xanh" //(which is blue)
let redString = "màu đỏ" //(whish is red)
let attributedString = NSMutableAttributedString.init(string: mainString)
attributedString.setColor(color: UIColor(red: 0.24, green: 0.65, blue: 0.96, alpha: 1.00), forText: blueString)
attributedString.setColor(color: UIColor(red: 0.99, green: 0.20, blue: 0.20, alpha: 1.00), forText: redString)
popUpLabel.attributedText = attributedString
And also tried this:
let mainString = popUpLabel.text!
let blueString = "màu xanh" //(which is blue)
let redString = "màu đỏ" //(which is red)
let attributedString = NSMutableAttributedString.init(string: mainString)
let blueRange = (mainString as NSString).range(of: blueString)
let redRange = (mainString as NSString).range(of: redString)
attributedString.addAttributes([NSAttributedString.Key.foregroundColor : UIColor(red: 0.24, green: 0.65, blue: 0.96, alpha: 1.00)], range: blueRange)
attributedString.addAttributes([NSAttributedString.Key.foregroundColor : UIColor(red: 0.99, green: 0.20, blue: 0.20, alpha: 1.00)], range: redRange)
popUpLabel.attributedText = attributedString
Both works pretty well for the first blue and red, but the second blue and red stayed in black and I don't know why.

range(of: finds only the first occurrence of the search string.
A possible solution is Regular Expression, the pattern searches for both red and blue and changes the color accordingly.
let string = "You need to pay attention to blue texts, and even more to red texts. Try again so there is no more blue / red texts"
let pattern = "(red|blue)"
var attributedString = NSMutableAttributedString(string: string)
let regex = try! NSRegularExpression(pattern: pattern)
let matches = regex.matches(in: string, range: NSRange(string.startIndex..., in: string))
for match in matches {
let range = Range(match.range, in: string)!
let color : UIColor
if string[range] == "red" {
color = UIColor(red: 0.99, green: 0.20, blue: 0.20, alpha: 1.00)
} else {
color = UIColor(red: 0.24, green: 0.65, blue: 0.96, alpha: 1.00)
}
attributedString.addAttribute(.foregroundColor, value: color, range: match.range)
}

You also may use html-text converted to attributed string. Look at this answer.
Example from the answer:
let htmlText = "<medium><b><font color='#2f3744'>IPL Tamil Web Series Episode #3 | யாருடா Swetha ? | Tamil Comedy Web Series | Being Thamizhan</font></b></medium> has been succesfully scheduled on <medium><b><font color='#2f3744'>2018-05-23 08:51 PM</font></b></medium>"
let encodedData = htmlText.data(using: String.Encoding.utf8)!
var attributedString: NSAttributedString
do {
attributedString = try NSAttributedString(data: encodedData,
options:
[NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html,
NSAttributedString.DocumentReadingOptionKey.characterEncoding: NSNumber(value: String.Encoding.utf8.rawValue)],
documentAttributes: nil)
} catch let error as NSError {
print(error.localizedDescription)
} catch {
print("error")
}

Related

UILabel With Different Colours

I have a label in a custom cell which displays some info. The info will different in every cell and I would like to change the colour of a few 'keywords' inside the label so that they stand out.
I've tried the approach of converting the text to a NSMutableAttributedString and changing the colour of the text at a certain index. However, the location of the keyword in the text is different in every sentence. Is there any way to add something around the keywords so that they can be identified easily?
Edit: This answered my question:
Changing specific text's color using NSMutableAttributedString in Swift
You can do with attirbutedSring. Do not forget change font.
let string1 = "Your string";
let string2 = "your string 2";
let attributedString = NSMutableAttributedString(string: "“\(string1)” \(string2)", attributes: [
.font: UIFont(name: "IBMPlexSans", size: 15.0)!,
.foregroundColor: UIColor(red: 128.0 / 255.0, green: 130.0 / 255.0, blue: 135.0 / 255.0, alpha: 1.0),
.kern: 0.4
])
attributedString.addAttribute(.foregroundColor, value: UIColor(red: 1.0 / 255.0, green: 6.0 / 255.0, blue: 16.0 / 255.0, alpha: 1.0), range: NSRange(location: 0, length: string1.count));
yourLabel.attributedText = attributedString;

Image Position in Attributed Text

I've created an attributed text with some text and 2 images. I want to place one of the images at the front and the other at the end after the text. That is working good so far. My issue is that I want the second image at the end to be placed above the text like a quotation ". I am trying to position that image at the top, instead of having it at the bottom.
This is what I've tried:
let iconsSize = CGRect(x: 0, y: -5, width: 10, height: 10)
let attributedString = NSMutableAttributedString()
let attachment = NSTextAttachment()
attachment.image = UIImage(named: "quote1")?.maskWithColor(color: #colorLiteral(red: 0.7540688515, green: 0.7540867925, blue: 0.7540771365, alpha: 1))
attachment.bounds = iconsSize
attributedString.append(NSAttributedString(attachment: attachment))
if let quotes = QuotesArray.instance.quotesArray.randomElement() {
attributedString.append(NSAttributedString(string: "\n \(quotes) "))
}
let attachment2 = NSTextAttachment()
attachment2.image = UIImage(named: "quote2")?.maskWithColor(color: #colorLiteral(red: 0.7540688515, green: 0.7540867925, blue: 0.7540771365, alpha: 1))
attachment2.bounds = iconsSize
attributedString.append(NSAttributedString(attachment: attachment2))
quotesLbl.attributedText = attributedString
Result:

Can't change Paragraph attributes and String Attributes at the same time

I can get either the NSMutableParagraphStyle line spacing working OR the NSMutableAttributedString to be the correct font,color and size, but I can't get them both at the same time.
let style = NSMutableParagraphStyle()
style.lineSpacing = 5
let attributes = [NSParagraphStyleAttributeName : style]
aboutScrollable.attributedText = NSAttributedString(string: aboutScrollable.text, attributes:attributes)
let myString:NSString = aboutScrollable.text as NSString
var myMutableString = NSMutableAttributedString()
myMutableString = NSMutableAttributedString(string: myString as String, attributes: [NSFontAttributeName:UIFont(name: "Geomanist-regular", size: 12.0)!])
myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor(red: 30/255, green: 30/255, blue: 30/255, alpha: 1), range: NSRange(location: 0,length: aboutScrollable.text.characters.count))
// set label Attribute
aboutScrollable.attributedText = myMutableString; NSAttributedString(string: aboutScrollable.text, attributes:attributes)

Does the legend limit the number of titles?

I am using iso-charts to try and draw a pie chart in an iOS app.
No matter what I try, I can't seem to get the full number of titles to draw in the legend.
I have my data set up as:
ages = ["18-", "25-", "35-", "45-", "55-", "65-", "75+"]
agePercentages = [10.0, 20.0, 30.0, 5.0, 10.0, 45.0, 120.0]
My code to setup the pieChart as:
func setPieDefaults(myPieChart: PieChartView) -> PieChartView {
myPieChart.frame = CGRectMake(0, 0, UIScreen.mainScreen().bounds.size.width, UIScreen.mainScreen().bounds.size.width*0.5)
myPieChart.usePercentValuesEnabled = true
myPieChart.holeTransparent = true
myPieChart.holeColor = UIColor.darkPurpleColor()
myPieChart.backgroundColor = UIColor.darkPurpleColor()
myPieChart.rotationAngle = 0.0
myPieChart.rotationEnabled = true
myPieChart.centerTextFont = UIFont(name: "HelveticaNeue-Bold", size:20)!
myPieChart.descriptionText = ""
myPieChart.centerText = "%"
myPieChart.centerTextColor = UIColor.whiteColor()
myPieChart.drawHoleEnabled = true
myPieChart.noDataText = "Loading Data ..."
let legend = myPieChart.legend
legend.font = UIFont(name: "Arial", size: 11)!
legend.textColor = UIColor.whiteColor()
legend.position = .RightOfChart
legend.form = .Circle
return myPieChart
}
And ..
func setChart(dataPoints: [String], values: [Double], myPieView: PieChartView) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = ChartDataEntry(value: values[i], xIndex: i)
dataEntries.append(dataEntry)
}
var colors = [UIColor]()
switch myPieView {
case genderPieChartView:
colors = [UIColor.blueColor(), UIColor.pinkColor()]
default:
colors = ChartColorTemplates.colorful()
}
let pieChartDataSet = PieChartDataSet(yVals: dataEntries, label: nil)
pieChartDataSet.sliceSpace = 3.0
pieChartDataSet.colors = colors
let pieChartData = PieChartData(xVals: dataPoints, dataSet: pieChartDataSet)
myPieView.animate(xAxisDuration: 2, yAxisDuration: 2)
let pFormatter = NSNumberFormatter()
pFormatter.numberStyle = .PercentStyle
pFormatter.maximumFractionDigits = 0
pFormatter.percentSymbol = ""
pFormatter.multiplier = 1
pieChartData.setValueFormatter(pFormatter)
pieChartData.setValueFont(UIFont(name: "HelveticaNeue-Bold", size: 11)!)
pieChartData.setValueTextColor(UIColor.whiteColor())
myPieView.data = pieChartData
myPieView.drawSliceTextEnabled = false
}
But it won't print any more than 5 of the labels. It's returning the pie-slices perfectly. But not the labels in the legend.
Am I doing something wrong? Thanks in advance for letting me know.
Solved.
In reading the framework docs for the Android version a little better:
The number of entries the automatically generated legend contains
depends on the number of different colors (across all DataSet objects)
as well as on the DataSet labels. The labels of the Legend depend on
the labels set for the used DataSet objects in the chart. If no labels
for the DataSet objects have been specified, the chart will
automatically generate them. If multiple colors are used for one
DataSet, those colors are grouped and only described by one label.
I realised I needed to increase the number of colours in the ChartColorTemplate.colorful() definition to match the number of labels I was trying to use. The current example code comes with only 5 colours defined.
public class func colorful () -> [UIColor]
{
return [
UIColor(red: 193/255.0, green: 37/255.0, blue: 82/255.0, alpha: 1.0),
UIColor(red: 255/255.0, green: 102/255.0, blue: 0/255.0, alpha: 1.0),
UIColor(red: 245/255.0, green: 199/255.0, blue: 0/255.0, alpha: 1.0),
UIColor(red: 106/255.0, green: 150/255.0, blue: 31/255.0, alpha: 1.0),
UIColor(red: 179/255.0, green: 100/255.0, blue: 53/255.0, alpha: 1.0),
UIColor(red: 200/255.0, green: 100/255.0, blue: 53/255.0, alpha: 1.0), // added colour
UIColor(red: 150/255.0, green: 150/255.0, blue: 70/255.0, alpha: 1.0), // added colour
UIColor(red: 84/255.0, green: 78/255.0, blue: 53/255.0, alpha: 1.0), // added colour
]
}
If you have the same problem, then define a lot more colours to meet the needs of the maximum number of labels needed. This will also solve a problem if you try and word-wrap the legend (which I was also facing).

Add several attributes to a NSMutableAttributedString

I'm trying to add several attributes to a NSMutableAttributedString; i tried this:
let stringNumero: NSString = "\(squadra.cori.count)" //= two-digit number
var stringNumeroMutable = NSMutableAttributedString()
stringNumeroMutable = NSMutableAttributedString(string: stringNumero as! String, attributes: [NSFontAttributeName: UIFont(name: "Noteworthy-Light", size: 9)!,
NSForegroundColorAttributeName: UIColor(red: 110/255.0, green: 183/255.0, blue: 93/255.0, alpha: 1.0)])
cell.numeroCori.attributedText = stringNumeroMutable
now I'd like to add an other attributes and i'm going uso this code:
stringNumeroMutable.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFontOfSize(8), range: NSRange(location: 0, length: 1))
but I'm incurring in a problem:
as you see, the bold effect is attributed only to the first digit and the previous attributed (such as the font) disappear. I think the the second NSFontAttributedName subscribe the previous one, so is there any way to set both font and bold?
Thanks a lot!!!
Edit: as suggested i tried to recall the method like this:
let stringNumero: NSString = "\(squadra.cori.count)" //= two-digit number
var stringNumeroMutable = NSMutableAttributedString()
stringNumeroMutable = NSMutableAttributedString(string: stringNumero as! String, attributes: [NSFontAttributeName: UIFont(name: "Noteworthy-Light", size: 9)!,
NSForegroundColorAttributeName: UIColor(red: 110/255.0, green: 183/255.0, blue: 93/255.0, alpha: 1.0)])
cell.numeroCori.attributedText = stringNumeroMutable
stringNumeroMutable.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFontOfSize(9), range: NSRange(location: 0, length: stringNumeroMutable.length))
cell.numeroCori.atributedText = stringNumeroMutable
but the second call overwrite the first one (so the number loose the attributed font). How to solve this?
I think your problem, that you use method boldSystemFontOfSize
boldSystemFontOfSize:
Returns the font object used for standard interface items that are
rendered in boldface type in the specified size.
See my solution:
#IBOutlet weak var label: UILabel!
var mutableAttributedString: NSMutableAttributedString!
override func viewDidLoad() {
super.viewDidLoad()
let someString = "Hello World"
let attr: [String: AnyObject] = [NSFontAttributeName: UIFont(name: "Helvetica", size: 10)!,
NSForegroundColorAttributeName: UIColor(red: 0.18, green: 0.18, blue: 0.18, alpha: 1.0)]
mutableAttributedString = NSMutableAttributedString(string: someString, attributes: attr)
label.attributedText = mutableAttributedString
}
#IBAction func buttonPressed(sender: UIButton) {
let font = mutableAttributedString.attribute(NSFontAttributeName, atIndex: 1, effectiveRange: nil)!
mutableAttributedString.addAttribute(NSFontAttributeName, value: font.fontWithSize(20) , range: NSMakeRange(0, mutableAttributedString.length))
label.attributedText = mutableAttributedString
}
In buttonPressed function you define current font of mutableAttributedString and then you can change font's size with method fontWithSize.