View shifts downward upon navigation link in Swift - 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))
)
}
}}}

Related

Only have one button active in dynamic list | SwiftUI

I have a list generated from a ForEach loop:
struct TrainingList: View {
#EnvironmentObject var trainingVM: TrainingViewModel
var body: some View {
VStack(alignment: .leading) {
Text("Your training sessions")
.font(.system(size: 35, weight: .semibold, design: .default))
.padding(.all, 10)
.foregroundColor(.white)
Divider()
ScrollView{
if(trainingVM.loading){
ProgressView("Loading training session").progressViewStyle(CircularProgressViewStyle(tint: .blue))
}
LazyVStack {
ForEach(trainingVM.trainingList) { training in
TrainingCell(training: training)
}
}
}
Spacer()
}
.background {
Rectangle()
.fill(Color(.sRGB, red: 41/255, green: 41/255, blue: 41/255))
.cornerRadius(10, corners: [.topRight, .bottomRight])
.shadow(color: .black.opacity(1), radius: 8, x: 6, y: 0)
}
.frame(width: 650)
.zIndex(.infinity)
}
}
Each TrainingCell has a button that opens an extra panel on the side of it. To indicate which row has the panel opened the button changes its styling:
struct TrainingCell: View {
#EnvironmentObject var trainingVM: TrainingViewModel
#State var showEvents = false
let training: Training
var body: some View {
HStack(spacing: 0) {
ZStack(alignment: .top) {
RoundedRectangle(cornerRadius: 10, style: .continuous)
.fill(Color(.sRGB, red: 41/255, green: 41/255, blue: 41/255))
VStack {
HStack(spacing: 10) {
VStack(alignment: .leading, spacing: 5) {
HStack{
Text(training.readableDate, style: .date)
.font(.system(size: 25, weight: .semibold, design: .default))
.foregroundColor(.white)
Text(" | ")
Text(training.readableDate, style: .time)
.font(.system(size: 25, weight: .semibold, design: .default))
.foregroundColor(.white)
}
VStack(alignment: .leading,spacing: 5){
HStack {
HStack(spacing: 5) {
Image(systemName: "person.text.rectangle.fill")
.foregroundColor(Color(.sRGB, red: 10/255, green: 90/255, blue: 254/255))
Text(training.instructor.fullName)
.foregroundColor(.white)
}
}
HStack{
ForEach(training.students){ student in
HStack(spacing: 5) {
Image(systemName: "person")
.imageScale(.medium)
.foregroundColor(Color(.sRGB, red: 10/255, green: 90/255, blue: 254/255))
Text(student.fullName_shortenedFirstName)
.foregroundColor(.white)
}
}
}
}
.font(.system(size: 20, weight: .regular, design: .default))
.foregroundColor(.primary)
}
.frame(maxHeight: .infinity, alignment: .center)
.clipped()
Spacer()
View_Close_Button(showEvents: $showEvents)
}
.frame(maxWidth: .infinity, maxHeight: 80, alignment: .top)
.padding(.all)
.background {
RoundedRectangle(cornerRadius: 0, style: .continuous)
.fill(Color(.sRGB, red: 41/255, green: 44/255, blue: 49/255))
.shadow(color: .black.opacity(1), radius: 5, x: 0, y: 5)
}
}
}
}
}
}
The button code:
struct View_Close_Button: View {
#EnvironmentObject var trainingVM: TrainingViewModel
#Binding var showEvents: Bool
var body: some View {
HStack
{
Image(systemName: showEvents ? "xmark" : "eye")
.imageScale(.large)
.padding(.horizontal, 5)
.font(.system(size: 17, weight: .regular, design: .default))
Text(showEvents ? "Close" : "View")
.padding(.all, 10)
.font(.system(size: 25, weight: .regular, design: .default))
.multilineTextAlignment(.leading)
}
.onTapGesture {
withAnimation(.easeIn(duration: 0.3)) {
showEvents.toggle()
if(showEvents) {
trainingVM.showingEvents = true
}else{
trainingVM.showingEvents = false
}
}
}
.foregroundColor(.white)
.background {
Capsule(style: .continuous)
.foregroundColor(showEvents ? Color(.sRGB, red: 253/255, green: 77/255, blue: 77/255) : Color(.sRGB, red: 10/255, green: 90/255, blue: 254/255))
.clipped()
.frame(maxWidth: 180)
}
}
}
Which should result in this:
The only problem I have is that all button can be activated at the same time. How would I go about disabling the rest of the button when one is tapped?
I need the user to only be able to have on of the button displayed as "X Close"
I tought about looping trough other buttons to deactivate them programatically before activating the one that was tapped but I have no clue how
You could keep track of the activated button in the parent view.
If you have some kind of unique identifier per button you could make a variable in the parent view that contains the active identifier.
You can pass that variable as a binding into the button views and depending on that you can change the views appearance.
This way there is always just one active button. When a button is clicked you can set the value of the binding variable in the button view with the unique identifier of this button and the other views change automatically.
On the TrainingList you can define a variable with the active tab:
#State var activeTab: Int = 0
On TrainingCell you can add this variable as a binding.
#Binding var activeTab: Int
And you pass it like:
TrainingCell(training: training, activeTab: $activeTab)
Then on View_Close_Button you can add two variables:
#Binding var activeTab: Int
#State var training: Training
And pass it like this on the TrainingCell:
View_Close_Button(showEvents: $showEvents, activeTab: $activeTab, training: training)
In the View_Close_Button you can use this to get the value and set the styles accordingly:
Image(systemName: activeTab == training.id ? "xmark" : "eye")
Text(activeTab == training.id ? "Close" : "View")
And you can set it when the button it tapped:
.onTapGesture {
withAnimation(.easeIn(duration: 0.3) {
activeTab = training.id
}
}

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()
})
}
}
}
...

How do I add Navigation Buttons to SwiftUI app?

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")
}
)

How do I have a button and a label share the same width using SwiftUI?

struct PasswordGenerator : View {
var body: some View {
NavigationView {
VStack {
Spacer()
//123
Text("Upon clicking the button the password\nwill also be copied so you\ncan simply paste")
.lineLimit(nil)
Spacer()
//123
Button(action: generatePassword) {
HStack {
Image("GeneratorGlyph")
Text("Generate!").font(.title)
}
.accentColor(.white)
.frame(minHeight: 56, maxHeight: 112)
.frame(minWidth: 0, maxWidth: .infinity)
}
.background(LinearGradient(gradient: Gradient(colors: [Color.init(red: 48/255, green: 153/255, blue: 216/255), Color.init(red: 65/255, green: 165/255, blue: 237/255)]), startPoint: .topLeading, endPoint: .bottomTrailing), cornerRadius: 9)
Spacer()
}
.navigationBarTitle(Text("Generator"), displayMode: .inline)
}
}
}
So I have a button and a Text label (I put a comment that says 123 over both of them so it's easier for you to see) and I was wondering how I could have the button have the same width as the Text label.
Just add padding to your button:
.padding(.horizontal, 40)