Style text blocks programmatically with colors, backgrounds, typefaces, and formatting.

CE.SDK exposes text styling through the Block API. Edit text content, apply colors and backgrounds, manage typefaces, and control case, weight, and style for an entire text block or for individual character ranges. Ranges are described with native Swift Range<String.Index> values.
Editing Text Content#
Use engine.block.replaceText(_:text:in:) and engine.block.removeText(_:from:) to replace, insert, or remove text. The in and from arguments are optional Swift string ranges — passing nil applies the operation to the entire string.
The snippets below compute ranges with String.range(of:) against a literal that matches the block’s current text — "Hello World".range(of: "World") works only because the block currently holds "Hello World". When you tweak the example, update each literal to match the live text before computing the range.
Replacing the whole string is the common case:
try engine.block.replaceText(text, text: "Hello World")Pass an empty range to insert at its lower bound. The example appends a "!" after the existing text:
// Add a "!" at the end of the texttry engine.block.replaceText(text, text: "!", in: "Hello World".endIndex ..< "Hello World".endIndex)Use String.range(of:) to locate a substring and replace only that range. Here "World" becomes "CE.SDK":
// Replace "World" with "CE.SDK"try engine.block.replaceText(text, text: "CE.SDK", in: "Hello World".range(of: "World")!)removeText(_:from:) mirrors the same shape. Pass an explicit range to remove a substring, or pass nil to clear the whole text:
// Remove the "Hello "try engine.block.removeText(text, from: "Hello CE.SDK".range(of: "Hello ")!)Text Colors#
Apply colors to the entire text block or to a specific range with engine.block.setTextColor(_:color:in:). Use Color.rgba(r:g:b:a:) for RGBA colors or Color.spot(name:tint:) for spot colors.
Color the whole string first:
try engine.block.setTextColor(text, color: .rgba(r: 1, g: 1, b: 0))Then override the color on a specific range. The example below leaves the leading "C" and the trailing "!" yellow, but renders the middle "E.SDK" in black:
try engine.block.setTextColor(text, color: .rgba(r: 0, g: 0, b: 0), in: "CE.SDK".range(of: "E.SDK")!)engine.block.getTextColors(_:in:) returns the ordered list of unique colors in the requested range. For the full text the result is [yellow, black], since yellow appears first:
let allColors = try engine.block.getTextColors(text)print("All unique colors: \(allColors)")Querying the "E.SDK!" range returns [black, yellow] — the range starts in the black middle and ends on the yellow !, so black appears first:
let colorsInRange = try engine.block.getTextColors(text, in: "CE.SDK!".range(of: "E.SDK!")!)print("Colors in \"E.SDK!\": \(colorsInRange)")Text Backgrounds#
Enable the background, then customize the color, padding, and corner radius.
Enable the background with engine.block.setBackgroundColorEnabled(_:enabled:):
try engine.block.setBackgroundColorEnabled(text, enabled: true)Read the current background color with engine.block.getBackgroundColor(_:) and change it with engine.block.setBackgroundColor(_:r:g:b:a:):
let currentBackgroundColor = try engine.block.getBackgroundColor(text)print("Current background color: \(currentBackgroundColor)")try engine.block.setBackgroundColor(text, r: 0.0, g: 0.0, b: 1.0, a: 1.0)Padding and corner radius are exposed as backgroundColor/* block properties. Adjust each padding side independently using engine.block.setFloat(_:property:value:) and the backgroundColor/paddingLeft, backgroundColor/paddingRight, backgroundColor/paddingTop, and backgroundColor/paddingBottom properties:
try engine.block.setFloat(text, property: "backgroundColor/paddingLeft", value: 8)try engine.block.setFloat(text, property: "backgroundColor/paddingTop", value: 8)try engine.block.setFloat(text, property: "backgroundColor/paddingRight", value: 8)try engine.block.setFloat(text, property: "backgroundColor/paddingBottom", value: 8)Round the corners by setting backgroundColor/cornerRadius:
try engine.block.setFloat(text, property: "backgroundColor/cornerRadius", value: 12)Text backgrounds inherit the animations assigned to their text block when textAnimationWritingStyle is set to "Block":
let animation = try engine.block.createAnimation(AnimationType.slide)try engine.block.setEnum(animation, property: "textAnimationWritingStyle", value: "Block")
try engine.block.setInAnimation(text, animation: animation)try engine.block.setOutAnimation(text, animation: animation)Text Case Transformations#
Render text in a different case without modifying the underlying string. The case is a render-time modifier — engine.block.replaceText(_:text:) still returns the original characters.
engine.block.setTextCase(_:textCase:in:) takes a TextCase value:
.normal— render the string as stored..uppercase— render every character in upper case..lowercase— render every character in lower case..titlecase— render the first character of each word in upper case.
try engine.block.setTextCase(text, textCase: .titlecase)engine.block.getTextCases(_:in:) returns the ordered list of text cases in the requested range:
let textCases = try engine.block.getTextCases(text)print("Text cases: \(textCases)")Typefaces and Fonts#
Use engine.block.setFont(_:fontFileURL:typeface:) when you want to change the font and reset existing formatting. Use engine.block.setTypeface(_:typeface:in:) when you want to change the typeface while preserving existing formatting.
A Typeface carries the typeface name and a list of Font definitions. Each Font needs a uri pointing at the font file and a subFamily string matching the font’s effective name within the typeface. The weight and style fields let the engine select the right variant when toggling bold or italic.
let typeface = Typeface( name: "Roboto", fonts: [ Font( uri: baseURL.appendingPathComponent("ly.img.typeface/fonts/Roboto/Roboto-Bold.ttf"), subFamily: "Bold", weight: .bold, style: .normal, ), Font( uri: baseURL.appendingPathComponent("ly.img.typeface/fonts/Roboto/Roboto-BoldItalic.ttf"), subFamily: "Bold Italic", weight: .bold, style: .italic, ), Font( uri: baseURL.appendingPathComponent("ly.img.typeface/fonts/Roboto/Roboto-Italic.ttf"), subFamily: "Italic", weight: .normal, style: .italic, ), Font( uri: baseURL.appendingPathComponent("ly.img.typeface/fonts/Roboto/Roboto-Regular.ttf"), subFamily: "Regular", weight: .normal, style: .normal, ), ],)try engine.block.setFont(text, fontFileURL: typeface.fonts[3].uri, typeface: typeface)setTypeface(_:typeface:in:) keeps the current weight and style as much as the new typeface allows. If the new typeface does not support the current combination, the engine falls back to the closest available variant or to the typeface’s fallback font:
try engine.block.setTypeface(text, typeface: typeface, in: "CE.SDK".range(of: "E.SDK")!)try engine.block.setTypeface(text, typeface: typeface)Query the current typeface with engine.block.getTypeface(_:). A newly created text block has no explicit typeface set, so this call throws until setFont(_:fontFileURL:typeface:) is called for the first time:
let currentDefaultTypeface = try engine.block.getTypeface(text)print("Default typeface: \(currentDefaultTypeface.name)")engine.block.getTypefaces(_:in:) returns the ordered list of unique typefaces used across the requested range:
let currentTypefaces = try engine.block.getTypefaces(text)let currentTypefacesOfRange = try engine.block.getTypefaces(text, in: "CE.SDK".range(of: "E.SDK")!)print("Typefaces across the block: \(currentTypefaces.map(\.name))")print("Typefaces in \"E.SDK\": \(currentTypefacesOfRange.map(\.name))")Font Weights and Styles#
A text block can mix weights and styles across ranges. Toggle between normal and bold, or between normal and italic, using the typed toggle APIs. The active typeface must include a font variant matching the requested combination — otherwise the toggle returns false and the call to apply it throws.
engine.block.canToggleBoldFont(_:in:) reports whether bold can be toggled; engine.block.toggleBoldFont(_:in:) applies the toggle:
if try engine.block.canToggleBoldFont(text) { try engine.block.toggleBoldFont(text)}if try engine.block.canToggleBoldFont(text, in: "CE.SDK".range(of: "E.SDK")!) { try engine.block.toggleBoldFont(text, in: "CE.SDK".range(of: "E.SDK")!)}engine.block.canToggleItalicFont(_:in:) and engine.block.toggleItalicFont(_:in:) work the same way for italic:
if try engine.block.canToggleItalicFont(text) { try engine.block.toggleItalicFont(text)}if try engine.block.canToggleItalicFont(text, in: "CE.SDK".range(of: "E.SDK")!) { try engine.block.toggleItalicFont(text, in: "CE.SDK".range(of: "E.SDK")!)}To set a font weight directly without toggling, use engine.block.setTextFontWeight(_:fontWeight:in:):
try engine.block.setTextFontWeight(text, fontWeight: .bold)engine.block.getTextFontWeights(_:in:) returns the ordered list of unique font weights in the requested range:
let fontWeights = try engine.block.getTextFontWeights(text)print("Font weights: \(fontWeights)")engine.block.setTextFontStyle(_:fontStyle:in:) and engine.block.getTextFontStyles(_:in:) are the equivalent setter and getter for font styles:
try engine.block.setTextFontStyle(text, fontStyle: .italic)let fontStyles = try engine.block.getTextFontStyles(text)print("Font styles: \(fontStyles)")API Reference#
Methods#
| Method | Purpose |
|---|---|
engine.block.replaceText(_:text:in:) |
Replace or insert text at a Swift string range |
engine.block.removeText(_:from:) |
Remove text at a Swift string range |
engine.block.setTextColor(_:color:in:) |
Set the text color for the whole block or a range |
engine.block.getTextColors(_:in:) |
Get the ordered unique text colors for a range |
engine.block.setBackgroundColorEnabled(_:enabled:) |
Enable or disable the text background |
engine.block.setBackgroundColor(_:r:g:b:a:) |
Set the text background color |
engine.block.getBackgroundColor(_:) |
Read the text background color |
engine.block.setFloat(_:property:value:) |
Set a numeric block property such as backgroundColor/paddingLeft or backgroundColor/cornerRadius |
engine.block.createAnimation(_:) |
Create an animation block |
engine.block.setEnum(_:property:value:) |
Set an enum-valued property such as textAnimationWritingStyle |
engine.block.setInAnimation(_:animation:) |
Assign an in-animation to the text block |
engine.block.setOutAnimation(_:animation:) |
Assign an out-animation to the text block |
engine.block.setTextCase(_:textCase:in:) |
Apply a text case transformation |
engine.block.getTextCases(_:in:) |
Get the ordered text cases for a range |
engine.block.setFont(_:fontFileURL:typeface:) |
Change the font and reset existing formatting |
engine.block.setTypeface(_:typeface:in:) |
Change the typeface while preserving formatting |
engine.block.getTypeface(_:) |
Get the text block’s default typeface |
engine.block.getTypefaces(_:in:) |
Get the ordered unique typefaces for a range |
engine.block.canToggleBoldFont(_:in:) |
Check whether bold can be toggled |
engine.block.toggleBoldFont(_:in:) |
Toggle between normal and bold weight |
engine.block.canToggleItalicFont(_:in:) |
Check whether italic can be toggled |
engine.block.toggleItalicFont(_:in:) |
Toggle between normal and italic style |
engine.block.setTextFontWeight(_:fontWeight:in:) |
Set the font weight for the whole block or a range |
engine.block.getTextFontWeights(_:in:) |
Get the ordered unique font weights for a range |
engine.block.setTextFontStyle(_:fontStyle:in:) |
Set the font style for the whole block or a range |
engine.block.getTextFontStyles(_:in:) |
Get the ordered unique font styles for a range |
Properties#
| Property | Type | Description |
|---|---|---|
backgroundColor/paddingLeft |
Float | Padding to the left of the text |
backgroundColor/paddingRight |
Float | Padding to the right of the text |
backgroundColor/paddingTop |
Float | Padding above the text |
backgroundColor/paddingBottom |
Float | Padding below the text |
backgroundColor/cornerRadius |
Float | Corner radius of the background rectangle |
textAnimationWritingStyle |
Enum | Set to "Block" so the background follows the text block’s animations |
Troubleshooting#
getTypeface(_:) throws an error — A new text block has no explicit typeface until setFont(_:fontFileURL:typeface:) is called for the first time.
Bold or italic toggle does nothing — Confirm the active Typeface includes a Font definition matching the requested weight and style combination.
Text background is not visible — Call setBackgroundColorEnabled(_:enabled:) with enabled: true before changing colors, padding, or corner radius.
Text case looks different from the string value — Text case transformations affect rendering only. The stored string value is unchanged; reading it back with the engine still returns the original characters.
Formatting resets after changing fonts — Use setTypeface(_:typeface:in:) instead of setFont(_:fontFileURL:typeface:) to keep weights, styles, and per-range overrides.