How to use Attributed String in SwiftUI
iOS 15 and Swift 5.5
Text
now supports markdown and also you can create custom attributes:
You can even get defined attributes remotely like:
iOS 13 and 14
You can combine multiple Text
objects together with a simple +
operator and that will handle some of the attributions:
Each one can have multiple and specific modifiers
A fully supported fallback!
Since it doesn't support directly on Text
(till iOS 15), you can bring the UILabel
there and modify it in anyway you like:
Implementation:
struct UIKLabel: UIViewRepresentable {
typealias TheUIView = UILabel
fileprivate var configuration = { (view: TheUIView) in }
func makeUIView(context: UIViewRepresentableContext<Self>) -> TheUIView { TheUIView() }
func updateUIView(_ uiView: TheUIView, context: UIViewRepresentableContext<Self>) {
configuration(uiView)
}
}
Usage:
var body: some View {
UIKLabel {
$0.attributedText = NSAttributedString(string: "HelloWorld")
}
}
How to use an NSAttributedString with a ScrollView in SwiftUI?
The reason is that SwiftUI ScrollView
requires defined content size, but used UITextView
is itself a UIScrollView
and detects content based on available space in parent view. Thus it happens cycle of undefined sizes.
Here is a simplified demo of possible approach how to solve this. The idea is to calculate content size of UITextView
and pass it to SwiftUI...
struct TextWithAttributedString: UIViewRepresentable {
@Binding var height: CGFloat
var attributedString: NSAttributedString
func makeUIView(context: Context) -> UITextView {
let textView = UITextView(frame: .zero)
textView.isEditable = false
return textView
}
func updateUIView(_ textView: UITextView, context: Context) {
textView.attributedText = self.attributedString
// calculate height based on main screen, but this might be
// improved for more generic cases
DispatchQueue.main.async { // << fixed
height = textView.sizeThatFits(UIScreen.main.bounds.size).height
}
}
}
struct NSAttributedStringView: View {
@State private var textHeight: CGFloat = .zero
var body: some View {
ScrollView {
TextWithAttributedString(height: $textHeight, attributedString: NSAttributedString(string: exampleText))
.frame(height: textHeight) // << specify height explicitly !
}
}
}
backup
How do you use NSAttributedString?
When building attributed strings, I prefer to use the mutable subclass, just to keep things cleaner.
That being said, here's how you create a tri-color attributed string:
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"firstsecondthird"];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,5)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(5,6)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(11,5)];
typed in a browser. caveat implementor
Obviously you're not going to hard-code in the ranges like this. Perhaps instead you could do something like:
NSDictionary *wordToColorMapping = ....; //an NSDictionary of NSString => UIColor pairs
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@""];
for (NSString *word in wordToColorMapping) {
UIColor *color = [wordToColorMapping objectForKey:word];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:color forKey:NSForegroundColorAttributeName];
NSAttributedString *subString = [[NSAttributedString alloc] initWithString:word attributes:attributes];
[string appendAttributedString:subString];
[subString release];
}
//display string
how to append Attributed Text String with Attributed String in Swift
Use NSMutableAttributedString
to achieve that.
Example
Swift 5
let yourAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 15)]
let yourOtherAttributes = [NSAttributedString.Key.foregroundColor: UIColor.red, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 25)]
let partOne = NSMutableAttributedString(string: "This is an example ", attributes: yourAttributes)
let partTwo = NSMutableAttributedString(string: "for the combination of Attributed String!", attributes: yourOtherAttributes)
partOne.append(partTwo)
Swift 3
let yourAttributes = [NSForegroundColorAttributeName: UIColor.black, NSFontAttributeName: UIFont.systemFont(ofSize: 15)]
let yourOtherAttributes = [NSForegroundColorAttributeName: UIColor.red, NSFontAttributeName: UIFont.systemFont(ofSize: 25)]
let partOne = NSMutableAttributedString(string: "This is an example ", attributes: yourAttributes)
let partTwo = NSMutableAttributedString(string: "for the combination of Attributed String!", attributes: yourOtherAttributes)
let combination = NSMutableAttributedString()
combination.append(partOne)
combination.append(partTwo)
combination
represents your final string which contains both formattings provided by yourAttributes
and yourOtherAttributes
Even older
let yourAttributes = [NSForegroundColorAttributeName: UIColor.blackColor(), NSFontAttributeName: UIFont.systemFontOfSize(15)]
let yourOtherAttributes = [NSForegroundColorAttributeName: UIColor.redColor(), NSFontAttributeName: UIFont.systemFontOfSize(25)]
let partOne = NSMutableAttributedString(string: "This is an example ", attributes: yourAttributes)
let partTwo = NSMutableAttributedString(string: "for the combination of Attributed String!", attributes: yourOtherAttributes)
let combination = NSMutableAttributedString()
combination.appendAttributedString(partOne)
combination.appendAttributedString(partTwo)
iphone/ipad: How exactly use NSAttributedString?
You should take a look at AliSoftware's OHAttributedLabel. It is a subclass of UILabel that draws an NSAttributedString and also provides convenience methods for setting the attributes of an NSAttributedString from UIKit classes.
From the sample provided in the repo:
#import "NSAttributedString+Attributes.h"
#import "OHAttributedLabel.h"
/**(1)** Build the NSAttributedString *******/
NSMutableAttributedString* attrStr = [NSMutableAttributedString attributedStringWithString:@"Hello World!"];
// for those calls we don't specify a range so it affects the whole string
[attrStr setFont:[UIFont systemFontOfSize:12]];
[attrStr setTextColor:[UIColor grayColor]];
// now we only change the color of "Hello"
[attrStr setTextColor:[UIColor redColor] range:NSMakeRange(0,5)];
/**(2)** Affect the NSAttributedString to the OHAttributedLabel *******/
myAttributedLabel.attributedText = attrStr;
// Use the "Justified" alignment
myAttributedLabel.textAlignment = UITextAlignmentJustify;
// "Hello World!" will be displayed in the label, justified, "Hello" in red and " World!" in gray.
Note: In iOS 6+ you can render attributed strings using the attributedText property of UILabel.
How to use replacingOccurrences for NSAttributedString in swift?
To get this working,
1. First you need to find the indices of all the duplicate substrings existing in a string. To get that you can use this: https://stackoverflow.com/a/40413665/5716829
extension String {
func indicesOf(string: String) -> [Int] {
var indices = [Int]()
var searchStartIndex = self.startIndex
while searchStartIndex < self.endIndex,
let range = self.range(of: string, range: searchStartIndex..<self.endIndex),
!range.isEmpty
{
let index = distance(from: self.startIndex, to: range.lowerBound)
indices.append(index)
searchStartIndex = range.upperBound
}
return indices
}
}
2. Next you need to apply your desired attribute to substring at each index, i.e.
let str = "The problem is that replacingOccurrences Hello is only possible for string types, as I want to give Hello a new value every time Hello the word appears in the entire sentence Hello."
let indices = str.indicesOf(string: "Hello")
let attrStr = NSMutableAttributedString(string: str, attributes: [.foregroundColor : UIColor.blue])
for index in indices
{
//You can write your own logic to specify the color for each duplicate. I have used some hardcode indices
var color: UIColor
switch index
{
case 41:
color = .orange
case 100:
color = .magenta
case 129:
color = .green
default:
color = .red
}
attrStr.addAttribute(.foregroundColor, value: color, range: NSRange(location: index, length: "Hello".count))
}
Screenshot:
Let me know if you still face any issues. Happy Coding../p>
How to set font size on NSAttributedString
let myString = "Swift Attributed String"
let myAttribute = [ NSForegroundColorAttributeName: UIColor.blue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute)
// set attributed text on a UILabel
myLabel.attributedText = myAttrString
Font
let myAttribute = [ NSFontAttributeName: UIFont(name: "Chalkduster", size: 18.0)! ]
Shadow
let myShadow = NSShadow()
myShadow.shadowBlurRadius = 3
myShadow.shadowOffset = CGSize(width: 3, height: 3)
myShadow.shadowColor = UIColor.gray
let myAttribute = [ NSShadowAttributeName: myShadow ]
Underline
let myAttribute = [ NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleSingle.rawValue ]
Textcolor
let myAttribute = [ NSForegroundColorAttributeName: UIColor.blue ]
Background Color
let myAttribute = [ NSBackgroundColorAttributeName: UIColor.yellow ]
NSAttributedString: How to mimic opacity or alpha equivalent using color
You can change any color alpha using
UIColor.red.withAlphaComponent(0.5)
Of course, you have to know the original color.
There is no universal alpha modifier.
IOS Anyway to have NSAttributedString throughout app. Swift
Based on @AdamPro13 suggestion, you could create a protocol extension for your NSAttributedString
:
So, create NSAttributedStringExtension.swift
with something like that:
protocol NSAttributedStringExtension {
static func attributed(string:String, font:UIFont, color:UIColor) -> NSAttributedString
}
extension NSAttributedString : NSAttributedStringExtension {
class func attributed(string:String, font:UIFont, color:UIColor) -> NSAttributedString {
let attrs = [NSFontAttributeName:font, NSForegroundColorAttributeName:color]
return NSAttributedString(string: string, attributes: attrs)
}
}
And you could make several different functions for different label types.
Just apply then on your label (rough code):
let label:UILabel
let font:UIFont
let color:UIColor
label.attributedText = NSAttributedString.attributed("test", font: font, color: color)
Note: the font and colour you could setup in your protocol extension function
Related Topics
Update Badge With Push Notification While App in Background
How to Add Pagecontrol Inside Uicollectionview Image Scrolling
How to Take a Screenshot Programmatically on Ios
Applications Are Expected to Have a Root View Controller At the End of Application Launch
Uploading File With Parameters Using Alamofire
Class Does Not Implement Its Superclass'S Required Members
Load Resources from Relative Path Using Local HTML in Uiwebview
Converting Storyboard from Iphone to Ipad
Ios App Submission: Missing 64-Bit Support
Scrolling Issue on Position Fixed Element on Ios
Open Facebook Page in Native Facebook iOS App Via Simple Url Sheme Issue
How to Associate File Types With an Iphone Application
Performselector May Cause a Leak Because Its Selector Is Unknown
How to Find Topmost View Controller on Ios
Background Location Services Not Working in iOS 7