TabView taking Top Space in SwiftUI - swiftui

Hi I am currently working on swiftUI project. I am facing a very strange issue. Here is the code for my problem. As you can see that, this tabView is taking some space from the Top which is highlighted in Red Color. It should be All blue in the View.
Why it is taking that extra space from the Top?
Kindly Review the code and help me with this problem as i'm a beginner.
import SwiftUI
struct StackOverFlowView: View {
#State private var selection = 0
var body: some View {
ZStack() {
Color.red
TabView(selection: $selection) {
Color.blue
}
.tabViewStyle(PageTabViewStyle())
.edgesIgnoringSafeArea(.all)
}.ignoresSafeArea(.all)
}
}
struct StackPreview: PreviewProvider {
static var previews: some View {
StackOverFlowView()
}
}

Related

SwiftUI animating part of a view without affecting specific other part

Sorry for the cryptic title.
I would like to have part of a row inside a list of rows to to animate downwards without moving the views vertically above it.
Here is a minimal example, showing what I mean:
import SwiftUI
struct ContentView: View {
#State var display = false
var body: some View {
List {
Button("Toggle") {
display.toggle()
}
Text("Text")
row
Text("Text")
}
.listStyle(.plain)
.animation(.linear, value: display)
}
var row: some View {
VStack {
Text("Title").bold()
if display {
Text("Lorem")
Text("ipsum")
Text("dolor")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewDevice(.init(rawValue: "iPhone 13 mini"))
}
}
The lorem ipsum block is supposed to animate into view without moving the Title text.
I imagine there's no way around GeometryReader here, but wanted to make sure. All suggestions are much appreciated 🙏

NavigationStack and TabView in Swiftui iOS 16: bug or improper usage?

[Xcode 14.1, iOS 16.1]
I have a NavigationStack with a navigationTitle and a TabView with 2 Views. Each View has a ScrollView (see image below):
NavigationStack and TabView problem image
When I tap on Tab1 (#1 in red on the image above), then swipe up, the behavior is as expected (#2), i.e. the big navigationTitle move to the center, and my view passes below and becomes blurry. Perfect.
However, when I tap ton Tab2 (#3) and then swipe up (#4), the big title stays big, and the view doesn't become blurry.
Then I tap on Tab1 again (#5) and it works as expected.
Please help!
Here is my code:
ContentView:
import SwiftUI
struct ContentView: View {
#State private var selection: Tab = .tab1
enum Tab {
case tab1
case tab2
}
#State private var mainTitle = "Tab1"
var body: some View {
NavigationStack {
TabView(selection: $selection) {
Tab1(mainTitle: $mainTitle)
.tabItem {
Label("Tab1", systemImage: "wrench.adjustable.fill")
}
.tag(Tab.tab1)
Tab2(mainTitle: $mainTitle)
.tabItem {
Label("Tab2", systemImage: "wrench.adjustable.fill")
}
.tag(Tab.tab2)
} .navigationTitle(mainTitle)
}
}
}
Tab1:
import SwiftUI
struct Tab1: View {
#Binding var mainTitle : String
var body: some View {
ScrollView {
Text("Text tab 1")
.padding(.all,100)
.background(.blue)
} .onAppear {
mainTitle = "Tab1"
}
}
}
Tab2:
import SwiftUI
struct Tab2: View {
#Binding var mainTitle : String
var body: some View {
ScrollView {
Text("Text tab 2")
.padding(.all,100)
.background(.green)
} .onAppear {
mainTitle = "Tab2"
}
}
}
I tried a hack that is supposed to fix the transparency bug for Tab bars, but it doesn't work.
.onAppear {
let tabBarAppearance = UITabBarAppearance()
tabBarAppearance.configureWithOpaqueBackground()
UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance
}
TabViews are designed to sit at the top of the navigation hierarchy. They're intended to allow users to switch between independent sections of your app at any time.
You would generally put a separate navigation stack within each tab that then handles pushing and popping of views. And then, you can use the navigationTitle modifier to manage the screen's title.
So your structure (which might be split over multiple custom views) should look something like:
TabView {
NavigationStack {
ScrollView {
}
.navigationTitle("Tab 1")
}
.tabItem { Label("Tab1", ...) }
NavigationStack {
ScrollView {
}
.navigationTitle("Tab 2")
}
.tabItem { Label("Tab2", ...) }
}
This structure is by design, to align with Apple's Human Interface Guidelines. It's worth reading the HIG to get a handle on where Apple are coming from, and how working on the same principles can really help your app feel like it belongs on your users' device.

How do I switch views by using a touch gesture on SwiftUI?

Hi I am pretty new to using SwiftUI. I have been having trouble with adding a tap gesture to my welcome page that will allow the user to move on to another view with drop down question boxes. I currently have this:
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "Globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Welcome to WOD planner!")
.font(.title)
.multilineTextAlignment(.center)
.onTapGesture{ action:{
//go to question page
}
}
}
.padding()
}
}
I made another view labeled QuestionPage. Im just confused how to code this gesture to make it change and isolate the two different views.
Thanks!
I solve this by having a State variable that will track the View that I want to show. Within the WindowGroup in my App, I now present the View that the viewState refers to.
This sample code should do the trick, it will change Views if you tap on the text in the middle of the screen. I personally would rather use a button, but it can be done with onTapGesture:
enum ViewState {
case welcomeView
case questionView
}
#main
struct MyApp: App {
#State var currentView: ViewState = .welcomeView
var body: some Scene {
WindowGroup {
switch (currentView) {
case .welcomeView:
WelcomeView(viewState: $currentView)
case .questionView:
QuestionView(viewState: $currentView)
}
}
}
}
struct WelcomeView: View {
#Binding var viewState: ViewState
var body: some View {
// your view here
Text("Welcome")
.onTapGesture { viewState = .questionView }
}
}
struct QuestionView: View {
#Binding var viewState: ViewState
var body: some View {
// your view here
Text("Some questions")
.onTapGesture { viewState = .welcomeView }
}
}

SwiftUI: NavigationLink pops out immediately on WatchOS 8.1RC in Tabview

I have discovered a regression in watchOS 8.1RC with NavigationLink triggered from a TabView.
It's immediately dismissed.
It was working in watchOS 8.0 or in Simulator (watchOS 8.0).
Do you know a workaround ?
Thanks
Sample code:
import SwiftUI
#main
struct TestNavigationApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
ContentView()
}
}
}
}
struct ContentView: View {
var body: some View {
List {
NavigationLink(destination: ContentView1()) {
Text("To TabView")
}
}
}
}
struct ContentView1: View {
var body: some View {
TabView {
NavigationView {
NavigationLink(destination: ContentView2()) {
Text("To ContentView2")
}
}
VStack {
Text("Screen2")
}
}
}
}
struct ContentView2: View {
var body: some View {
Text("ContentView2")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I'm experiencing the same issue with watchOS 8.1 (and 8.3 beta) while it was working with previous watchOS versions.
We were able to get it working again by moving the NavigationView inside the TabView. This workaround isn't ideal at all but it does seem to work.
#State private var tabSelection = 1
var body: some Scene {
WindowGroup {
TabView(selection: $tabSelection) {
NavigationView {
// List goes here
}
.tag(1)
VStack(alignment: .center, spacing: 12, content: {
// content 2nd tab: we didn't have a list in the 2nd tab
})
.tag(2)
}
}
}
However, there are 2 things impacted with this fix:
I didn't get the navigationBarTitle working, so there won't be a title on top of the screen.
If you click on an item in the list, it will navigate to your page (as expected) but the TabView dots at the bottom of the screen will remain.

SwiftUI View appear differently in device and preview compare to view hierarchy capture

I have a problem with SwiftUI
There was a issue
yello view don't appear at first launch view
move to home that makes app into background mode
move to app (foreground)
then yellow view appears
I captured view hierarchy in step 1.
(left is view hierarchy capture, right is simulator)
view hierarchy capture shows the yellow square but simulator didn't show yellow square
I checked the view breadscrum but both was same so I have no clue.
I'm sure this is not a networking problem.
There is two way to appear yellow square
background -> foreground
present alert -> dismiss alert
I'm not sure this is a framework bug or else.
Also, is there any API that I can print the swiftUI rendering request succeed or fail?
Thank you in advance and merry christmas!
(left is before yello square appear on simulator/ right is after yello square appear on simulator)
edit - add sample code
contentView
import SwiftUI
struct ContentView: View {
#ObservedObject var viewModel : viewModel
#ObservedObject var params : otherViewModel
var body: some View {
HorizontalScrollView(viewModel: viewModel, someParmas: params)
.padding(.leading, 24)
.frame(width: UIScreen.main.bounds.width, height:400)
.background(Color.red)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(viewModel: viewModel(homeAPI: HomeAPI()), params: otherViewModel())
}
}
import SwiftUI
struct HorizontalScrollView: View {
#ObservedObject var viewModel: viewModel
#ObservedObject var holder : otherViewModel
private var homeHightlightRange: Range<Int> {
return 0..<(viewModel.something?.somethingList?.count ?? 0)
}
init(viewModel: viewModel, someParmas: otherViewModel) {
self.viewModel = viewModel
self.holder = someParmas
}
var body: some View {
VStack(spacing: 20) {
HStack(spacing: 0) {
Text("Merry christmas")
.font(.system(size: 24))
.foregroundColor(.white)
.bold()
.onTapGesture {
viewModel.getHighlight()
}
Spacer()
}
ScrollView(.horizontal, showsIndicators: false, content: {
HStack(alignment:.bottom, spacing: 14) {
ForEach(homeHightlightRange, id: \.self) { index in
Color.yellow.frame(width:200, height:300)
}
}
})
}
.frame(height: 339)
}
}
struct HighlightView_Previews: PreviewProvider {
static var previews: some View {
HorizontalScrollView(viewModel: viewModel(homeAPI: HomeAPI()),someParmas: otherViewModel())
.previewLayout(.sizeThatFits)
}
}
homeHightlightRange is got from server via viewModel
I suppose that the solution is to add ScrollView conditionally on API results appear, like (not tested - typed here, so typos might be present)
if viewModel.something?.somethingList?.count != 0 {
ScrollView(.horizontal, showsIndicators: false, content: {
HStack(alignment:.bottom, spacing: 14) {
ForEach(homeHightlightRange, id: \.self) { index in
Color.yellow.frame(width:200, height:300)
}
}
})
}