Avoid inherited styling inside List Section - swiftui

When I add my custom widget into List's Section header, the elements inside my widget gets styled. Among others all the text become ALLCAPS. How can I avoid that styling, especially text capitalization?
struct MyHeader: View {
var body: some View {
Text("Hello wOrLd!")
}
}
struct ContentView: View {
var body: some View {
List {
Section(header: MyHeader()) {}
}
}
}

struct MyHeader: View {
var body: some View {
Text("Hello wOrLd!").textCase(.none)
}
}
Maybe it works

Related

Does a LazyVStack remain "lazy" if it's inside a VStack?

Let's consider a list of 100 posts. According to Apple, if I layout them inside a LazyVStack:
the stack view doesn’t create items until it needs to render them
onscreen.
What if I embed that LazyVStack inside a VStack? Does it still load the views "as needed"?
struct MyView: View {
init() {
print("init...")
}
var body: some View {
Text("test")
}
}
struct ContentView: View {
var body: some View {
ScrollView {
VStack {
LazyVStack {
ForEach.init(0..<100) { int in
MyView()
}
}
}
}
}
}
Running the above code, as we scroll we can see more MyViews are init'd (by viewing the print statements in the console), so it seems like a LazyVStack in a VStack does indeed create it's content lazily. We can see the same is true when removing the VStack as well.

Navigation + Tabview + Sheet broken in iOS 15

It looks like Navigation + TabView + Sheet is broken in iOS 15.
When I do this:
ContentView -> DetailView -> Bottom Sheet
When the bottom sheet comes up, the Detail view is automatically popped off the stack:
https://www.youtube.com/watch?v=gguLptAx0l4
I expect the Detail view to stay there even when the bottom sheet appears. Does anyone have any idea on why this happens and how to fix it?
Here is my sample code:
import Combine
import SwiftUI
import RealmSwift
struct ContentView: View {
var body: some View {
NavigationView {
TabView {
TabItemView(num: 1)
.tabItem {
Text("One")
}
TabItemView(num: 2)
.tabItem {
Text("Two")
}
}
}
}
}
struct TabItemView: View {
private let num: Int
init(num: Int) {
self.num = num
}
var body: some View {
NavigationLink(destination: DetailView(text: "Detail View \(num)")) {
Text("Go to Detail View")
}
}
}
struct DetailView: View {
#State private var showingSheet = false
private let text: String
init(text: String) {
self.text = text
}
var body: some View {
Button("Open Sheet") {
showingSheet.toggle()
}.sheet(isPresented: $showingSheet) {
Text("Sheet Text")
}
}
}
This works on iOS 14 btw
UPDATE 1:
Tried #Sebastian's suggestion of putting NavigationView inside of TabView. While this fixed the nav bug, it fundamentally changed the behavior (I don't want to show the tabs in DetailView).
Also tried his suggestion of using Introspect to set navigationController.hidesBottomBarWhenPushed = true on the NavigationLink destination, but that didn't do anything:
struct ContentView: View {
var body: some View {
TabView {
NavigationView {
TabItemView(num: 1)
}.tabItem {
Text("One")
}
NavigationView {
TabItemView(num: 2)
}.tabItem {
Text("Two")
}
}
}
}
struct TabItemView: View {
private let num: Int
init(num: Int) {
self.num = num
}
var body: some View {
NavigationLink(destination: DetailView(text: "Detail View \(num)").introspectNavigationController { navigationController in
navigationController.hidesBottomBarWhenPushed = true
}) {
Text("Go to Detail View")
}
}
}
struct DetailView: View {
#State private var showingSheet = false
private let text: String
init(text: String) {
self.text = text
}
var body: some View {
Button("Open Sheet") {
showingSheet.toggle()
}.sheet(isPresented: $showingSheet) {
Text("Sheet Text")
}
}
}
You need to flip how you nest TabView & NavigationView. Instead of nesting several TabView views inside a NavigationView, use the TabView as the parent component, with a NavigationView for each tab.
This is how the updated ContentView would look like:
struct ContentView: View {
var body: some View {
TabView {
NavigationView {
TabItemView(num: 1)
}
.tabItem {
Text("One")
}
NavigationView {
TabItemView(num: 2)
}
.tabItem {
Text("Two")
}
}
}
}
This makes sense and is more correct: The tabs should always be visible, but you want to show a different navigation stack with different content in each tab.
That it worked previously doesn't make it more correct - SwiftUI probably just changed its mind on dealing with unexpected situations. That, and the lack of error messages in these situations, is the downside of using a framework that tries to render anything you throw at it!
If the goal is specifically to hide the tabs when pushing a new view on a NavigationView (e.g., when tapping on a conversation in a messaging app), you have to use a different solution. Apple added the UIViewController.hidesBottomBarWhenPushed property to UIKit to support this specific use case.
This property is set on the UIViewController that, when presented, should not show a toolbar. In other words: Not the UINavigationController or the UITabBarController, but the child UIViewController that you push onto the UINavigationController.
This property is not supported in SwiftUI natively. You could set it using SwiftUI-Introspect, or simply write the navigation structure of your application using UIKit and write the views inside in SwiftUI, linking them using UIHostingViewController.

SwiftUI - Navigating back to home without nesting?

