Skip to content

Commit b8effab

Browse files
committed
fix: appearance handling on iOS
1 parent 7b761e6 commit b8effab

File tree

3 files changed

+62
-75
lines changed

3 files changed

+62
-75
lines changed

ios/Extensions.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,16 @@ extension UIImage {
3737
return resizedImage
3838
}
3939
}
40+
41+
extension View {
42+
@ViewBuilder
43+
func introspectTabView(closure: @escaping (UITabBarController) -> Void) -> some View {
44+
self
45+
.introspect(
46+
.tabView,
47+
on: .iOS(.v14, .v15, .v16, .v17, .v18),
48+
.tvOS(.v14,.v15, .v16, .v17, .v18),
49+
customize: closure
50+
)
51+
}
52+
}

ios/TabItemEventModifier.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,9 @@ struct TabItemEventModifier: ViewModifier {
1818

1919
func body(content: Content) -> some View {
2020
content
21-
.introspect(.tabView, on: .iOS(.v14, .v15, .v16, .v17, .v18)) { tabController in
21+
.introspectTabView(closure: { tabController in
2222
handle(tabController: tabController)
23-
}
24-
.introspect(.tabView, on: .tvOS(.v14, .v15, .v16, .v17, .v18)) { tabController in
25-
handle(tabController: tabController)
26-
}
23+
})
2724
}
2825

2926
func handle(tabController: UITabBarController) {

ios/TabViewImpl.swift

Lines changed: 47 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import Foundation
22
import SwiftUI
33
import React
4+
@_spi(Advanced) import SwiftUIIntrospect
5+
46

57
/**
68
Props that component accepts. SwiftUI view gets re-rendered when ObservableObject changes.
@@ -52,6 +54,8 @@ struct TabViewImpl: View {
5254
@ObservedObject var props: TabViewProps
5355
var onSelect: (_ key: String) -> Void
5456
var onLongPress: (_ key: String) -> Void
57+
@Weak var tabBar: UITabBar?
58+
5559

5660
var body: some View {
5761
TabView(selection: $props.selectedPage) {
@@ -72,9 +76,15 @@ struct TabViewImpl: View {
7276
emitHapticFeedback()
7377
}
7478
})
79+
.introspectTabView(closure: { tabController in
80+
tabBar = tabController.tabBar
81+
})
82+
.onChange(of: tabBar) { newValue in
83+
updateTabBarAppearance(props: props, tabBar: tabBar)
84+
}
85+
.configureAppearance(props: props, tabBar: tabBar)
7586
.tintColor(props.selectedActiveTintColor)
7687
.getSidebarAdaptable(enabled: props.sidebarAdaptable ?? false)
77-
.configureAppearance(props: props)
7888
.onChange(of: props.selectedPage ?? "") { newValue in
7989
if (props.disablePageAnimations) {
8090
UIView.setAnimationsEnabled(false)
@@ -136,66 +146,6 @@ struct TabViewImpl: View {
136146
}
137147
}
138148

139-
@available(iOS 15.0, *)
140-
private func configureAppearance(for appearanceType: String, appearance: UITabBarAppearance) -> UITabBarAppearance {
141-
if (appearanceType == "transparent") {
142-
return appearance
143-
}
144-
145-
switch appearanceType {
146-
case "opaque":
147-
appearance.configureWithOpaqueBackground()
148-
default:
149-
appearance.configureWithDefaultBackground()
150-
}
151-
152-
UITabBar.appearance().scrollEdgeAppearance = appearance
153-
154-
return appearance
155-
}
156-
157-
private func setTabBarItemColors(_ itemAppearance: UITabBarItemAppearance, inactiveColor: UIColor) {
158-
itemAppearance.normal.iconColor = inactiveColor
159-
itemAppearance.normal.titleTextAttributes = [.foregroundColor: inactiveColor]
160-
}
161-
162-
private func configureAppearance(inactiveTint inactiveTintColor: UIColor?, appearance: UITabBarAppearance) -> UITabBarAppearance {
163-
// @see https://stackoverflow.com/a/71934882
164-
if let inactiveTintColor {
165-
setTabBarItemColors(appearance.stackedLayoutAppearance, inactiveColor: inactiveTintColor)
166-
setTabBarItemColors(appearance.inlineLayoutAppearance, inactiveColor: inactiveTintColor)
167-
setTabBarItemColors(appearance.compactInlineLayoutAppearance, inactiveColor: inactiveTintColor)
168-
}
169-
170-
return appearance
171-
}
172-
173-
private func updateTabBarAppearance(props: TabViewProps) {
174-
var appearance = UITabBarAppearance()
175-
appearance = configureAppearance(
176-
inactiveTint: props.inactiveTintColor,
177-
appearance: appearance
178-
)
179-
180-
181-
if #available(iOS 15.0, *) {
182-
appearance = configureAppearance(for: props.scrollEdgeAppearance ?? "", appearance: appearance)
183-
184-
if props.translucent == false {
185-
appearance.configureWithOpaqueBackground()
186-
}
187-
188-
if props.barTintColor != nil {
189-
appearance.backgroundColor = props.barTintColor
190-
}
191-
} else {
192-
UITabBar.appearance().barTintColor = props.barTintColor
193-
UITabBar.appearance().isTranslucent = props.translucent
194-
}
195-
196-
UITabBar.appearance().standardAppearance = appearance
197-
}
198-
199149
struct TabItem: View {
200150
var title: String?
201151
var icon: UIImage?
@@ -215,6 +165,36 @@ struct TabItem: View {
215165
}
216166
}
217167

168+
private func updateTabBarAppearance(props: TabViewProps, tabBar: UITabBar?) {
169+
guard let tabBar else { return }
170+
171+
if (props.scrollEdgeAppearance == "transparent") {
172+
tabBar.barTintColor = props.barTintColor
173+
tabBar.isTranslucent = props.translucent
174+
tabBar.unselectedItemTintColor = props.inactiveTintColor
175+
return
176+
}
177+
178+
let appearance = UITabBarAppearance()
179+
appearance.configureWithDefaultBackground()
180+
appearance.backgroundColor = props.barTintColor
181+
182+
if let inactiveTintColor = props.inactiveTintColor {
183+
let itemAppearance = UITabBarItemAppearance()
184+
itemAppearance.normal.iconColor = inactiveTintColor
185+
itemAppearance.normal.titleTextAttributes = [.foregroundColor: inactiveTintColor]
186+
187+
appearance.stackedLayoutAppearance = itemAppearance
188+
appearance.inlineLayoutAppearance = itemAppearance
189+
appearance.compactInlineLayoutAppearance = itemAppearance
190+
}
191+
192+
tabBar.standardAppearance = appearance
193+
if #available(iOS 15.0, *) {
194+
tabBar.scrollEdgeAppearance = appearance.copy()
195+
}
196+
}
197+
218198
extension View {
219199
@ViewBuilder
220200
func getSidebarAdaptable(enabled: Bool) -> some View {
@@ -268,25 +248,22 @@ extension View {
268248
}
269249

270250
@ViewBuilder
271-
func configureAppearance(props: TabViewProps) -> some View {
251+
func configureAppearance(props: TabViewProps, tabBar: UITabBar?) -> some View {
272252
self
273-
.onAppear() {
274-
updateTabBarAppearance(props: props)
275-
}
276253
.onChange(of: props.barTintColor) { newValue in
277-
updateTabBarAppearance(props: props)
254+
updateTabBarAppearance(props: props, tabBar: tabBar)
278255
}
279256
.onChange(of: props.scrollEdgeAppearance) { newValue in
280-
updateTabBarAppearance(props: props)
257+
updateTabBarAppearance(props: props, tabBar: tabBar)
281258
}
282259
.onChange(of: props.translucent) { newValue in
283-
updateTabBarAppearance(props: props)
260+
updateTabBarAppearance(props: props, tabBar: tabBar)
284261
}
285262
.onChange(of: props.inactiveTintColor) { newValue in
286-
updateTabBarAppearance(props: props)
263+
updateTabBarAppearance(props: props, tabBar: tabBar)
287264
}
288265
.onChange(of: props.selectedActiveTintColor) { newValue in
289-
updateTabBarAppearance(props: props)
266+
updateTabBarAppearance(props: props, tabBar: tabBar)
290267
}
291268
}
292269

0 commit comments

Comments
 (0)