SwiftUI AttributedString on Watch


Gerriet M. Denkmann
 

I have a Watch-App using SwiftUI.

let fontSize = 40.0
struct WatchContentView: View
{
@State var timeAttributedStr = AttributedString("--")
let timer = Timer.publish(every: 1, tolerance: 0.1, on: .main, in: .common).autoconnect()

var body: some View
{
VStack
{
Text(timeAttributedStr)
}
.onReceive(timer)
{ currentTime in

timeAttributedStr = … make from currentTime using fontSize …

// compare size of timeAttributedStr to window and decrease fontSize if needed
// no idea how to do this
}
}
}

The Problem:
I want to make fontSize as big as possible. And then do:
if timeAttributedStr.size.width > window.size.width then decrease fontSize

But sadly, AttributedString has no size.

A fixed fontSize is less than ideal, because the optimal timeAttributedStr will depend both on Locale and Watch model.

Gerriet.


Laurent Daudelin
 

Doesn’t AttributedString uses a dictionary to set its attributes, including font and font size?

-Laurent.
-- 
Laurent Daudelin   laurent@...
Skype: LaurentDaudelin
Logiciels Némésys Software   https://www.nemesys-soft.com/

On Nov 7, 2022, at 07:06, Gerriet M. Denkmann <gerriet@...> wrote:

I have a Watch-App using SwiftUI.

let fontSize = 40.0
struct WatchContentView: View
{
@State var timeAttributedStr = AttributedString("--")
let timer = Timer.publish(every: 1, tolerance: 0.1, on: .main, in: .common).autoconnect()

var body: some View
{
VStack
{
Text(timeAttributedStr)
}
.onReceive(timer)
{ currentTime  in

timeAttributedStr = … make from currentTime using fontSize …

//  compare size of timeAttributedStr to window and decrease fontSize if needed
// no idea how to do this
      }
}
}

The Problem:
I want to make fontSize as big as possible. And then do:
if timeAttributedStr.size.width > window.size.width then decrease fontSize

But sadly, AttributedString has no size.

A fixed fontSize is less than ideal, because the optimal timeAttributedStr will depend both on Locale and Watch model.

Gerriet.


Alex Zavatone
 

Would you use a sizeToFit or sizeThatFits method call to do that for you even after you’ve set the attributed text?

I have some old Objective-C libraries that I wrote for CVS to set iOS app text to their standard fonts.

