Support text scaling
On Android, you can use Scale-independent Pixels to scale text. This unit ensures that the user's preferences are taken into account when determining the font size. We recommend to define the textSize in your styles to make sure it's the same everywhere.
xml
<style name="Widget.TextView">
<item name="android:textSize">18sp</item>
</style> In Jetpack Compose, you can use Scale-independent Pixels to scale text. This unit ensures that the user's preferences are taken into account when determining the font size. We recommend to define the fontSize) property inside the Typography object in your code to ensure consistency throughout your app.
You can use the @PreviewFontScale annotation to preview different font scales.
kotlin
val typography = Typography(
titleLarge = TextStyle(
fontSize = 20.sp,
),
bodyLarge = TextStyle(
fontSize = 16.sp,
),
headlineLarge = TextStyle(
fontSize = 20.sp,
),
)
@FontScalePreviews
@Composable
fun fontScalePreviews() {
Text(text = "This is font scale ${LocalDensity.current.fontScale}")
} On iOS, you can use Dynamic Type to scale text. By using this function, the font size is adjusted to the preferences of the user. If you're using your own font, you can use the scaledFont method from UIFontMetrics to calculate the font size.
Text elements such as UILabel, UITextField and UITextView have a property called adjustsFontForContentSizeCategory. If you set it to true, the element automatically updates its font when the device's content size category changes.
For adjustsFontForContentSizeCategory to take effect, the element’s font must be one of the following:
- A font vended using
preferredFont(forTextStyle:)orpreferredFont(forTextStyle:compatibleWith:)with a validUIFont.TextStyle - A font vended using
UIFontMetrics.scaledFont(for:)or one of its variants
swift
// MARK: - Scaling custom fonts
import UIKit
extension UIFont {
static func font(name: String, size: CGFloat, style: TextStyle) -> UIFont {
guard let font = UIFont(name: name, size: size) else {
fatalError("Font \(name) does not exist")
}
return UIFontMetrics(forTextStyle: style).scaledFont(for: font)
}
static func openSans(weight: UIFont.Weight, size: CGFloat, style: TextStyle) -> UIFont {
if UIAccessibility.isBoldTextEnabled {
return font(name: "OpenSans-Bold", size: size, style: style)
}
switch weight {
case .regular:
return font(name: "OpenSans-Regular", size: size, style: style)
case .semibold:
return font(name: "OpenSans-SemiBold", size: size, style: style)
case .bold:
return font(name: "OpenSans-Bold", size: size, style: style)
default:
fatalError("Font weight \(weight) is not supported")
}
}
}
// MARK: - Enabling content size category adjustments
label.adjustsFontForContentSizeCategory = true swift
button.showsLargeContentViewer = true
button.addInteraction(UILargeContentViewerInteraction()) In SwiftUI, scaling text to match the user's preferred content size is straightforward. SwiftUI automatically supports Dynamic Type, which means your text will adapt to the user's preferred font size set in the device settings.
swift
Text("Appt")
// Scales text automatically
.font(.title) swift
var body: some View {
Text("Appt")
.scaledFont(name: "Roboto-Regular", size: 24)
}
struct ScaledFont: ViewModifier {
var name: String
var size: CGFloat
var relativeTo: Font.TextStyle
func body(content: Content) -> some View {
content
.font(.custom(name,
size: size,
relativeTo: relativeTo))
}
}
extension View {
func scaledFont(name: String,
size: CGFloat,
relativeTo: Font.TextStyle = .body) -> some View {
self.modifier(ScaledFont(name: name,
size: size,
relativeTo: relativeTo))
}
} swift
var body: some View {
Button("Appt", action: action)
.accessibilityShowsLargeContentViewer()
} Flutter automatically scales the text on the screen to the text size set by the user. We recommend using ThemeData to use the same text sizes and fonts everywhere.
Try to avoid using the setter of textScaler property because it overrides the text scale factor preferred by the user. The default factor is 1.0, but can go as high as 4.0 for some users. Restricting the number means that some users might not be able to read the text.
There are valid use cases to restrict the text scale to a certain number. You can use MediaQuery to override the value globally. You can also override it for a single use case by using the property inside a Text widget.
dart
// Override scale for all widgets
MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaler: const TextScaler.linear(1.0)
// or
textScaler: TextScaler.noScaling,
),
child: ...,
);
//or even shorter
MediaQuery.withNoTextScaling(
child: ...,
)
// Override scale for a single widget
Text(
'Appt',
textScaler: TextScaler.noScaling,
); dart
LargeContentViewer(
scaleFactor: 2.5, // Child will scale 2.5x on long press
child: IconButton(
icon: Icon(Icons.settings),
onPressed: () {
// Action
},
tooltip: 'Settings',
),
) React Native automatically scales text depending on the font size preferences of the user settings. In addition, all dimensions in React Native are unitless, and represent density-independent pixels.
Try to avoid using properties such as maxFontSizeMultiplier, allowFontScaling, adjustsFontSizeToFit and numberOfLines. Using these properties may cause text to be unscalable or become inaccessible.
When inheriting a project you may find previous developers have disabled font-scaling with the following code: Text.defaultProps.allowFontScaling = false;. This is accessibility anti-pattern and should be rolled back.
The code example below shows how to have a scaling font size.
jsx
<Text style={{ fontSize: 16 }}>
Appt
</Text> In MAUI, all controls that display text automatically apply font scaling. The scale is based on the font size preference set in the Android or iOS operating system.
By default, .NET MAUI apps use the Open Sans font on each platform. However, this default can be changed by registering additional fonts in your app.
You can find additional guidance in the .NET MAUI fonts article.
csharp
<Label Text="Appt"
FontSize="18"
FontAutoScalingEnabled="True"
FontFamily="Custom" /> In Xamarin Forms you make styles for the scalable fonts that you use in your app.
First, accessibility scaling should be enabled for named font sizes. This can be done by pass True to the the SetEnableAccessibilityScalingForNamedFontSizes) method of the Application. This can also be done in XAML by using ios:Application.EnableAccessibilityScalingForNamedFontSizes="true".
Secondly, you have to register the font and it's properties with the assembly. Afterwards, the fonts can be used in your app and they will automatically scale depending on the users' font size preference.
For more information, see Understand named font sizes, Named font size scaling and Dynamic Styles.
The code examples below shows how to enable font size scaling and how to use dynamic styles.
csharp
using Xamarin.Forms;
[assembly: ExportFont("Lobster-Regular.ttf", Alias="Lobster")]
[assembly: ExportFont("Lobster-Bold.ttf", Alias="LobsterBold")]
namespace Project
{
public partial class App : Xamarin.Forms.Application
{
On<Xamarin.Forms.PlatformConfiguration.iOS>().SetEnableAccessibilityScalingForNamedFontSizes(true);
}
} xml
<Application
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Application.EnableAccessibilityScalingForNamedFontSizes="true">
</Application>
<Style TargetType="Entry">
<Setter Property="FontFamily" Value="Lobster" />
</Style>
<Style
x:Key="LabelRegular"
ApplyToDerivedTypes="True"
BaseResourceKey="BodyStyle"
TargetType="Label">
<Setter Property="TextColor" Value="Black" />
<Setter Property="FontFamily" Value="Lobster" />
<Setter Property="FontSize" Value="{DynamicResource Body}" />
<!-- For Android you have to set FontSize property -->
</Style>
<Style
x:Key="LabelBold"
ApplyToDerivedTypes="True"
BaseResourceKey="LabelRegular"
TargetType="Label">
<Setter Property="FontFamily" Value="LobsterBold" />
<Setter Property="FontAttributes">
</Style> Prevent text truncation
On Android, you can avoid text truncation by removing all instances of android:maxLines from your app. You should also avoid using fixed values for any heights or widths and instead use wrap_content where possible.
xml
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Avoid text truncation"
android:maxLines="REMOVE" /> In Jetpack Compose, you can avoid text truncation by removing all instances of maxLines) from your app. You should also avoid using fixed values for any heights or widths.
kotlin
Text(
text = "Appt",
maxLines = 1 // Do not set maxLines
)
Column(
modifier = Modifier
.width(100.dp) // Do not use fixed width
.height(100.dp) // Do not use fixed height
) {
// Content
} On iOS, you can avoid text truncation by seting the numberOfLines property to 0 on your UILabel. You should also avoid using fixed values for any heights or widths and instead use constraints and self-sizing.
swift
let label = UILabel()
label.text = "Avoid text truncation"
label.numberOfLines = 0 In SwiftUI, Text views expand to multiple lines by default. To ensure that Text views display without truncation, verify that you haven't set a lineLimit-513mb).
To further avoid text truncation, especially when the text content exceeds the available screen space, it's recommended to place the Text view inside a scrollable container like a ScrollView.
swift
ScrollView {
VStack {
Text("Appt")
// Other views
}
} In Flutter, you can avoid text truncation by removing all instances of maxLines from your app. You should also set overflow to TextOverflow.visible where needed. Lastly, avoid using fixed values for any heights or widths.
dart
Text(
'Avoid text truncation',
maxLines: REMOVE,
overflow: TextOverflow.visible
) In React Native, you can avoid text truncation by removing all instances of numberOfLines from you rapp.
jsx
<Text numberOfLines="{REMOVE}">
Avoid text truncation
</Text> In MAUI, the Label component has the MaxLines property set to -1 by default, making labels not truncated. You can modify this behavior by changing the MaxLines property to a specific number.
xml
<Label
Text="Avoid text truncation"
MaxLines="-1" /> When using Xamarin.Forms, you can avoid text truncation by removing all instances of MaxLines from your app.
xml
<Label
Text="Avoid text truncation"
MaxLines="REMOVE" />