在这段代码中,我使用Home()中的一个标记为“seeprofile”的按钮,将自定义选项卡栏中的选定选项卡更改为Profile()。
这将起作用(将当前选项卡更改为Profile(),但.clipShape(BottomCurve(currentXValue:currentXValue))效果不会发生。我如何确保它是响应的(就像currentTab变量一样)?
下面是代码:
class AppViewModel: ObservableObject {
@Published var currentTab: Tab = .Home
}
struct MainPage: View {
@StateObject var appModel: AppViewModel = .init()
@Namespace var animation
var body: some View {
VStack(spacing: 0) {
TabView(selection: $appModel.currentTab) {
Profile()
.tag(Tab.Profile)
.setUpTab()
Home(appModel: appModel)
.tag(Tab.Home)
.setUpTab()
Statistics()
.tag(Tab.Statistics)
.setUpTab()
}
.overlay(alignment: .bottom) {
CustomTabBar(currentTab: $appModel.currentTab, animation: animation)
}
}
}
}
struct Home: View {
@ObservedObject var appModel: AppViewModel
init(appModel: AppViewModel) {
self.appModel = appModel
}
var body: some View {
VStack {
Button(action: {
appModel.currentTab = .Profile
}) {
HStack {
Text("See profile")
.font(.headline)
.foregroundColor(.black)
Image(systemName: "chevron.right")
.foregroundColor(.black)
}
}
}
}
}
struct Profile: View {
var body: some View {
VStack {
Text("Profile view")
}
}
}
struct Statistics: View {
var body: some View {
VStack {
Text("Statistics view")
}
}
}
struct CustomTabBar: View {
@Binding var currentTab: Tab
var animation: Namespace.ID
// Current Tab XValue...
@State var currentXValue: CGFloat = 0
var body: some View {
HStack(spacing: 0){
ForEach(Tab.allCases,id: \.rawValue){tab in
TabButton(tab: tab)
.overlay {
Text(tab.rawValue)
.font(.system(size: 14, weight: .semibold))
.foregroundColor(.yellow)
.fixedSize(horizontal: true, vertical: false)
.offset(y: currentTab == tab ? 15 : 100)
}
}
}
.padding(.top)
// Preview wont show safeArea...
.padding(.bottom,getSafeArea().bottom == 0 ? 15 : 10)
.background{
Color(.gray)
.shadow(color: .black.opacity(0.08), radius: 5, x: 0, y: -5)
.clipShape(BottomCurve(currentXValue: currentXValue))
.ignoresSafeArea(.container, edges: .bottom)
}
}
// TabButton...
@ViewBuilder
func TabButton(tab: Tab)->some View{
// Since we need XAxis Value for Curve...
GeometryReader{proxy in
Button {
withAnimation(.easeInOut){
currentTab = tab
// updating Value...
currentXValue = proxy.frame(in: .global).midX
}
} label: {
// Moving Button up for current Tab...
// Image(tab.rawValue)
Image(systemName: "person.fill")
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width: 25, height: 25)
.frame(maxWidth: .infinity)
.foregroundColor(currentTab == tab ? .white : .blue.opacity(0.8))
.padding(currentTab == tab ? 15 : 0)
.background(
ZStack{
if currentTab == tab{
Circle()
.fill(.green)
.shadow(color: .black.opacity(0.1), radius: 8, x: 5, y: 5)
.matchedGeometryEffect(id: "TAB", in: animation)
}
}
)
.contentShape(Rectangle())
.offset(y: currentTab == tab ? -50 : 0)
}
// Setting intial Curve Position...
.onAppear {
if tab == Tab.allCases.first && currentXValue == 0{
currentXValue = proxy.frame(in: .global).midX
}
}
}
.frame(height: 30)
}
}
enum Tab: String,CaseIterable{
case Profile = "Profile"
case Home = "Home"
case Statistics = "Statistics"
}
extension View{
func getSafeArea()->UIEdgeInsets{
guard let screen = UIApplication.shared.connectedScenes.first as? UIWindowScene else{
return .zero
}
guard let safeArea = screen.windows.first?.safeAreaInsets else{
return .zero
}
return safeArea
}
}
extension View{
@ViewBuilder
func setUpTab()->some View{
self
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background{
Color("StriderBG")
.ignoresSafeArea()
}
}
}
// Tab Bar Curve...
struct BottomCurve: Shape {
var currentXValue: CGFloat
// Animating Path...
// it wont work on previews....
var animatableData: CGFloat{
get{currentXValue}
set{currentXValue = newValue}
}
func path(in rect: CGRect) -> Path {
return Path{path in
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: rect.width, y: 0))
path.addLine(to: CGPoint(x: rect.width, y: rect.height))
path.addLine(to: CGPoint(x: 0, y: rect.height))
// mid will be current XValue..
let mid = currentXValue
path.move(to: CGPoint(x: mid - 50, y: 0))
let to1 = CGPoint(x: mid, y: 35)
let control1 = CGPoint(x: mid - 25, y: 0)
let control2 = CGPoint(x: mid - 25, y: 35)
path.addCurve(to: to1, control1: control1, control2: control2)
let to2 = CGPoint(x: mid + 50, y: 0)
let control3 = CGPoint(x: mid + 25, y: 35)
let control4 = CGPoint(x: mid + 25, y: 0)
path.addCurve(to: to2, control1: control3, control2: control4)
}
}
}
正如您在运行此代码时所看到的,当点击Home()中的按钮时,Profile()会显示,但BottomCurve效果没有响应。
1条答案
按热度按时间lnvxswe21#
下面的代码修改了曲线开始位置和曲线动画。首次启动和点击“查看配置文件”按钮时都存在动画问题。
如果我错过了什么,请告诉我: