Placing TabView inside NavigationView makes header transparent - swiftui

TabView worked fine for me before i added NavigationView around it.
Here's a normal behaviour
A problem arises when i add NavigationView around my TabView - when scrolling I see "test" in front of black rectangle.
I tried setting
UINavigationBar.appearance().backgroundColor
to some opaque color but it just draws another rectangle in front of everything.
Is there any way to make that black rectangle opaque when using NavigationView around TabView?
Oh, one more thing.. i tried removing
.edgesIgnoringSafeArea(.top)
which solves the problem but huge white space appears in top area:
import SwiftUI
struct ContentView: View {
let tabData = [
TabItem(menuTitle: Text("item 1"), menuImage: Image(systemName: "heart.fill"), bodyHeadline: Text("Postnatal recovery"), bodyMeta: Text(""), tag: 1),
TabItem(menuTitle: Text("item 2"), menuImage: Image(systemName: "heart.fill"), bodyHeadline: Text("Weight loss"), bodyMeta: Text(""), tag: 2),
]
var body: some View {
NavigationView {
ZStack {
TabView {
ForEach(tabData) { tabItem in
VStack {
VStack {
Rectangle()
}
.frame(height: 90)
.background(Color.yellow)
ScrollView {
LazyVStack(spacing: 0) {
ForEach(0...100, id:\.self) { val in
ZStack {
Text("test")
.font(.system(size: 128))
} // ZStack
.background(Color.white)
} // ForEach
}
}
.background(Color.blue)
}
.tabItem {
tabItem.menuImage
tabItem.menuTitle
.foregroundColor(Color.red)
}
.edgesIgnoringSafeArea(.top)
} // ForEach
} // TabView
} // ZStack
} // NavigationView
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct TabItem: Identifiable {
var id = UUID()
var menuTitle: Text
var menuImage: Image
var bodyHeadline: Text
var bodyMeta: Text
var tag: Int
}

adding
.navigationBarHidden(true).navigationBarTitle("")
made everything work smoothly

Related

TabView Label doesn't appear while the background color doesn't fill the entire screen

This is my reproducible code.
Problems: There is no error in my code but I can't find my TabView Label. The background was declared with .ignoresSafeArea(.all) but still doesn't fill the entire screen.
import SwiftUI
struct LibraryView: View {
var allColors: [Color] = [Color.red, Color.green, Color.blue]
var body: some View {
TabView {
ForEach(allColors, id: \.self) { color in
BookSubView(bColor: color)
.tabItem {
Text("BOOK")
.foregroundColor(color)
Image(systemName: "book")
}
}
}
.tabViewStyle(.page)
}
}
struct BookSubView: View {
var bColor: Color
var body: some View {
LinearGradient(colors: [bColor, Color.white], startPoint: .top,
endPoint: .bottom).ignoresSafeArea(.all)
}
}
Use a Label inside of the .tabItem modifier
BookSubView(bColor: color)
.tabItem {
// There are probably modifiers for Label you can use to customize to your needs
Label("Book", systemImage: "book")
}

SwiftUI - How to change the background Color of top safe area to gray?

I want to change the background color of top safe area from green to gray. I have looked everywhere but could not find any solution. The screen in preview looks like this.
My codes:
struct ContentView: View {
#State var name = ""
init() {
//Use this if NavigationBarTitle is with Large Font
UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: UIColor.red]
UINavigationBar.appearance().backgroundColor = .gray
}
var body: some View {
NavigationView {
ZStack{
VStack{
TextField("Name", text: $name)
.frame(height:200)
.padding()
.background(backgrounImage())
.overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.gray,lineWidth: 4))
.padding()
Spacer()
}.navigationTitle("Tanvir")
.background(Color.green.edgesIgnoringSafeArea(.all))
}
}
}
}
You can add another view on top of the ZStack:
var body: some View {
NavigationView {
ZStack(alignment: .top) { // <- Don't forget this
,,,
GeometryReader { reader in
Color.yellow
.frame(height: reader.safeAreaInsets.top, alignment: .top)
.ignoresSafeArea()
}
}
}
}
Don't forget the stack alignment!
Consistant Bar for the entire App
If you need it to be on all of your views, try putting the code somewhere more consistent like where you are providing the contentView:
#main
struct SwiftUIAppPlaygroundApp: App {
var body: some Scene {
WindowGroup {
ZStack {
ContentView()
GeometryReader { reader in
Color.yellow
.frame(height: reader.safeAreaInsets.top, alignment: .top)
.ignoresSafeArea()
}
}
}
}
}
Use this UIApplication extension to chagne your status bar color
extension UIApplication {
/**
Get status bar view
*/
var statusBarUIView: UIView? {
let tag = 13101996
if let statusBar = self.windows.first?.viewWithTag(tag) {
self.windows.first?.bringSubviewToFront(statusBar)
return statusBar
} else {
let statusBarView = UIView(frame: UIApplication.shared.windows.first?.windowScene?.statusBarManager?.statusBarFrame ?? .zero)
statusBarView.tag = tag
self.windows.first?.addSubview(statusBarView)
return statusBarView
}
}
}
Usage
struct ContentViewStatusBar: View {
#State var name = ""
init() {
//Use this if NavigationBarTitle is with Large Font
UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: UIColor.red]
UINavigationBar.appearance().backgroundColor = .gray
}
var body: some View {
NavigationView {
ZStack{
VStack{
TextField("Name", text: $name)
.frame(height:200)
.padding()
.background(backgrounImage())
.overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.gray,lineWidth: 4))
.padding()
Spacer()
}.navigationTitle("Tanvir")
.background(Color.green.edgesIgnoringSafeArea(.all))
}
}.onAppear {
UIApplication.shared.statusBarUIView?.backgroundColor = .gray //<<=== Here
}
}
}

