From fb2d2b5a887f285b97b2cfe837e10f03d49187d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Sat, 20 Jun 2026 17:06:25 +0200 Subject: [PATCH] Fix tab bar labels wrapping at large Dynamic Type sizes Pin the tab bar title font and icon to a fixed size so large accessibility text settings no longer wrap or truncate the labels. --- LoopFollow/Application/AppDelegate.swift | 27 ++++++++++++++++++++++++ LoopFollow/Application/MainTabView.swift | 19 +++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/LoopFollow/Application/AppDelegate.swift b/LoopFollow/Application/AppDelegate.swift index 6c9d8e884..395a244d3 100644 --- a/LoopFollow/Application/AppDelegate.swift +++ b/LoopFollow/Application/AppDelegate.swift @@ -13,6 +13,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { LogManager.shared.log(category: .general, message: "App started") LogManager.shared.cleanupOldLogs() + configureTabBarAppearance() + let options: UNAuthorizationOptions = [.alert, .sound, .badge] notificationCenter.requestAuthorization(options: options) { didAllow, _ in @@ -87,6 +89,31 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } + // MARK: - Tab bar appearance + + /// Pin the tab bar item titles to a fixed, non-scaling font so large + /// Dynamic Type sizes don't wrap or truncate the labels. + private func configureTabBarAppearance() { + // 10pt medium matches the system default tab bar label. + let titleFont = UIFont.systemFont(ofSize: 10, weight: .medium) + let attributes: [NSAttributedString.Key: Any] = [.font: titleFont] + + func apply(to itemAppearance: UITabBarItemAppearance) { + itemAppearance.normal.titleTextAttributes = attributes + itemAppearance.selected.titleTextAttributes = attributes + itemAppearance.disabled.titleTextAttributes = attributes + itemAppearance.focused.titleTextAttributes = attributes + } + + let appearance = UITabBarAppearance() + apply(to: appearance.stackedLayoutAppearance) + apply(to: appearance.inlineLayoutAppearance) + apply(to: appearance.compactInlineLayoutAppearance) + + UITabBar.appearance().standardAppearance = appearance + UITabBar.appearance().scrollEdgeAppearance = appearance + } + // MARK: - BFU recovery @objc private func protectedDataDidBecomeAvailable() { diff --git a/LoopFollow/Application/MainTabView.swift b/LoopFollow/Application/MainTabView.swift index 140204358..f6c652746 100644 --- a/LoopFollow/Application/MainTabView.swift +++ b/LoopFollow/Application/MainTabView.swift @@ -25,7 +25,7 @@ struct MainTabView: View { ForEach(Array(orderedItems.prefix(4).enumerated()), id: \.element) { index, item in tabContent(for: item) .tabItem { - Label(item.displayName, systemImage: item.icon) + tabLabel(item.displayName, systemImage: item.icon) } .tag(index) } @@ -34,7 +34,7 @@ struct MainTabView: View { MoreMenuView() } .tabItem { - Label("Menu", systemImage: "line.3.horizontal") + tabLabel("Menu", systemImage: "line.3.horizontal") } .tag(4) } @@ -62,6 +62,21 @@ struct MainTabView: View { } } + /// Tab bar label with a fixed-size icon so large Dynamic Type sizes don't + /// grow the symbol and squeeze the title. The title font is pinned in AppDelegate. + private func tabLabel(_ title: String, systemImage: String) -> some View { + Label { + Text(title) + } icon: { + let config = UIImage.SymbolConfiguration(pointSize: 24, weight: .regular) + if let image = UIImage(systemName: systemImage, withConfiguration: config) { + Image(uiImage: image.withRenderingMode(.alwaysTemplate)) + } else { + Image(systemName: systemImage) + } + } + } + @ViewBuilder private func tabContent(for item: TabItem) -> some View { switch item {