In the code below, if I use the links to go back and forth between views A and B, I will end up with nested views as shown in the image. The only way I've found to avoid nesting is to never link to a view where a NavigationView is declared - as it is in ViewA below. My question...is there any way to go back to ViewA without the views nesting?
struct ViewA: View {
var body: some View {
NavigationView{
NavigationLink(destination: ViewB()) {
Text("ViewB")
}
}
.navigationBarTitle("ViewA")
}
}
struct ViewB: View {
var body: some View {
NavigationLink(destination: ViewA()) {
Text("ViewA")
}
.navigationBarTitle("ViewB")
}
}
You should not create NavigationLink(destination: ViewA()) because it is not back it creates a new ViewA. Once you navigate to ViewB, the back button will be create for you automatically.
struct ViewA: View {
var body: some View {
NavigationView{
NavigationLink(destination: ViewB()) {
Text("ViewB")
}
}
.navigationBarTitle("ViewA")
}
}
struct ViewB: View {
var body: some View {
Text("ViewB Pure Content")
.navigationBarTitle("ViewB")
}
}
You are nesting views because every time you click ViewA/ViewB it creates a new view object. You can add
#Environment(\.presentationMode) var presentationMode
and call
presentationMode.wrappedValue.dismiss()
when the view button gets pressed you dismiss it.

SwiftUI Navigation Multiple back button

When I push more than one view, multiple back buttons are visible in the navigation bar.
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination:SecView()) {
Text("Primo")
}
}
}
}
struct SecView: View {
var body: some View {
NavigationView {
NavigationLink(destination:TerView()) {
Text("Secondo")
}
}
}
}
struct TerView: View {
var body: some View {
Text("Hello World!")
}
}
I would like to have only one back button per view.
Here is a screenshot of the problem.
There should only be a single NavigationView at the root of your navigation stack.
Remove the NavigationView block from SecView and you will then have a single navigation bar owned by ContentView.
as Gene said, there should only be a single NavigationView at the root of you navigation stack. This means that the next time you need to navigate to a page in a different View, you will add a NavigationLink but not wrap it in a NavigationView. So in the code that you initially posted, you need to remove the NavigationView from your SecView View but still keep the NavigationLink. See the code below:
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination:SecView()) {
Text("Primo")
}
}
}
}
struct SecView: View {
var body: some View {
NavigationLink(destination:TerView()) {
Text("Secondo")
}
}
}
struct TerView: View {
var body: some View {
Text("Hello World!")
}
}

How to disable NavigationView push and pop animations

Given this simple NavigationView:
struct ContentView : View {
var body: some View {
NavigationView {
VStack {
NavigationLink("Push Me", destination: Text("PUSHED VIEW"))
}
}
}
}
Did anyone find a way of disabling the NavigationView animation when a destination view is pushed/popped into/from the stack?
This has been possible in UIKit since iOS2.0! I think it is not too much to ask from the framework. I tried all sorts of modifiers on all views (i.e., the NavigationView container, the destination view, the NavigationLink, etc)
These are some of the modifiers I tried:
.animation(nil)
.transition(.identity)
.transaction { t in t.disablesAnimations = true }
.transaction { t in t.animation = nil }
None made a difference. I did not find anything useful in the EnvironmentValues either :-(
Am I missing something very obvious, or is the functionality just not there yet?
Xcode 11.3:
Right now there is no modifier to disable NavigationView animations.
You can use your struct init() to disable animations, as below:
struct ContentView : View {
init(){
UINavigationBar.setAnimationsEnabled(false)
}
var body: some View {
NavigationView {
VStack {
NavigationLink("Push Me", destination: Text("PUSHED VIEW"))
}
}
}
}
First you need state for the NavigationLink to respond to, then set that state inside a transaction with animations disabled, as follows:
struct ContentView : View {
#State var isActive = false
var body: some View {
NavigationView {
VStack {
NavigationLink(isActive: $isActive, destination: {
Text("PUSHED VIEW")}) {
Text("Push Me")
}
Button("Navigate Without Animation") {
var transaction = Transaction()
transaction.disablesAnimations = true
withTransaction(transaction) {
isActive = true
}
}
}
}
}
}
I recently created an open source project called swiftui-navigation-stack (https://github.com/biobeats/swiftui-navigation-stack) that contains the NavigationStackView, a view that mimics the navigation behaviours of the standard NavigationView adding some useful features. For example, you could use the NavigationStackView and disable the transition animations as requested by Kontiki in the question. When you create the NavigationStackView just specify .none as transitionType:
struct ContentView : View {
var body: some View {
NavigationStackView(transitionType: .none) {
ZStack {
Color.yellow.edgesIgnoringSafeArea(.all)
PushView(destination: View2()) {
Text("PUSH")
}
}
}
}
}
struct View2: View {
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.all)
PopView {
Text("POP")
}
}
}
}
PushView and PopView are two views that allow you push and pop views (similar to the SwiftUI NavigationLink). Here is the complete example:
import SwiftUI
import NavigationStack
struct ContentView : View {
var body: some View {
NavigationStackView(transitionType: .none) {
ZStack {
Color.yellow.edgesIgnoringSafeArea(.all)
PushView(destination: View2()) {
Text("PUSH")
}
}
}
}
}
struct View2: View {
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.all)
PopView {
Text("POP")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The result is:
It would be great if you guys joined me in improving this open source project.