无法在 SwiftUI 中获得正确的视图位置
Can not get correct position of view in SwiftUI
我试图获取 Button 的 midX 位置,但它总是给我意想不到的结果。我尝试过使用 .global、.local。和 .named 坐标空间,但它仍然不起作用。也许还有另一种方法可以在没有 GeometryReader 的情况下获取 UI 元素的坐标
曲线中心应位于所选按钮的中心。
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)
}
}
}
它似乎与 .global 坐标一起工作得很好。请参阅下面的演示。也许 TabBarShape
中 xAxis 的使用有问题...因为你没有分享所以无法判断。
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)
}
}
}
}
我试图获取 Button 的 midX 位置,但它总是给我意想不到的结果。我尝试过使用 .global、.local。和 .named 坐标空间,但它仍然不起作用。也许还有另一种方法可以在没有 GeometryReader 的情况下获取 UI 元素的坐标 曲线中心应位于所选按钮的中心。
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)
}
}
}
它似乎与 .global 坐标一起工作得很好。请参阅下面的演示。也许 TabBarShape
中 xAxis 的使用有问题...因为你没有分享所以无法判断。
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)
}
}
}
}