Im trying to get midX position of Button, but it always gives me unexpected result. I have tried to use .global, .local. and .named coordinate spaces but it still don't work. Maybe there is another way to get coordinates of UI element without GeometryReader The curve center should be in the center of selected button.

struct CoreTabBar: View {
@State var selectedTab: Tab = .home
@State private var xAxis: CGFloat = 0
private let home: AnyView
private let search: AnyView
private let media: AnyView
init(
home: AnyView,
search: AnyView,
media: AnyView
) {
self.home = home
self.search = search
self.media = media
}
var body: some View {
ZStack(alignment: .center) {
TabView(selection: $selectedTab) {
switch selectedTab {
case .home:
home
.ignoresSafeArea()
case .search:
search
.ignoresSafeArea()
case .media:
media
.ignoresSafeArea()
}
}
VStack {
Spacer()
HStack(spacing: 0) {
ForEach(Tab.allCases, id: \.self) { tab in
if tab == .search { Spacer(minLength: 0) }
GeometryReader { proxy in
Button {
selectedTab = tab
xAxis = proxy.frame(in: .named("TabBar")).midX
} label: {
Image(systemName: tabImage(tab))
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width: 25, height: 25)
.foregroundColor(tab == selectedTab ? Color.blue : Color.gray)
.coordinateSpace(name: "Button")
}
.onAppear {
}
}
.frame(width: 25, height: 25)
if tab == .search { Spacer(minLength: 0) }
}
}
.coordinateSpace(name: "TabBar")
.padding(.horizontal, 60)
.padding(.vertical)
.background(Color.white.clipShape(TabBarShape(xAxis: self.xAxis)))
.cornerRadius(50)
.padding(.horizontal, idiomIsPhone() ? nil : tabBarHorizontalPaddingForIpad())
Spacer()
.frame(height: 5)
}
}
}
It seems to work just fine with .global coordinates. See my demo below. Maybe there is a problem with the use of xAxis in TabBarShape ... can't tell because you didn't share it.

import SwiftUI
enum Tab: CaseIterable {
case home
case search
case media
}
struct ContentView: View {
@State var selectedTab: Tab = .home
@State private var xAxis: CGFloat = 0
private let home = Text("home")
private let search = Text("search")
private let media = Text("media")
var body: some View {
ZStack(alignment: .center) {
TabView(selection: $selectedTab) {
switch selectedTab {
case .home:
home
.ignoresSafeArea()
case .search:
search
.ignoresSafeArea()
case .media:
media
.ignoresSafeArea()
}
}
VStack {
Spacer()
HStack(spacing: 0) {
ForEach(Tab.allCases, id: \.self) { tab in
if tab == .search { Spacer(minLength: 0) }
GeometryReader { proxy in
Button {
withAnimation {
selectedTab = tab
xAxis = proxy.frame(in: .global).midX // .global should work fine
}
} label: {
Image(systemName: "house")
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width: 25, height: 25)
.foregroundColor(tab == selectedTab ? Color.blue : Color.gray)
}
.onAppear {
if tab == selectedTab {
xAxis = proxy.frame(in: .global).midX // set for initial selection
}
}
}
.frame(width: 25, height: 25)
if tab == .search { Spacer(minLength: 0) }
}
}
.padding(.horizontal, 60)
.padding(.vertical)
.background(
ZStack {
Color.green
Circle().fill(.white).frame(width: 50)
.position(x: xAxis) // applied here
}
)
.cornerRadius(50)
// .padding(.horizontal, idiomIsPhone() ? nil : tabBarHorizontalPaddingForIpad())
Spacer()
.frame(height: 5)
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With