iOS Swift: maximumContentSizeCategory not working on UILabel - ios

According to this article:
https://useyourloaf.com/blog/restricting-dynamic-type-sizes/
And this WWDC 2021 video:
https://developer.apple.com/videos/play/wwdc2021/10059/?time=879
The minimumContentSizeCategory and maximumContentSizeCategory can limit the min and max font size when user uplevel/downlevel the font sizes in System Accessibility settings.
However I tried it out, and from the debugging info these two settings are properly set, but in view rendering, the font size still goes to very large if accessibility font size is very large.
// before setting
print(label.appliedContentSizeCategoryLimitsDescription)
label.minimumContentSizeCategory = .small
label.maximumContentSizeCategory = .accessibilityMedium
// after setting
print(label.appliedContentSizeCategoryLimitsDescription)
print results:
UILabel:0x7fd610a414a0: AX-L
--> AX-L
UILabel:0x7fd610a414a0: S <= (none->)AX-M <= AX-M
--> AX-M
How can I properly use these two settings?

Any ideas on how to properly use these two settings?
I hope that's the proper way because I use them as you did (and it works).
I created a blank project in Interface Builder (Xcode 13.4.1) as follows:
... and the Dynamic Type feature is blocked within the specified thresholds I defined like you (in the viewDidLoad of the view controller).
I think you should check out the way you created your label because, with the above one, it works like a charm.

Related

Programmatically Collapse NavigationSplitView to One Column

I have developed a SwiftUI NavigationSplitView app with two columns and it works as expected.
I have chosen dynamic fonts and crafted the visual elements to respond to user settings
for visual accessibility. I know that a number of the users who will employ this app will have
the font size set to the largest available. While that enhances their view of the detail
screen, it pretty much makes the sidebar unreadable. I'm trying to find a way to change
the app's behavior based on the size of the dynamic type. Specifically, I'd like to have
the iPad behavior the same as an iPhone behavior based on a font size that I define.
As it is, the app on an iPhone collapses to a single column. I have not been able to
find a way to programmatically do this on an iPad.
I have tried:
Setting the horizontalSizeClass and as expected, this is a getter only.
.horizontalSizeClass = .compact
I have tried setting the column width of the detail to 0.
.navigationSplitViewColumnWidth(0)
that does not work
I have tried using the old stack function.
.navigationViewStyle(StackNavigationViewStyle())
that does not work.
Clearly, this can be done, since it is automatic when the device is an iPhone. I guess
I could create two views - one stacked and one split and choose based on a State variable
but that seems a bit crude.
Any guidance would be appreciated. Xcode 14 beta 6, iOS 16
This is a great idea and can be achieved by overriding the horizontalSizeClass in the environment depending on the environment value of dynamicTypeSize as follows:
struct NavigationSplitViewTest: View {
#Environment(\.dynamicTypeSize) var dynamicTypeSize
var body: some View {
ViewContainingSplitView()
.environment(\.horizontalSizeClass, dynamicTypeSize > .large ? .compact : .none)
}
}
I tested it by launching the app on iPad simulator and it was in 2 column, then switching to Settings to increase the type size by one notch then back to app and it had switched to single column. However when attempting to switch the size back I noticed the show/hide column button disappeared so I think we have some feedback to submit.
I still have not found an elegant way to do this, but my solution here does work.
Basically, I code for NavigationSplitView and for NavigationStack and change based on the
Environment(.dynamicTypeSize). Like this:
if dynamicTypeSize <= .xxLarge {
NavigationSplitView(columnVisibility: $columnVisibility) {
//all the code
} detail: {
//all the code
}
} else {
NavigationStack {
//all the code
}
}
For others, I was confused by the terms involved here. There is DynamicTypeSize, dynamic
fonts and Larger Accessibility Sizes. Dynamic fonts are those pre-built fonts that
support dynamic type out of the box - .title, .headline, .body etc. Dynamic type size is
the slider in settings that allows the user to scale the dynamic fonts to suit their
needs - all the dynamic fonts scale with the slider setting. Then on top of the slider
in settings for these pre-made fonts, is the option for Larger Accessibility sizes
which gives the user even bigger options.
My scheme above supports all of those intermingled options for both iPad and iPhone.

Swift - Strange text rendering at runtime

I am working on an iOS app right now. I usually use the Interface Builder and recently it has been producing an issue. When the storyboard is seen in Xcode the labels on everything look fine, but some UI elements don't render properly at runtime. This has also happened for some of the images in this project. The only font used is the system font.
I have tried readjusting the font and using attributed text, but this hasn't worked for the specific label shown. Just to mention, this app is a shared project through Git so it may be an issue with it pulling incorrectly or something, but that seems odd for it to affect the text after it has been changed and adjusted.
View post on imgur.com
The results should be crystal clear text on iOS, but it results in "fuzzy" text you would expect if you were running the Windows XP on a 480p screen. What could be causing this issue?
It seems like the layer of a superview of the UILabel in the provided image is set to pre-render. This is good for performance reasons but may not always look as good, as is seen here.
If you're setting a custom layer on a superview of the UILabel, try setting the layer's shouldRasterize to false.
Ex: exampleLayer.shouldRasterize = false

