I have used SwiftUI to develop brief exercises and fix some bugs. NavigtaionView is one of the most annoying bugs, and this article will report the bugs to you.
# use UINavigationBarAppearance
In general case, we will be in the application (_, didFinishLaunchingWithOptions) using the following code to the UINavigationBar configuration:
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().barTintColor = UIColor(named: "themeColor")
UINavigationBar.appearance().shadowImage = UIImage()
...
Copy the code
For SwiftUI in iOS 13.4 these codes will also work, but:
- in
IOS 13.3
Will directly cause a crash, and can not be analyzed through the crash file; - If in the code once the
NavigationView
Set up the.navigationViewStyle(StackNavigationViewStyle())
So no matter what system version will be in thisNavigationView
It crashes when it’s about to be shown;
It is recommended to use the new API of iOS 13, with an example of code with comments as follows:
let coloredAppearance = UINavigationBarAppearance(a)// Set it to opaque
coloredAppearance.configureWithOpaqueBackground()
// set the backgroundColor (for solid background you can use backgroundColor without setting backgroundImage)
coloredAppearance.backgroundColor = UIColor(named: "themeColor2")
// There is no need to set shadowColor, nil or clear for the same performance
coloredAppearance.shadowColor = .clear
let titleAttr: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.white
]
// Set the title attribute in the inline state. The large state corresponds to the largeTitleTextAttributes
coloredAppearance.titleTextAttributes = titleAttr
// You can also set titlePositionAdjustment to control the title offset UIOffset(Horizontal: -10, vertical: 0)
// Set the style of the return button
let backButtonAppearance = UIBarButtonItemAppearance(a)// Font style
backButtonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.white]
coloredAppearance.backButtonAppearance = backButtonAppearance
let backImage = UIImage(named: "back")? .withRenderingMode(.alwaysOriginal)// Set the return button arrow image to nil
coloredAppearance.setBackIndicatorImage(backImage, transitionMaskImage: backImage)
// sets the appearance properties in the standard (large) state. CompactAppearance if not set will use the standardAppearance style
UINavigationBar.appearance().standardAppearance = coloredAppearance
// Describes the appearance properties of the navigation bar to use when the associated UIScrollView reaches the edge adjacent to the navigation bar (the top edge of the navigation bar).
// if not, a modified standardAppearance will be used.
UINavigationBar.appearance().scrollEdgeAppearance = coloredAppearance
Copy the code
# NavigationLink
The problem of
Create a new SwiftUI project and replace the contentView. swift code with the following:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
VStack(spacing: 30) {
NavigationLink(destination: secondView()) {
Text("Use NavigationLink directly")
}
}
.navigationBarTitle("Navigation BUG", displayMode: .inline)
.navigationBarItems(
trailing: NavigationLink(destination: secondView()) {
Text("Link")}}}func secondView(a) -> some View {
return Text("second").navigationBarTitle("Sencod", displayMode: .inline)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()}}Copy the code
NavigationLink and NavigationLink should be NavigationLink and NavigationLink should be NavigationLink and NavigationLink should be NavigationLink. _? 13.1.? NavigationBar infinite overlay problem may occur on NavigationBar, this does not reproduce 😑);
NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink: NavigationLink
* * *Assertion failure in- [UINavigationController popToViewController:transition:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore_Sim/UIKit-3900.12.16/UINavigationController.m:8129* * *Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Tried to pop to a view controller that doesn't exist.'
First throw call stack:
(
0 CoreFoundation 0x00007fff23c4f02e __exceptionPreprocess + 350
1 libobjc.A.dylib 0x00007fff50b97b20 objc_exception_throw + 48
2 CoreFoundation 0x00007fff23c4eda8+ [NSException raise:format:arguments:] + 88
3 Foundation 0x00007fff256c9b61- [NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 191
4 UIKitCore 0x00007fff4713d9b1 __57- [UINavigationController popToViewController:transition:]_block_invoke + 620
5 UIKitCore 0x00007fff4713d65e- [UINavigationController popToViewController:transition:] + 753.Copy the code
The solution is to use NavigationLink’s other notation:
NavigationLink(destination: secondView(), isActive: $showDetail, label: { EmptyView()})Copy the code
Add this code to the ContentView struct as follows
struct ContentView: View {@State private var showDetail = false
var body: some View {
NavigationView {
VStack(spacing: 30) {
NavigationLink(destination: secondView()) {
Text("Use NavigationLink directly")}NavigationLink(destination: secondView(), isActive: $showDetail, label: { EmptyView()})Button(action: {
self.showDetail = true{})Text("Use isActive and EmptyView")
}
}
.navigationBarTitle("Navigation BUG", displayMode: .inline)
.navigationBarItems(
leading: Button("Empty") {
self.showDetail = true
},
trailing: NavigationLink(destination: secondView()) {
Text("Link")
})
}
.navigationViewStyle(StackNavigationViewStyle()}func secondView(a) -> some View {
return Text("second").navigationBarTitle("Sencod", displayMode: .inline)
}
}
Copy the code
After running, click Empty and use isActive and EmptyView to jump and return with no problems. OK, we’re done here? NO! We are too excited. If you run it on iOS 13.3, you will find that if you click Link to jump back and click Link again, you will not jump again. Similarly, click Empty and use NavigationLink directly. Same with isActive and EmptyView!!
The program didn’t crash but I was about to crash! There is no solution to this problem for the time being! If you have a good solution please be sure to leave a message notice, thank you.
It only took me less than 4 days to write and finish the application, but just adapting iOS 13.1, iOS 13.2.x, iOS 13.3 has already tested my hair amount;
So in order not to lengthen my hairline, I had to specify that iOS 13.4 was available in the second update to The Brief, but that’s not the end of it.
# In transition animation inNavigationView
The problems in the
The overall code is as follows, and the problem code is commented:
import SwiftUI
fileprivate extension AnyTransition {
static var moveToOpacity: AnyTransition {
let insertion = AnyTransition.move(edge: .bottom)
let removal = AnyTransition.opacity
return .asymmetric(insertion: insertion, removal: removal)
}
}
fileprivate class CModel: Identifiable {
let id = UUID()}struct BUGTransition: View {
var body: some View {
ShowOrHiddenAnimation2()}}// NavigationView uses ZStcak ==> Transition
fileprivate struct ShowOrHiddenAnimation4: View {@State private var model: CModel? = nil
var body: some View {
NavigationView {
ZStack {
Button("Tap Me") {
withAnimation(.easeOut(duration: 3)) {
self.model = CModel()}}if self.model ! =nil {
FullScreenView1(model: $model)
}
}
.navigationBarTitle("xxx", displayMode: .inline)
}
}
}
// NavigationView Group ==> Transition insert without removal,navigationBar perfect occlusion
fileprivate struct ShowOrHiddenAnimation3: View {@State private var model: CModel? = nil
var body: some View {
ZStack {
NavigationView {
Button("Tap Me") {
withAnimation(.easeOut(duration: 3)) {
self.model = CModel()
}
}
.navigationBarTitle("xxx", displayMode: .inline)
}
if self.model ! =nil {
/* Color.pink.edgesIgnoringSafeArea(.all) .transition(.moveToOpacity) .animation(.easeOut(duration: 3)) .onTapGesture { withAnimation(.easeOut(duration: 3)) { self.model = nil } } */
FullScreenView2(model: $model)
}
}
}
}
// ZStack ==> Transition to insert without removal,navigationBar perfect occlusion
fileprivate struct ShowOrHiddenAnimation2: View {@State private var model: CModel? = nil
var body: some View {
ZStack {
NavigationView {
Button("Tap Me") {
withAnimation(.easeOut(duration: 3)) {
self.model = CModel()
}
}
.navigationBarTitle("xxx", displayMode: .inline)
}
if self.model ! =nil {
FullScreenView1(model: $model)
}
}
}
}
// Use ZStack ==> Transition without using navigationBar
fileprivate struct ShowOrHiddenAnimation1: View {@State private var model: CModel? = nil
var body: some View {
ZStack {
Button("Tap Me") {
withAnimation(.easeOut(duration: 3)) {
self.model = CModel()}}if self.model ! =nil {
FullScreenView1(model: $model)
}
}
}
}
// Use ZStack internally
fileprivate struct FullScreenView1: View {@Binding var model: CModel?
var body: some View {
ZStack {
Color.pink.edgesIgnoringSafeArea(.all)
}
.transition(.moveToOpacity)
.animation(.easeOut(duration: 3))
.onTapGesture {
withAnimation(.easeOut(duration: 3)) {
self.model = nil}}}}// Use Group wrapping, layout is determined externally
fileprivate struct FullScreenView2: View {@Binding var model: CModel?
var body: some View {
Group {
Color.pink.edgesIgnoringSafeArea(.all)
NavigationView {
Text("FullScreenView2")
}
}
.transition(.moveToOpacity)
.animation(.easeOut(duration: 3))
.onTapGesture {
withAnimation(.easeOut(duration: 3)) {
self.model = nil}}}}struct BUGTransition_Previews: PreviewProvider {
static var previews: some View {
BUGTransition()}}Copy the code
Similarly, if you downloaded the official tutorial demo, find it
extension AnyTransition {
static var moveAndFade: AnyTransition {
let insertion = AnyTransition.move(edge: .trailing)
.combined(with: .opacity)
let removal = AnyTransition.scale
.combined(with: .opacity)
return .asymmetric(insertion: insertion, removal: removal)
}
}
Copy the code
The removal effect is completely invalid in NavigationView ðŸ¤.
# end?
These are just a few of the problems in NavigationView,
- Other not very serious will not repeat;
- and
NavigationView
Irrelevant ones are also not described in this article (e.g., for useUIViewRepresentable
çš„View
addcornerRadius
Modifiers cause it to be “unresponsive” 🤥);
All versions of iOS 13 are now supported. In order to fully adapt to iOS 13.x, I had to abandon NavigationView in SwiftUI and use the external UINavigationController to set UIHostingController to rootVC. UIHostingController uses the corresponding Swiftui-View initialization method to fix these problems.