How do I add Navigation Buttons to SwiftUI app? - swift

I'm very new to Swift and SwiftUI in Xcode and have been working on an app.
I'm trying to have three buttons at the top of the main screen: HOME, ABOUT, HELP.
They all should bring the user to different views (or screens) when tapped on.
I already have the basis of the app created: the background, image, text, text field, and button (will set up for action at a later time). I'm wondering how I can add these buttons to the top of the app on top of my ZStack (which includes a VStack and an HStack) for the background. Here is my code so far:
import SwiftUI
struct ContentView: View {
#State private var accession: String = ""
var body: some View {
ZStack {
// Background navy blue
Rectangle()
.foregroundColor(Color(red: 10/255, green: 77/255, blue: 174/255)).edgesIgnoringSafeArea(.all)
// Background light blue
Rectangle()
.foregroundColor(Color(red: 86/255, green: 118/255, blue: 255/255))
.frame(height: 200)
.offset(x: 0, y: -200)
VStack {
// Image of Logo
Logo()
.offset(x: 0, y: -98)
// Text for user input
Text("Please enter the gene accession number below")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
.offset(x: -9, y: -10)
// Text field for user input Ω£
TextField("NG_017013", text: $accession)
.textFieldStyle(RoundedBorderTextFieldStyle())
.offset(x: 0, y: -8)
// Button
Button(action: {
// ParseXML()
}) {
Text("Find my gene! 🧬")
.font(.system(size: 23))
.foregroundColor(Color.white)
.bold()
.padding(.all, 10)
.background(Color(red: 86/255, green: 118/255, blue: 255/255))
.cornerRadius(20)
.offset(x: 0, y: 20)
}.padding()
}.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

You can wrap the ZStack in a NavigationView.
At the bottom inside the NavigationView add...
.navigationBarItems(
leading:
HStack {
NavigationLink(destination: Text("Home View")) {
Text("Home")
}
NavigationLink(destination: Text("About View")) {
Text("About")
}
},
trailing:
NavigationLink(destination: Text("Help View")) {
Text("Help")
}
)

Related

NavigationView doesn't show up correctly in ScrollView

I have encountered this problem during UI building. Previously, I've been asking here about NavigationView and why NavigationLink wasn't working. I fixed this problem with NavigationView at the top of my ScrollView. Now FrameView works just fine: opens and closes it in preview, which means I'm doing it right.
Here's the catch: When I add this LongFrameScrollView to my main view HomeView, it appears in some sort of frame and doesn't open link in full screen.
What am I doing wrong? How to fix that? Providing the code:
// Long frame view
import SwiftUI
struct LongFrameView: View {
var body: some View {
NavigationLink {
PlayerView()
} label: {
ZStack {
Rectangle()
.fill(LinearGradient(gradient: Gradient(colors: [Color(red: 0.268, green: 0.376, blue: 0.587), Color(red: 0.139, green: 0.267, blue: 0.517)]),
startPoint: .leading,
endPoint: .trailing))
.frame(width: 310, height: 62)
.cornerRadius(8)
HStack {
Image("mountains")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 70, height: 62)
.cornerRadius(8, corners: [.topLeft, .bottomLeft])
VStack(alignment: .leading) {
Text("Sense of anxiety")
.font(.custom("Manrope-Bold", size: 14))
.foregroundColor(.white)
Text("11 MIN")
.font(.custom("Manrope-Medium", size: 12))
.foregroundColor(.white)
}
Spacer()
}
}
.frame(width: 310, height: 62)
}
}
}
// Scroll View with LongFrame. Works fine in the preview
struct LongFrameScrollView: View {
let rows = Array(repeating: GridItem(.fixed(70), spacing: 10, alignment: .leading), count: 2)
var body: some View {
NavigationView {
ScrollView(.horizontal, showsIndicators: false) {
LazyHGrid(rows: rows, spacing: 10) {
// PLACEHOLDER UNTIL SERVER IS READY
LongFrameView()
LongFrameView()
LongFrameView()
LongFrameView()
}
}
.padding([.horizontal, .bottom], 10)
}
}
}
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .center) {
///
// Long frame. There is more view, but we'll just ignore them
LongFrameScrollView()
.padding(.bottom)
///
}
.padding(.top, 10)
}
.background(
Image("background2")
.resizable()
.aspectRatio(contentMode: .fill)
)
}
}
The reason why it wasn't working correctly is because it was in TabView. So, in order to work, our TabView must be in NavigationView and we must delete from all child views NavigationView.

View shifts downward upon navigation link in Swift

