I have a custom progress view that indicates what view the user is currently on inside the navigation stack.
我有一个定制的进度视图,它指示用户当前在导航堆栈中所处的视图。
I am wanting to animate the progress view alongside my NavigationView transitions.
That is to say, as the views transition from one to another inside the NavigationView the progress view should also animate to the next/previous section.
我希望将进度视图与我的导航视图过渡一起设置为动画。这就是说,当视图在NavigationView内从一个视图转换到另一个时,进度视图也应该动画显示到下一个/上一个部分。
I want this to work by detecting the percentage of transition and updating the progress accordingly, that way if the user begins swiping back the animation will update based on the users current swipe.
我希望这是通过检测转换的百分比并相应地更新进度来实现的,这样如果用户开始向后滑动,动画将根据用户当前的滑动进行更新。
This can be achieved inside UIKit by having a custom UINavigationController, then adding a selector to the interactivePopGestureRecognizer and then reading the percentageComplete variable on the UIViewControllerTransitionCoordinator on said navigation controller.
这可以在UIKit中实现,方法是拥有一个自定义的UINavigationController,然后向interactivePopGestureRecognizer添加一个选择器,然后在所述导航控制器上的UIViewControllerTransftionCoadator上读取Percent ageComplete变量。
However I have yet to find any SwiftUI alternative, does such a thing exist yet/is this possible?
然而,我还没有找到任何SwiftUI替代方案,这样的东西存在吗/这可能吗?
更多回答
优秀答案推荐
To solve this, you need a state variable that tracks the current navigation level. The state variable should be updated whenever the level changes. One way is to use .onAppear
on the destination views.
要解决这个问题,您需要一个跟踪当前导航级别的状态变量。只要级别发生变化,就应该更新状态变量。一种方法是在目标视图上使用.onspecar。
The example below shows it working this way. NavigationView
is deprecated, so the example uses a NavigationStack
instead:
下面的示例显示了它以这种方式工作。NavigationView已弃用,因此该示例改用NavigationStack:
struct ContentView: View {
let nLevels = 7
@State private var currentLevel = 1
private func viewForLevel(level: Int) -> some View {
VStack(spacing: 40) {
Text("This is level \(level)")
if level < nLevels {
NavigationLink("Go to level \(level + 1)", value: level + 1)
}
}
.onAppear {
withAnimation {
currentLevel = level
}
}
// If onAppear is not called when navigating back then
// onDisappear can be used as fallback.
// Not found to be needed with NavigationStack and iOS 16.4
// .onDisappear {
// if currentLevel == level {
// withAnimation {
// currentLevel = level - 1
// }
// }
// }
}
private func progressIndicator(currentLevel: Int) -> some View {
HStack(spacing: 6) {
ForEach(1...nLevels, id: \.self) { level in
Rectangle()
.frame(height: 6)
.foregroundColor(level <= currentLevel ? .teal : Color(white: 0.9))
.frame(maxWidth: .infinity)
}
}
.padding()
}
var body: some View {
VStack(spacing: 0) {
progressIndicator(currentLevel: currentLevel)
NavigationStack {
viewForLevel(level: 1)
.navigationDestination(for: Int.self) { level in
viewForLevel(level: level)
}
}
}
}
}
You could also associate the NavigationStack
with a path
and read the current level from the end of the path, instead of using a separate state variable. I tried this, but found that the change was delayed when navigating back. So a separate state variable probably works better (as used here).
您还可以将NavigationStack与路径相关联,并从路径的末尾读取当前级别,而不是使用单独的状态变量。我尝试了一下,但发现返回时更改被延迟了。因此,单独的状态变量可能工作得更好(就像这里使用的那样)。
更多回答
我是一名优秀的程序员,十分优秀!