How to handle a change in system level font size on iOS with React Native?

We have a situation where if a user decides to increase the "Larger Text" size in iOS Settings (see image below), it then messes up our view layouts in React Native, as the font size will now be larger.
For example here is a ListView row BEFORE changing the "Larger Text" setting in iOS system settings:
And here is the same row AFTER increasing the "Larger Text" setting:
What is best practice to handle such font scale increase in React Native ? This is obviously just one example, and there are other scenario's such as a View that only contains Text, but we do not want to increase the height of that View at runtime.
Appreciate anyone's advice on this, thanks!
You can do the following to block such changes (do it on your root js file):
Text.defaultProps.allowFontScaling = false;
you could use ITEM_SIZE * PixelRatio.getFontScale()

How to get iOS font size and set it to all labels of the app?

I want to make an app, where font size increase or decrease according to font size maintained in iOS in Settings. If you change font size of your iOS from settings, whatsapp font size displayed accordingly, I want same functionality.
The iOS functionality you're looking for is the Dynamic Type that only works for text with implemented text styles.
Basically, you must :
Use the text styles but beware, their availability depends on your iOS version.
Tick the adjustsFontForContentSizeCategory property (since iOS 10) in your interface builder or implement it in code so as to tell the system to handle automatically the Dynamic Type for the object it belongs to (text styles must be used of course).
Adapt all your constraints to the different sizes your app may encounter.
You can also follow the notifications related to the Dynamic Typeevents as indicated below :
Everything is well explained in this WWDC video detailed summary where all the contents and their video timelapses are indicated to reach rapidly the information.
There's also the possibility of adapting the graphical elements size as well with a Dynamic Type implementation.
All you have to do if to use Dynamic Type for your labels. This means not to set it explicitly but to use styles like Header 1 or caption. This styles are depends on user setting in Accessibility and will change automatically. https://www.raywenderlich.com/77092/text-kit-tutorial-swift
You can use system default sizes for Texts, like,
self.label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
Please find documentation here.
For other components you can use like labelFontSize() and many more,
+ (CGFloat)labelFontSize;//Returns the standard font size used for labels.
+ (CGFloat)buttonFontSize;//Returns the standard font size used for buttons.
+ (CGFloat)smallSystemFontSize;//Returns the size of the standard small system font.
+ (CGFloat)systemFontSize;//Returns the size of the standard system font.

Automatic Preferred Max Layout Width is not available on iOS versions prior to 8.0