Here’s a chunk of it.  You can see how I apply the font size to the dictionary.  Cheers!

   // Set base font & size.
    CGFloat fontSize = 20.0;
    UIFont *fnt = [UIFont fontWithName:@"Helvetica" size:fontSize]; // never initialize a font with a size of 0.0, or it will always be Helvetica

    

    // Define base string.
    NSString *myString;
    //myString = @"beauty club®"; // with R
    myString = @"beauty club™"; // with TM

    

    // Define base color and font definitions.

    

    fontSize = 24;
    UIColor *myBlue = [UIColor colorWithRed:.02 green:.48 blue:.66 alpha:1.0]; // Unused.  Kept as an example.
    UIColor *myPink = [UIColor colorWithRed:.93 green:.36 blue:.62 alpha:1.0];
    UIFont *thickFont = [UIFont fontWithName:@"HelveticaNeue-Bold" size:fontSize];
    UIFont *thinFont = [UIFont fontWithName:@"HelveticaNeue-Light" size:fontSize];
    thinFont = [UIFont fontWithName:@"HelveticaNeue-Medium" size:fontSize];

    

    // Define attributes dictionary for bold text.
    NSDictionary *boldAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                    thickFont, NSFontAttributeName,
                                    myPink, NSForegroundColorAttributeName,
                                    nil];

    

    // Find range of text to make bold.
    NSString *textToBeBoldAndPink = @"beauty";
    NSRange boldAndPinkRange = [myString rangeOfString:textToBeBoldAndPink];

    

    // Define attributes dictionary for thin text.
    NSDictionary *thinAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                    thinFont, NSFontAttributeName,
                                    myPink, NSForegroundColorAttributeName,
                                    nil];

    

    // Find range of text to make thin.
    NSString *textToBeThin;
    //        textToBeThin= @"club®"; // with R
    textToBeThin= @"club™"; // with TM
    NSRange thinTextRange = [myString rangeOfString:textToBeThin];

    

    

    // Make the basic attributed string
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:myString
                                                                                         attributes:@{NSFontAttributeName: [fnt fontWithSize:fontSize]}];

    

    // Apply bold and thin formatting to strings using appropriate ranges.
    [attributedString setAttributes:boldAttributes range:boldAndPinkRange];
    [attributedString setAttributes:thinAttributes range:thinTextRange];

    

    // AZ - find position of desired character to superscript in string
    NSString *charToFind;
    //charToFind = @"®"; // In case we are using R instead.  Just an example.
    charToFind = @"™"; // In case we are using TM instead.  Just an example.

    

    NSRange positionOfSuperscriptCharacter = [myString rangeOfString:charToFind];

    

    // Setting the point sizes using exact numbers
    //  NSInteger superscriptCharSize = 12;
    //  CGFloat pointsToRaiseBaseLineOfSupercriptChar = 8.0;
    //  UIColor *colorOfSuperText = myPink;
    //  NSNumber *characterBaselineOffsetUp = [NSNumber numberWithFloat:pointsToRaiseBaseLineOfSupercriptChar];

    

    // Set point size of superscript text relative to display font size as a percentage of original.
    CGFloat superscriptCharacterPercentOfFullsizeText = 0.60f; // 12 pt if original is 20 point
    NSInteger superscriptCharSize = fontSize * superscriptCharacterPercentOfFullsizeText ;

    

    // Set points to raise superscript text relative to font size as a percentage of original.

    

    CGFloat superscriptCharacterPercentOfFullsizeTextToRaiseChar = 0.40f; // 8 points if original is 20 point
    CGFloat pointsToRaiseBaseLineOfSupercriptChar = fontSize * superscriptCharacterPercentOfFullsizeTextToRaiseChar ;

    

    NSNumber *characterBaselineOffsetUp = [NSNumber numberWithFloat:pointsToRaiseBaseLineOfSupercriptChar];

    

    // Set color for text.
    UIColor *colorOfSuperText = myPink;

    

    // Set attributes to be applied to string.
    NSDictionary *superTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                         [fnt fontWithSize:superscriptCharSize], NSFontAttributeName,
                                         colorOfSuperText, NSForegroundColorAttributeName,
                                         characterBaselineOffsetUp, NSBaselineOffsetAttributeName,
                                         nil];

    

    // Apply the formatting for the superscript to the range of text for the string.
    [attributedString setAttributes:superTextAttributes range:positionOfSuperscriptCharacter];

    

    return attributedString;


On Nov 7, 2022, at 6:06 AM, Gerriet M. Denkmann <gerriet@...> wrote:

I have a Watch-App using SwiftUI.

let fontSize = 40.0
struct WatchContentView: View
{
@State var timeAttributedStr = AttributedString("--")
let timer = Timer.publish(every: 1, tolerance: 0.1, on: .main, in: .common).autoconnect()

var body: some View
{
VStack
{
Text(timeAttributedStr)
}
.onReceive(timer)
{ currentTime  in

timeAttributedStr = … make from currentTime using fontSize …

//  compare size of timeAttributedStr to window and decrease fontSize if needed
// no idea how to do this
      }
}
}

The Problem:
I want to make fontSize as big as possible. And then do:
if timeAttributedStr.size.width > window.size.width then decrease fontSize

But sadly, AttributedString has no size.

A fixed fontSize is less than ideal, because the optimal timeAttributedStr will depend both on Locale and Watch model.

Gerriet.