I am having a weird issue when I try to navigate back and forth between different views. On WelcomePage, when the user clicks sign in, they are directed to HomePage. HomePage has a navigation bar. Right now, all of the items on the nav bar redirect to HomePage. However, every time you navigate between the two pages using the navigation bar and the sign in button, the entire view is pushed downwards. Also, the navigation bar doesn't display in the preview.
Below is the relevant code from the WelcomePage
'''
struct WelcomePage: View {
var body: some View {
NavigationView{
NavigationLink(destination:HomePageView()){
Text("Sign in")
.font(.custom(buttons_font, size: 17))
.foregroundColor(.white)
.padding()
.background(
RoundedRectangle(cornerRadius: 15)
.fill(Color(red: 0.14, green: 1, blue: 0.73))
.frame(width: 208, height: 27)
.overlay(RoundedRectangle(cornerRadius: 15)
.stroke(Color.white, lineWidth: 1))
)
}
}}}
'''
And Here is the code from the Home Page
'''
struct HomePageView: View {
var body: some View {
ZStack{
(Color(#colorLiteral(red: 1, green: 0, blue: 0, alpha: 1)))
.ignoresSafeArea(.all)
.navigationBarItems(
leading:
Text("TITLE")
.font(
.custom(custom_font, size: 50))
.underline()
.foregroundColor(Color(#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)))
,
trailing:
HStack( spacing:0.00001) {
Spacer()
NavigationLink(destination:WelcomePage()){
Image("icon1")
}
NavigationLink(destination:WelcomePage()){
Image("icon2")
}
NavigationLink(destination:WelcomePage()){
Image("icon3")
}
}
)
}
}
}
'''
When I build and run this in my simulator.
On your issue about everything being pushed down to the bottom of the view, if you are using a ZStack I see that you've put a background color, then anything after that, wrap inside of a VStack or HStack. This way, I put in some Text, that text got pushed up inside of the HomePageView
HomePageView:
struct HomePageView: View {
var body: some View {
ZStack{
(Color(#colorLiteral(red: 1, green: 0, blue: 0, alpha: 1)))
.ignoresSafeArea(.all)
VStack {
Text("Hello Chap")
Button {
print("hello chap")
} label: {
Text("Hello Chap")
}
Spacer()
}
}
.navigationBarItems(leading: Text("Title"), trailing: HStack(spacing: 0.00001) {
Spacer()
NavigationLink(destination:WelcomePage()){
Image("icon1")
}
NavigationLink(destination:WelcomePage()){
Image("icon2")
}
NavigationLink(destination:WelcomePage()){
Image("icon3")
}
})
}
}
WelcomePage:
struct WelcomePage: View {
var body: some View {
NavigationView{
NavigationLink(destination:HomePageView()){
Text("Sign in")
//.font(.custom(buttons_font, size: 17))
.foregroundColor(.white)
.padding()
.background(
RoundedRectangle(cornerRadius: 15)
.fill(Color(red: 0.14, green: 1, blue: 0.73))
.frame(width: 208, height: 27)
.overlay(RoundedRectangle(cornerRadius: 15)
.stroke(Color.white, lineWidth: 1))
)
}
}}}

NavigationLink won't transition to new View upon selecting custom Button

When I embed my Button inside a NavigationLink and I set the destination to a Text View, the view doesn't transition upon clicking the button, although it sometimes does transition if I just randomly click around the button. What am I doing wrong?
Here is what I'm working with...
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView{
VStack{
Spacer()
VStack(spacing: 50){
NavigationLink(destination: Text("Testing")){
awButton(content: "Request Support", backColor: Color(#colorLiteral(red: 0.1764705926, green: 0.01176470611, blue: 0.5607843399, alpha: 1)))
}
}
Spacer()
}
.navigationBarTitle(Text("AccessWeb"))
.navigationBarItems(trailing: HStack{
Image(systemName: "bell")
.font(.system(size: 30))
Image(systemName:"person.circle")
.font(.system(size: 30))
Text("Tester")
.font(.system(size: 20))
})
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct awButton: View {
var content : String
var backColor : Color
var body: some View {
Button(action: {}, label: {
VStack {
HStack {
Image(uiImage: #imageLiteral(resourceName: "awText"))
.resizable()
.frame(width: 30, height: 20)
.padding(.leading)
Spacer()
}
.padding(.top)
HStack {
Text("\(content)")
.font(.title)
.fontWeight(.semibold)
.offset(y: 10.0)
}
Spacer()
}
})
.foregroundColor(Color(#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)))
.frame(width: 300, height: 150, alignment: .center)
.background(backColor)
.clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
}
}
The NavigationLink wraps everything in a button already (or at least something that receives click/tap events), so by also including a Button in your custom view, you're preventing those tap events from getting to the original NavigationLink.
But, since your action is empty, you can just take out your Button wrapper:
struct awButton: View {
var content : String
var backColor : Color
var body: some View {
VStack {
HStack {
Image(systemName: "pencil")
.resizable()
.frame(width: 30, height: 20)
.padding(.leading)
Spacer()
}
.padding(.top)
HStack {
Text("\(content)")
.font(.title)
.fontWeight(.semibold)
.offset(y: 10.0)
}
Spacer()
}
.foregroundColor(Color(#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)))
.frame(width: 300, height: 150, alignment: .center)
.background(backColor)
.clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
}
}

SwiftUI - My list doest not come all the way up to my navigation view

I can't seem to find the reason why there's a space between my list and navigation view. When I remove my navigation bar items, my list fills the space, when I have my navigation bar items, there's a gap between the navigation bar and my list. The style I'm using for my navigation bar is inline. Is this a bug in Xcode or is there something that I'm missing. Here's the code below.
...
import SwiftUI
struct DigitalReceiptContent: View {
#ObservedObject var store = ReceiptStore()
#State var showProfile = false
func addUpdate() {
store.updates.append(Update(name: "New Purchase", purchase: "$0.00", date: "00/00/21"))
}
var body: some View {
NavigationView {
List {
ForEach(store.updates) { update in
NavigationLink(destination: FullDigitalReceipt(update: update))
{
HStack {
Circle()
.frame(width: 50, height: 50)
.background(Color(#colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)))
.foregroundColor(.gray)
.cornerRadius(50)
.shadow(color: Color.black.opacity(0.6), radius: 2, x: 0, y: 1)
Text(update.name)
.font(.system(size: 20, weight: .bold))
.padding(.leading)
Spacer()
VStack(alignment: .trailing, spacing: 4.0) {
Text(update.date)
.font(.caption)
Text(update.purchase)
.foregroundColor(Color(#colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)))
.fontWeight(.heavy)
}
}
.padding()
}
}
.onDelete{ index in
self.store.updates.remove(at: index.first!)
}
}
.listStyle(GroupedListStyle())
.navigationBarTitle(Text("Purchases"), displayMode: .inline)
.navigationBarItems(
// Selection button; organize purchases
leading: EditButton(),
trailing: Button(action: {self.showProfile.toggle() }) { Image(systemName: "person.crop.circle")
}
.sheet(isPresented: $showProfile) {
ProfileSettings()
})
}
}
}
...

Align rectangle to be within certain distance of safe area bottom edge SWIFTUI

I am used to Interface Builder and layout constraints but now I want to convert my app to Swift UI. What I am trying to do right now is align the top edge of the view marked with a 1 to be within a certain distance of the safe area bottom edge (marked with a 2) so that the top edge that is now at 1 will then be at position 3. I tried using spacers but then it will look different on smaller devices such as an iPhone 8. In IB I could have used a simple layout constraint. How does this work in Swift UI? I have attached the relevant code and an image. Thank you for your help.
struct ContentView: View {
init() {
UINavigationBar.appearance().backgroundColor = .orange
}
var body: some View {
NavigationView {
VStack{
Spacer()
ZStack{
Rectangle()
.fill(Color(hue: 0, saturation: 0, brightness: 0, opacity: 0.1))
Image("")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100, height: 150)
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
}.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width, alignment: .center)
Spacer(minLength: 100)
ZStack(alignment: .bottom){
ExtractedView()
.edgesIgnoringSafeArea(.bottom)
}
}
.navigationBarTitle(Text("You See"))
.navigationBarHidden(false)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewDevice("iPhone")
}
}
struct ExtractedView: View {
#State private var name: String = ""
var body: some View {
VStack{
ZStack(alignment: .top){
VStack{
RoundedRectangle(cornerRadius: 50)
.frame(width: 60, height: 7)
.padding(.top)
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/) {
Text("Start advertising")
.font(.headline)
.foregroundColor(Color.black)
}.padding(.top)
TextField("Test", text: $name)
.padding(.all)
.background(Color.white.cornerRadius(20))
.padding()
}
RoundedRectangle(cornerRadius: 30)
.fill(Color(hue: 0, saturation: 0, brightness: 0, opacity: 0.1))
.zIndex(-5)
}
}
}
}
Ok, so I was able to solve my problem. The trick is to create two VStacks with different frame alignments. The outer VStack has top alignment so that the Discover view can be at the top. The inner VStack has a bottom alignment so that the sheet can be pulled up from the bottom. Space will be filled from the bottom up in this case.
VStack{
Discover()
.padding(.top, 60.0)
VStack{
Text("Recent Messages:")
.font(.headline)
DetailSheet()
.offset(x: 0, y: 0)
}.frame(width: g.size.width, height: (g.size.height - g.size.width - 80 + 200), alignment: .bottom)
}
.frame(width: g.size.width, height: g.size.height, alignment: .top)
you can try this:
offset -10 is just your offset you want to have....
i hope i understood you right, i am not so sure...
var body: some View {
VStack{
// ZStack(alignment: .top){
VStack{
RoundedRectangle(cornerRadius: 50)
.frame(width: 60, height: 7)
.padding(.top)
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/) {
Text("Start advertising")
.font(.headline)
.foregroundColor(Color.black)
}.padding(.top)
TextField("Test", text: $name)
.padding(.all)
.background(Color.white.cornerRadius(20))
.padding()
}.background(RoundedRectangle(cornerRadius: 30)
.fill(Color(hue: 0, saturation: 0, brightness: 0, opacity: 0.1))
).offset(y:-10)
}
// }