I opened an existing iOS project with Xcode6 beta6, and Xcode lists the following warning for both Storyboard and Xib files:
Automatic Preferred Max Layout Width is not available on iOS versions
prior to 8.0
I tried addressing the warning by setting the width as explicit like below:
Yet this didn't resolve the warnings. How can they be removed?
Update 3:
This warning can also be triggered by labels that have numberOfLines set to anything but 1 if your deployment target is set to 7.1. This is completely reproducible with new single-view project.
Steps to Reproduce:
Create a new single-view, objective-c project
Set the Deployment Target to 7.1
Open the project's storyboard
Drop a label onto the provided view controller
Set the numberOfLines for that label to 2.
Compile
I've filed the following radar:
rdar://problem/18700567
Update 2:
Unfortunately, this is a thing again in the release version of Xcode 6. Note that you can, for the most part, manually edit your storyboard/xib to fix the problem. Per Charles A. in the comments below:
It's worth mentioning that you can pretty easily accidentally
introduce this warning, and the warning itself doesn't help in finding
the label that is the culprit. This is unfortunate in a complex
storyboard. You can open the storyboard as a source file and search
with the regex <label(?!.*preferredMaxLayoutWidth) to find labels that
omit a preferredMaxLayoutWidth attribute/value. If you add in
preferredMaxLayoutWidth="0" on such lines, it is the same as marking
explicit and setting the value 0.
Update 1:
This bug has now been fixed in Xcode 6 GM.
Original Answer
This is a bug in Xcode6-Beta6 and XCode6-Beta7 and can be safely ignored for now.
An Apple engineer in the Apple Developer forums had this to say about the bug:
Preferred max layout width is an auto layout property on UILabel that
allows it to automatically grow vertically to fit its content.
Versions of Xcode prior to 6.0 would set preferredMaxLayoutWidth for
multiline labels to the current bounds size at design time. You would
need to manually update preferredMaxLayoutWidth at runtime if your
horizontal layout changed.
iOS 8 added support for automatically computing
preferredMaxLayoutWidth at runtime, which makes creating multiline
labels even easier. This setting is not backwards compatible with iOS
7. To support both iOS 7 and iOS 8, Xcode 6 allows you to pick either "Automatic" or "Explicit" for preferredMaxLayoutWidth in the size
inspector. You should:
Pick "Automatic" if targeting iOS 8 for the best experience. Pick
"Explicit" if targeting < iOS 8. You can then enter the value of
preferredMaxLayoutWidth you would like set. Enabling "Explicit"
defaults to the current bounds size at the time you checked the box.
The warning will appear if (1) you're using auto layout, (2)
"Automatic" is set for a multiline label [you can check this in the
size inspector for the label], and (3) your deployment target < iOS 8.
It seems the bug is that this warning appears for non-autolayout
documents. If you are seeing this warning and not using auto layout
you can ignore the warning.
Alternately, you can work around the issue by using the file inspector on the storyboard or xib in question and change "Builds for" to "Builds for iOS 8.0 and Later"
To Find the problem label(s) in a large storyboard, follow my steps below.
In xCode's Issue Navigator right click on the error and select "Reveal In Log". (Note: #Sam suggests below, look in xCode's report navigator. Also #Rivera notes in the comments that "As of Xcode 6.1.1, clicking on the warning will automatically open and highlight the conflicting label". I haven't tested this).
This will show the error with a code at the end of your storyboard file. Copy the value after .storyboard
Next, reveal your storyboard as source file.
Search. You should be able to tell what label it is from here quite easily by looking at the content.
Once you find the label the solution that worked for me was to set the "preferred width" to 0.
BTW, you can always quickly get the id of an interface item by selecting the item and looking under the identify inspector. Very handy.
You can fix this issue without opening the storyboard as a source.
This warning is triggered by UILabels if numberOfLines !=1 and deployment target is < 8.0
HOW TO FIND IT?
Go to Issue Navigator (CMD+8) and Select latest built with the warning
Locate the warning(s) (search for "Automatic Preferred Max Layout") and press expand button on the right
Find the Object ID of the UILabel
Open the Storyboard and SEARCH (CMD+f) for the object. It will SELECT AND HIGHLIGHT the UILabel
Set Preferred Width = 0 "Explicit" as others suggested
Solution it's quite simple
Just enable Builds for iOS 8 and Later
Now my Xcode version is 6.1. But I got this warning too. it annoys me a lot . after search again and again.I found the solution.
Reason:You must have set your UILabel Lines > 1 in your Storyboard.
Solution: set your UILabel Lines attribute to 1 in Storyboard. restart your Xcode. It works for me, hope it can help more people.
If you really need to show your words more than 1 line. you should do it in the code.
//the words will show in UILabel
NSString *testString = #"Today I wanna set the line to multiple lines. bla bla ...... Today I wanna set the line to multiple lines. bla bla ......"
[self.UserNameLabel setNumberOfLines:0];
self.UserNameLabel.lineBreakMode = NSLineBreakByWordWrapping;
UIFont *font = [UIFont systemFontOfSize:12];
//Here I set the Label max width to 200, height to 60
CGSize size = CGSizeMake(200, 60);
CGRect labelRect = [testString boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName] context:nil];
self.UserNameLabel.frame = CGRectMake(self.UserNameLabel.frame.origin.x, self.UserNameLabel.frame.origin.y, labelRect.size.width, labelRect.size.height);
self.UserNameLabel.text = testString;
To summarize, for me following the two instructions above to change any instances where numberOfLines = 0 to 1 or greater, and manually adding preferredMaxLayoutWidth="0" to each instance of a label inside the storyboard source fixed all of my warnings.
Since I don't have a 50 reputation Stackoverflow wont let me comment on the second best answer. Found another trick for finding the culprit label in the Storyboard.
So once you know the id of the label, open your storyboard in a seperate tab with view controllers displayed and just do command F and command V and will take you straight to that label :)
I got it working by selecting the original layout I had in the W / H selection. Storyboard is working as expected and the error is gone.
Be also sure that you are developing for iOS 8.0. Check that from the project's general settings.
This is where you should press.
I had this issue and was able to fix it by adding constraints to determine the max with for a label.
When dropping a multiline label in there is not constraint set to enforce the width inside the parent view. This is where the new PreferredMaxWidth comes into play. On iOS 7 and earlier you have to define the max width yourself. I simply added a 10px constraint to the left and right hand side of the label.
You can also add a <= width constraint which also fixes the issue.
So this is not actually a bug, you simply have to define the max width yourself. The explicit option mention in other answer will also work as you are setting this width value however you will have to modify this value if you want the max width to change based on the parent width (as you have explicitly set the width).
My above solution ensures the width is always maintained no matter how big the parent view is.
For some reason, even if changing the iOS Deployment Target to 8.0 or higher, the Xib files don't adopt that change and remain with the previous settings in the File inspector
Therefore, you should change it manually for each Xib
Once done, the warning will disappear :-)

Resources