I want to create a simple NavigationView. But with code outside of it. Like this:
struct TestView: View {
var body: some View {
VStack{
RoundedRectangle(cornerRadius: 10)
.frame(width: 100, height: 100)
NavigationView {
VStack{
NavigationLink {
Text("HEllo")
} label: {
Text("Click me")
}
.navigationViewStyle(.columns)
}
.navigationTitle("A Title")
}
}
}
}
I do that so the navigation Title is below the item outside the NavigationView.
This code gives me this:
Image because I am not allowed to insert images yet.
When I click on the NavigationLink though I see this:
The Image
As you see the RoundedRectangle still is viewable at top of the screen. How can I fix that, so that the Rectangle disappears and the Destination is viewable in full screen?
Set navigation view first, You have to put everything inside the navigation view.
NavigationView { // Here
VStack{
RoundedRectangle(cornerRadius: 10)
.frame(width: 100, height: 100)
VStack{ // Remove from above
The RoundedRectangle is still visible because it is outside of the NavigationView, only the content of the NavigationView will move with the NavigationLink
Something you could do is to use the toolbar of the NavigationView to place items on the top of the screen
struct TestView: View {
var body: some View {
NavigationView {
NavigationLink {
Text("HEllo")
} label: {
Text("Click me")
}
.navigationViewStyle(.columns)
.navigationTitle("A Title")
.toolbar {
ToolbarItem {
RoundedRectangle(cornerRadius: 10)
.frame(width: 100, height: 100)
}
}
}
}
}
Related
I want to have an alert style view that can include an icon image at the top along with the title.
alert(isPresented:content:) used with Alert does not seem to support adding images in any way. However, other than that limitation, it functions as I want my alert to function. It covers the status bar and blurs the main view as the background for the alert.
I attempted to use fullScreenCover(isPresented:onDismiss:content:) instead, but this approach does not behave like an alert as far as covering up EVERYTHING including the status bar, and blurring the main view as the background.
I have tried this so far, with the following result. One of the reasons I want it to behave like a normal Alert is so that the content can scroll without overlapping the clock time.
struct AlertView: View {
#EnvironmentObject var dataProvider: DataProvider
var alert: Watch.AlertMessage
var body: some View {
ScrollView {
Image("IconAlert")
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width: 40, height: 40)
.foregroundColor(.accentColor)
Text("Test Title")
.bold()
Text("Test Description")
Button("DISMISS") { print("dismiss") }
}
.padding()
.ignoresSafeArea()
.navigationBarHidden(true)
}
}
Try this this sample custom alert. It may give you some great approach(Code is below the image):
struct CustomAlert: View {
#State var isClicked = false
var body: some View {
ZStack {
Color.orange.edgesIgnoringSafeArea(.all)
Button("Show Alert") {
withAnimation {
isClicked.toggle()
}
}
ZStack {
if isClicked {
RoundedRectangle(cornerRadius: 20)
.fill(.thickMaterial)
.frame(width: 250, height: 250)
.transition(.scale)
VStack {
Image("Swift")
.resizable()
.frame(width: 150, height: 150)
.mask(RoundedRectangle(cornerRadius: 15))
Button("Dismiss") {
withAnimation {
isClicked.toggle()
}
}
.foregroundColor(.red)
}
.transition(.scale)
}
}
}
}
}
How can I position my search-bar and button to the top of the screen with 65 padding from the top AND KEEP the onTapGestureFunctionality?
I tried the modifiers .edgesIgnoringSafeArea(.top) with padding(.top, 65) applied to the VStack inside my ZStack but then my onTapGesture would not work when tapping on either the search bar or the button...
Why does the Spacer() only push the elements about 80% to the top of the screen? Could this be because its inside a navigation view?
See image below.
Thank you
struct MapScreen: View {
var body: some View {
NavigationView {
ZStack(alignment: .bottom) {
VStack {
HStack(spacing: 15) {
SearchBar()
.padding(.leading, 5)
.onTapGesture {
print("search pressed")
}
ActivateClaimButton()
.onTapGesture {
print("claim pressed")
}
}
// 2 modifiers below positions correctly but
// onTapGesture doesn't work
// .padding(.top, 65)
// .edgesIgnoringSafeArea(.top)
Spacer()
}.zIndex(2)
MapView(locations: $locations, spotArray: $spotArray).edgesIgnoringSafeArea([.top, .bottom])
BottomNavBar().zIndex(1).edgesIgnoringSafeArea(.all).offset(y: 35)
}
.navigationViewStyle(StackNavigationViewStyle())
.fullScreenCover(isPresented: $presentSearchView, content: {
SearchView()
})
}
}
}
The answer that worked for me was
.navigationBarHidden(true)
I'm using Xcode 12 with deployment for iOS 14.0.
My home screen has a NavigationView
Within the NavigationView there is a TabView (with 4 tabs)
Within each tab are subviews that have buttons and NavigationLinks
The navigation on the app is functioning correctly (when I click a NavigationLink on one of the subviews, it navigates to the correct view and when I click the back button, it dismisses the view.) However, when I click the back button, the console prints the following error:
Trying to pop to a missing destination at /Library/Caches/com.apple.xbs/Sources/Monoceros/Monoceros-103/Shared/NavigationBridge_PhoneTV.swift:337
Aside from the error log, the app is functioning fine, so I'm planning to just ignore the error for now... but I'm wondering what it means? I don't have anything within my code named "Monoceros". I'm guessing it has something to do with the TabView being a subview of the NavigationView?
EDIT:
Several months later, this issue still persists. Here is reproducible code. Open the ContentView(), on the FirstScreen() click on the NavigationLink, then click the back button. It will print out Monoceros lol
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
TabView {
FirstScreen()
.tabItem {
Text("One")
Image(systemName: "house.fill")
}
Text("Second Screen")
.tabItem {
Text("Two")
Image(systemName: "heart.fill")
}
}
}
}
}
struct FirstScreen: View {
var body: some View {
NavigationLink("Click here", destination: Text("Final Screen"))
// Click the back button on FinalScreen prints:
//Trying to pop to a missing destination at /Library/Caches/com.apple.xbs/Sources/Monoceros_Sim/Monoceros-120/Shared/NavigationBridge_PhoneTV.swift:341
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Unfortunately this is an active issue with a TabView placed inside NavigationView.
The error would not manifest itself if you placed your NavigationView inside the TabView, but this of course would lead to the tabs being displayed from within your Final Screen, which you are probably trying to avoid.
There is currently no work-around for this, and as of to date we need to wait for Apple to properly implement the corresponding .navigationBarHidden() of TabViews as well.
Problems and unexpected behaviours have been reported when embedding a TabView into a NavigationView, however if you have tested your app thoroughly and found no particular problems, it is safe to say that you can stick to this method.
Alternatively you will have to build a TabView component manually, like below:
import SwiftUI
enum Tab {
case house, heart
}
struct TabView: View {
#Binding var tabIdx: Tab
var body: some View {
HStack {
Group {
Spacer()
Button (action: {
self.tabIdx = .house
}) {
VStack{
Image(systemName: "house.fill")
Text("House")
.font(.system(size: 10))
}
}
.foregroundColor(self.tabIdx == .house ? .blue : .secondary)
Spacer()
Button (action: {
self.tabIdx = .heart
}) {
VStack{
Image(systemName: "heart.fill")
Text("Heart")
.font(.system(size: 10))
}
}
.foregroundColor(self.tabIdx == .heart ? .blue : .secondary)
Spacer()
}
}
.padding(.bottom, 30)
.padding(.top, 10)
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
.font(.system(size: 30))
.frame(height: 80)
}
}
struct FirstScreen: View {
var body: some View {
NavigationLink("Click here", destination: Text("Final Screen"))
.font(.system(size:20))
}
}
struct ContentView: View {
#State var tabIdx: Tab = .house
var body: some View {
NavigationView {
VStack(spacing: 20) {
Spacer()
if tabIdx == .house {
FirstScreen()
} else if tabIdx == .heart {
Text("Second Screen")
}
Spacer(minLength: 0)
TabView(tabIdx: self.$tabIdx)
}
.ignoresSafeArea()
}
}
}
The above bug is well detailed in this blog post, which you could consult for further reference and more examples.
I'm quite new to programming so please excuse any dumb questions. I'm trying to make a ScrollView with the content being buttons. Although the button prints to console, when shown in the simulator the button displays as a large blue rectangle rather than displaying the image I would like it to.
Code Regarding ScrollView:
struct ContentView: View {
var body: some View {
[Simulator Display][1]
VStack {
Image("logo")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(.leading, 50)
.padding(.trailing, 50)
.padding(.top, 20)
.padding(.bottom, -20)
Spacer()
ScrollView {
VStack(spacing: 20) {
Button(action: {
//ToDo
print("Executed")
}) {
Image("Logo")
}
}
}
}
}
}
Simulator Display:
Image(Placeholder for now) I want to be displayed:
So I tried it an yeah it was very weird. Anyway, here is an example of how you can include the image. Just take the portion of the Button and paste it
struct ContentView: View {
var body: some View {
ZStack {
Button(action: {
print("button pressed")
}) {
Image("image")
.renderingMode(.original)
}
}
}
}
I try to use "sheet" modifier to popup a modal view when a List cell was tapped. I find that it's ok in the List Cell View (Modal View could popup multi-times when cell be clicked), but in List View the modal view popups just once.
I have tried using Gesture and Button to trigger the popup, I find that once I use "sheet" modifier to trigger the Modal View, the Result is all the same.
struct ContentView: View {
var body: some View {
List {
ForEach(0..<5) { _ in
ListRow()
}
}
}
}
struct ListRow: View {
#State var showDetail: Bool = false
var body: some View {
HStack(spacing: 20.0) {
Button(action: {self.showDetail = true}) {
HStack {
Text("BigTitle")
.font(.largeTitle)
.fontWeight(.heavy)
Spacer()
Text("SubTitle")
.font(.headline)
.fontWeight(.medium)
.padding(.trailing, 10)
}
}
.sheet(isPresented: self.$showDetail) {
DetailView()
}
}
.frame(width: 320, height: 48)
.padding()
}
}
struct DetailView: View {
var body: some View {
Text("I am Detail View!")
.font(.largeTitle)
.fontWeight(.heavy)
}
}
I had hoped that the modal view could be popped multiple-times in the List View, but in reality the popup occurred just once.
Hope you reply!
Thank you!