diff --git a/packages/capacitor-native-ui/ios/Sources/NativeUIPlugin/Components/NativeUIVerticalBars.swift b/packages/capacitor-native-ui/ios/Sources/NativeUIPlugin/Components/NativeUIVerticalBars.swift index cb74276c0..0b01de1cd 100644 --- a/packages/capacitor-native-ui/ios/Sources/NativeUIPlugin/Components/NativeUIVerticalBars.swift +++ b/packages/capacitor-native-ui/ios/Sources/NativeUIPlugin/Components/NativeUIVerticalBars.swift @@ -241,6 +241,8 @@ private struct NativeUIVerticalBarsView: View { TabView(selection: Binding(get: { model.selection }, set: { model.select($0) })) { ForEach(model.tabs) { item in NativeUIVerticalBarsPage(model: model) + // Keep toolbar and search accents independent of the tab selection. + .tint(nil) .tag(item.id) .tabItem { NativeUIVerticalBarsLabel(item: item) } .modifier(NativeUIVerticalBarsBadge(badge: item.badge)) @@ -249,6 +251,7 @@ private struct NativeUIVerticalBarsView: View { .accessibilityIdentifier(item.id) } } + .tint(model.tabTint.map { Color(uiColor: NativeUIRendering.color($0)) }) .modifier(NativeUIExtensionAccessory(content: model.accessory)) } } diff --git a/packages/capacitor-native-ui/ios/Tests/NativeUIPluginTests/NativeUISnapshotTests.swift b/packages/capacitor-native-ui/ios/Tests/NativeUIPluginTests/NativeUISnapshotTests.swift index 1bb40cc6e..ed4ea314b 100644 --- a/packages/capacitor-native-ui/ios/Tests/NativeUIPluginTests/NativeUISnapshotTests.swift +++ b/packages/capacitor-native-ui/ios/Tests/NativeUIPluginTests/NativeUISnapshotTests.swift @@ -52,7 +52,22 @@ final class NativeUISnapshotTests: XCTestCase { if let tabs = parent as? UITabBarController { return tabs } return parent.children.lazy.compactMap { tabController($0) }.first } + func assertTint(_ actual: UIColor?, _ expected: UIColor?, traits: UITraitCollection, + file: StaticString = #filePath, line: UInt = #line) throws { + func components(_ color: UIColor?) throws -> [CGFloat] { + let color = try XCTUnwrap(color, file: file, line: line).resolvedColor(with: traits) + var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0 + XCTAssertTrue(color.getRed(&red, green: &green, blue: &blue, alpha: &alpha), file: file, line: line) + return [red, green, blue, alpha] + } + // SwiftUI may resolve a dynamic UIColor into a different RGB color + // space with tiny rounding differences. Compare the rendered components. + for (actual, expected) in zip(try components(actual), try components(expected)) { + XCTAssertEqual(actual, expected, accuracy: 0.001, file: file, line: line) + } + } var systemTint: UIColor? + var controllerSystemTint: UIColor? for (index, tint) in ([nil, "rgb(255, 0, 0)", "rgb(255, 0, 0)", "rgb(128, 0, 128)", nil] as [String?]).enumerated() { var value = control(["kind": "tab-bar", "placement": "vertical-bars", "items": [ item(["id": "first", "label": "First", "selected": index % 2 == 0]), @@ -64,8 +79,16 @@ final class NativeUISnapshotTests: XCTestCase { rail.apply(try decode([value]).controls, rendering: NativeUIControlRendering(), edge: "right", animated: false) try await Task.sleep(nanoseconds: 500_000_000) let tabs = try XCTUnwrap(tabController(owner)) - if index == 0 { systemTint = tabs.tabBar.tintColor } - XCTAssertEqual(tabs.tabBar.tintColor, tint.map { NativeUIRendering.color($0) } ?? systemTint) + if index == 0 { systemTint = tabs.tabBar.tintColor; controllerSystemTint = tabs.view.tintColor } + try assertTint(tabs.tabBar.tintColor, tint.map { NativeUIRendering.color($0) } ?? systemTint, traits: tabs.traitCollection) + if tint == nil { + try assertTint(tabs.view.tintColor, controllerSystemTint, traits: tabs.traitCollection) + } + if let tint { + // On iOS 27.1, the visible SwiftUI rail follows its controller's + // accent; setting only the legacy UITabBar property leaves it blue. + try assertTint(tabs.view.tintColor, NativeUIRendering.color(tint), traits: tabs.traitCollection) + } XCTAssertEqual(tabs.selectedIndex, index % 2) XCTAssertEqual(tabs.traitCollection.userInterfaceStyle, index == 3 ? .dark : .light) XCTAssertNil(tabs.tabBar.items?.first?.standardAppearance, "Keep the native background and state appearances")