Combining a TabView with PageTabViewStyle, a NavigationView and a ScrollView correctly in SwiftUI

I am working on a UI that combines a TabView with PageTabViewStyle, a NavigationView and a ScrollView. When scrolling down, I expect the title of the NavigationView to adjust and get smaller. But it does not when the ScrollView is placed inside the TabView. How do I implement this behavior?
This is an extension to my original question on how to use a TabView with PageTabViewStyle and a NavigationView together.
struct ContentView: View {
#State var selection = 1
var body: some View {
NavigationView {
TabView {
LibraryView()
.tag(1)
LibraryView()
.tag(2)
}
.navigationTitle(selection == 1 ? "A" : "B")
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
//.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
struct LibraryView: View {
#State var gridLayout: [GridItem] = [
GridItem(),
GridItem()
]
var body: some View {
ScrollView {
LazyVGrid(columns: gridLayout, alignment: .center, spacing: 10) {
ForEach(collections.indices) { index in
CollectionItem(collection: collections[index])
}
}
.padding(.all, 10)
}
}
}

SwiftUI popover background color

With UIKit, I could customize the background color of a popover using UIPopoverPresentationController's backgroundColor.
This would change the color including the arrow.
How can I accomplish this with SwiftUI? When I change the the popover content's background color, it doesn't include the arrow:
You can use .scaleEffect(…) to make your background view take more space. When it’s bigger than the content of the popover, it will fill the arrow.
struct ContentView: View {
#State var popoverVisible = false
var body: some View {
VStack {
Button("Open Popover") {
self.popoverVisible = true
}
.popover(isPresented: $popoverVisible) {
ZStack {
// Scaled-up background
Color.blue
.scaleEffect(1.5)
Text("Hello world")
.foregroundColor(.white)
.padding()
}
}
}
}
}
Use i.e. a VStack to fill the view, and then background will be extrapolated from the view at the edge:
struct ContentView: View {
#State var popoverVisible = false
var body: some View {
VStack {
Button("Open Popover") {
self.popoverVisible = true
}
.popover(isPresented: $popoverVisible) {
VStack {
Text("Hello world")
.foregroundColor(.white)
.padding(8)
Spacer()
Text("Bye world")
.foregroundColor(.white)
.background(Color.blue)
}
}
}
}
}

SwiftUI: animating between Single and HStack views

Goal:
1- Shows a view (Blue) that covers entire screen
2- When tapped on bottom (top right corner), it shows an HStack animating right side HStack (Green) "Slide Offset animation".
import SwiftUI
struct ContentView: View {
#State var showgreen = false
var body: some View {
NavigationView {
HStack {
Rectangle()
.foregroundColor(.blue)
if showgreen {
Rectangle()
.foregroundColor(.green)
.offset(x: showgreen ? 0 : UIScreen.main.bounds.width)
.animation(.easeInOut)
}
}
.navigationBarItems(trailing:
Button(action: { self.showgreen.toggle() }) {
Image(systemName: "ellipsis")
})
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.colorScheme(.dark)
.previewDevice("iPad Pro (12.9-inch) (3rd generation)")
}
}
The code works, however I cannot get the Green "Slide Offset animation" to work. Really appreciate any help! : )
Instead of using the if conditional, you need the green rectangle to be already present, and just offscreen. When showgreen toggles, you need to shrink the size of the blue rectangle, which will make room for the green rectangle.
struct ContentView: View {
#State var showgreen = false
var body: some View {
NavigationView {
HStack {
Rectangle()
.foregroundColor(.blue)
.frame(width: showgreen ? UIScreen.main.bounds.width / 2 : UIScreen.main.bounds.width)
.animation(.easeInOut)
Rectangle()
.foregroundColor(.green)
.animation(.easeInOut)
}
.navigationBarItems(trailing:
Button(action: { self.showgreen.toggle() }) {
Image(systemName: "ellipsis")
})
}
.navigationViewStyle(StackNavigationViewStyle())
}
}