我正在使用SwiftUI向MacOS应用添加一个简单视图。这是我的代码:
struct ContentView: View {
@State var showOtherView = false
var body: some View {
VStack {
Text("Hello World").padding().onTapGesture {
withAnimation {
self.showOtherView.toggle()
}
}
if showOtherView {
Text("Other View").frame(height: 200).border(Color.red)
}
}
}
}
动画有效,但看起来确实很糟糕。
谁能让我知道如何在动画中正确添加Views
?
答案 0 :(得分:1)
问题在于,导航isActive状态和显示的选项卡状态均未记录。
通过记录每个选项卡的导航状态以及哪个选项卡处于活动状态,可以为每个选项卡显示正确的导航状态。
可以改进模型以删除元组并使其更灵活,但是关键是使用getter和setter对每个选项卡使用什么状态的封装模型,以便允许NavigationLink更新通过绑定。
我已经简化了顶层VStack,并删除了此处不需要的顶层开关,但是可以在实际实现中添加回去,以便在顶层使用不同类型的视图
enum TabName : String {
case Explore, Network
}
struct ContentView: View {
@State var model = TabModel()
init(){
UINavigationBar.setAnimationsEnabled(false)
}
var body: some View {
VStack(spacing: 0) {
Spacer()
AViewWhichNavigates(model: $model).background(Color.green)
Spacer()
CustomTabView(model:$model)
}
}
}
struct CustomTabView: View {
@Binding var model: TabModel
var body: some View {
HStack {
Spacer()
Text("Explore").border(Color.black, width: 1).onTapGesture { model.selectedTab = .Explore }
Spacer()
Text("Network").border(Color.black, width: 1).onTapGesture { model.selectedTab = .Network }
Spacer()
}
}
}
struct AViewWhichNavigates: View {
@Binding var model:TabModel
var body: some View {
NavigationView(content: {
NavigationLink(destination: Text("We are one level deep in navigation in \(model.selectedTab.rawValue)"), isActive: $model.isActive) {
Text("You are at root of \(model.selectedTab.rawValue). Tap to navigate").navigationTitle(model.selectedTab.rawValue)
}.onDisappear {
UINavigationBar.setAnimationsEnabled(model.isActive)
}
})
}
}
struct TabModel {
var selectedTab:TabName = .Explore
var isActive : Bool {
get {
switch selectedTab {
case .Explore : return tabMap.0
case .Network : return tabMap.1
}
}
set {
switch selectedTab {
case .Explore : nOn(isActive, newValue); tabMap.0 = newValue;
case .Network : nOn(isActive, newValue); tabMap.1 = newValue;
}
}
}
//tuple used to represent a fixed set of tab isActive navigation states
var tabMap = (false, false)
func nOn(_ old:Bool,_ new:Bool ){
UINavigationBar.setAnimationsEnabled(new && !old)
}
}
答案 1 :(得分:1)
您需要的只是具有不透明性的ZStack。
import SwiftUI
enum TabName {
case explore, network
}
struct ContentView: View {
@State var displayedTab: TabName = .explore
var body: some View {
VStack {
ZStack {
AViewWhichNavigates(title: "Explore")
.background(Color.green)
.opacity(displayedTab == .explore ? 1 : 0)
AViewWhichNavigates(title: "Network")
.background(Color.green)
.opacity(displayedTab == .network ? 1 : 0)
}
CustomTabView(displayedTab: $displayedTab)
}
}
}
struct CustomTabView: View {
@Binding var displayedTab: TabName
var body: some View {
HStack {
Spacer()
Text("Explore").border(Color.black, width: 1).onTapGesture { self.displayedTab = .explore }
Spacer()
Text("Network").border(Color.black, width: 1).onTapGesture { self.displayedTab = .network }
Spacer()
}
}
}
struct AViewWhichNavigates: View {
let title: String
var body: some View {
NavigationView(content: {
NavigationLink(destination: Text("We are one level deep in navigation")) {
Text("You are at root. Tap to navigate").navigationTitle(title)
}
})
}
}
答案 2 :(得分:0)
我认为即使使用自定义标签页视图也是可行的,因为问题在于切换标签页时重建ExploreTab()
,所以该标签页的所有内容也都被重建,因此内部NavigationView
处于打开状态重建在第一页上。
假设您的应用程序中只有一个ExploreTab
(很明显),可能的解决方案是显式地使其Equatable
,并且不允许SwiftUI在刷新时替换它。
所以
struct ExploreTab: View, Equatable {
static func == (lhs: Self, rhs: Self) -> Bool {
return true // prevent replacing ever !!
}
var body: some View {
// ... your code here
}
}
和
VStack(spacing: 0) {
switch displayedTab {
case .explore: ExploreTab().equatable() // << here !!
case .network: NetworkTab()
}
CustomTabView(displayedTab: $displayedTab) //This is the Custom TabBar
}
更新:已在Xcode 12 / iOS 14上进行了测试-如上所述,其工作原理(对于标准容器,实际上是相同的想法)
这里是如上所述CustomTabView
与测试环境的快速演示复制。
完整的模块代码:
struct ExploreTab: View, Equatable {
static func == (lhs: Self, rhs: Self) -> Bool {
return true // prevent replacing ever !!
}
var body: some View {
NavigationView {
NavigationLink("Go", destination: Text("Explore"))
}
}
}
enum TestTabs {
case explore
case network
}
struct CustomTabView: View {
@Binding var displayedTab: TestTabs
var body: some View {
HStack {
Button("Explore") { displayedTab = .explore }
Divider()
Button("Network") { displayedTab = .network }
}
.frame(maxWidth: .infinity)
.frame(height: 80).background(Color.yellow)
}
}
struct TestCustomTabView: View {
@State private var displayedTab = TestTabs.explore
var body: some View {
VStack(spacing: 0) {
switch displayedTab {
case .explore: ExploreTab().equatable() // << here !!
case .network: Text("NetworkTab").frame(maxWidth: .infinity, maxHeight: .infinity)
}
CustomTabView(displayedTab: $displayedTab) //This is the Custom TabBar
}
.edgesIgnoringSafeArea(.bottom)
}
}