I'm experiencing a strange visual bug with navigation bar titles. This swiftUI app has
a basic master/detail type view with a List view and a Detail view that is presented
with a NavigationLink. That Detail view is then a list of Texts displaying information
or a list of TextFields when the page is in the edit mode.
When in the Detail view with edit mode and I scroll to the bottom item in the list and
edit it then the navigationBarTitle on the first view has a ghost of the "Detail"
navigationBarTitle of the second view. If I don't scroll the ghosting does not appear.
By scrolling, I include the scroll so the keyboard does not hide the textfield.
If I change the Detail view navigationBarTitle to .inline the issues is a nearly
imperceptible flash with no permanent residual. Obviously, I will leave it in this mode
but I'd certainly prefer a standard iOS look and feel.
I've experimentally disabled every combination that I can think of - no joy.
The root List:
NavigationView {
List {
ForEach(myPhysicians, id: \.self) { mp in
NavigationLink(destination: PhysicianDetailView(physician: mp)) {
Text(mp.lastName ?? "no last name")
}
}
.onDelete { indexSet in
//standard core data delete process
}
}.navigationBarTitle("Physicians")
.navigationBarItems(
leading:
NavigationLink(destination: AddPhysicianView()) {
Image(systemName: "plus.circle.fill")
.font(.title)
},
trailing:
EditButton()
)//bar button items
}//nav
The Detail View:
var body: some View {
DispatchQueue.main.async {
self.localFirstName = self.physician.wrappedFirstName
self.localLastName = self.physician.wrappedLastName
//bunch more...
}
return ZStack(alignment: .topTrailing) {
List {
VStack { //group 1
VStack (alignment: .leading) {
Text("First Name:")
.font(.system(size: 14))
.font(.subheadline)
if !showEditView {
Text("\(physician.wrappedFirstName)")
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.vertical, 5)
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(.headline)
} else {
TextField("tf firstname", text: $localFirstName)
.modifier(TextFieldSetup())
}
}
VStack (alignment: .leading) {
Text("Last Name:")
.font(.system(size: 14))
.font(.subheadline)
if !showEditView {
Text("\(physician.wrappedLastName)")
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.vertical, 5)
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(.headline)
} else {
TextField("tf lastname", text: $localLastName)
.modifier(TextFieldSetup())
}
}
//bunch more...
}//outer vstack
}//list
.frame(maxWidth: .infinity - 20)
//.navigationBarTitle("Detail",displayMode: .inline)
.navigationBarTitle("Detail")
.navigationBarBackButtonHidden(true)
.navigationBarItems(
leading:
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
if self.showEditView {
Text("Cancel")
} else {
Image(systemName: "arrowshape.turn.up.left.circle.fill")
.font(.title)
}
},
trailing:
Button(action: {
if self.showEditView {
self.saveEditedPhysicianToCoreData(physician: self.physician)
}
self.showEditView.toggle()
}) {
Image(systemName: self.showEditView ? "gear" : "square.and.pencil")
.font(.title)
.frame(width: 60, height: 60)
}
)//nav bar items
}//zstack
.modifier(AdaptsToSoftwareKeyboard())
}//body
Any guidance would be appreciated. Xcode 11.6 iOS 13.6
Added: 29 July 2020
struct AdaptsToSoftwareKeyboard: ViewModifier {
#State var currentHeight: CGFloat = 0
func body(content: Content) -> some View {
content
.padding(.bottom, self.currentHeight)
.edgesIgnoringSafeArea(self.currentHeight == 0 ? Edge.Set() : .bottom)
.onAppear(perform: subscribeToKeyboardEvents)
}
private let keyboardWillOpen = NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { $0.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect }
.map { $0.height }
private let keyboardWillHide = NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in CGFloat.zero }
private func subscribeToKeyboardEvents() {
_ = Publishers.Merge(keyboardWillOpen, keyboardWillHide)
.subscribe(on: RunLoop.main)
.assign(to: \.self.currentHeight, on: self)
}
}
Related
I'm struggling with a view where I want to have multiple pickers embedded in
other views. When I wrap the pickers in a Form, I get the desired behavior for the
picker but there is a lot of extra space around the pickers that I can't seem to
automatically adjust.
This is an example - the space in the red outline seems to be determined by the other
view elements not the size of the picker.
I can, of course, hard-code a frame height for the Form but that is trial and error
and would only be specific to the device and orientation. I have tried multiple
versions of Stacks inside Stacks with padding, GeometryReader etc, but I have not come up with any
solution. As an aside, I DO want the picker labels, otherwise I could just remove
the Form.
I also tried setting UITableView.appearance().tableFooterView in an init() but that did not work either.
Here is a simplified version:
struct ContentView4: View {
#State var selectedNumber1: Int = 1
#State var selectedNumber2: Int = 2
#State var selectedNumber3: Int = 3
var body: some View {
NavigationView {
VStack(alignment: .leading) {
HStack {
Spacer()
Text("Compare up to 3")
.font(.caption)
Spacer()
}//h
Form {//for pickers
Picker(selection: $selectedNumber1, label: Text("A")) {
ForEach(0..<10) {
Text("\($0)")
}
}//picker
Picker(selection: $selectedNumber2, label: Text("B")) {
ForEach(0..<10) {
Text("\($0)")
}
}//picker
Picker(selection: $selectedNumber3, label: Text("C")) {
ForEach(0..<10) {
Text("\($0)")
}
}//picker
}//form for pickers
.padding(.horizontal, 10)
//.frame(height: 200) //don't want to hard code this
VStack(alignment: .leading) {
HStack {
Text("A")
.frame(width: 100)
Text("B")
.frame(width: 100)
Text("C")
.frame(width: 100)
}
.padding(.horizontal, 10)
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading){
Text("A title line")
.font(.headline)
.padding(.vertical, 5)
HStack {
Text("Number")
.frame(width: 100)
Text("Number")
.frame(width: 100)
Text("Number")
.frame(width: 100)
}
Text("Another title line")
.font(.headline)
.padding(.vertical, 5)
HStack {
Text("Something")
.frame(width: 100)
Text("Something")
.frame(width: 100)
Text("Something")
.frame(width: 100)
}
Text("A Third title line")
.font(.headline)
.padding(.vertical, 5)
HStack {
Text("More")
.frame(width: 100)
Text("More")
.frame(width: 100)
Text("More")
.frame(width: 100)
}
}
}//scroll
.padding(.horizontal, 10)
}
.navigationBarTitle("Compare Three", displayMode: .inline)
}
}//nav
}//body
}//struct
Interestingly, I am able to get a solution by removing the form and wrapping each
picker in a menu, like this:
Menu {
Picker(selection: $selectedNumber2, label: EmptyView()) {
ForEach(0..<10) {
Text("\($0)")
}
}//picker
} label: {
HStack {
Text("B")
Spacer()
Image(systemName: "chevron.right")
.resizable()
.frame(width: 14, height: 14)
}//h
}//menu label
However, I still like the look of the Form better if I could automatically configure
the space around the Form items.
Any guidance would be appreciated. Xcode 13.4, iOS 15.5
Form (and List) is not meant to be stacked inside other views like this, which is why it has such strange behavior.
Thankfully, it's fairly simple to recreate the stuff you do want using NavigationLink. Here’s a quick example of a couple custom views that do just that:
// drop-in NavigationLink replacement for Picker
struct NavigationButton<Content: View, SelectionValue: Hashable> : View {
#Binding var selection: SelectionValue
#ViewBuilder let content: () -> Content
#ViewBuilder let label: () -> Text
var body: some View {
NavigationLink {
PickerView(selection: $selection, content: content, label: label)
} label: {
HStack {
label()
Spacer()
Text(String(describing: selection))
.foregroundColor(.secondary)
}
.contentShape(Rectangle())
}
.buttonStyle(NavigationLinkButtonStyle())
}
}
// subview for the Picker page, which lets us use `dismiss()`
// to pop the subview when the user selects an option
struct PickerView<Content: View, SelectionValue: Hashable> : View {
#Binding var selection: SelectionValue
#ViewBuilder let content: () -> Content
#ViewBuilder let label: () -> Text
#Environment(\.dismiss) private var dismiss
var body: some View {
Form {
Picker(selection: $selection, content: content, label: label)
.pickerStyle(.inline)
.labelsHidden()
.onChange(of: selection) { _ in
dismiss()
}
}
.navigationTitle(label())
}
}
// recreate the appearance of a List row
struct NavigationLinkButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.label
.frame(maxWidth: .infinity)
Image(systemName: "chevron.right")
.font(.footnote.bold())
.foregroundColor(Color(UIColor.tertiaryLabel))
}
.padding()
.background(
Rectangle()
.fill(configuration.isPressed ? Color(UIColor.quaternaryLabel) : Color(UIColor.systemBackground))
)
}
}
If you like the .insetGrouped style you got using Form, we can replicate that by putting NavigationButton inside a clipped VStack:
VStack(spacing: 0) {
NavigationButton(selection: $selectedNumber1) {
ForEach(0..<10) {
Text("\($0)")
}
} label: {
Text("A")
}
Divider()
NavigationButton(selection: $selectedNumber2) {
ForEach(0..<10) {
Text("\($0)")
}
} label: {
Text("B")
}
}
.clipShape(RoundedRectangle(cornerRadius: 11))
.padding()
.background(Color(UIColor.systemGroupedBackground))
And here’s a screenshot showing my custom views above your original Form.
(And if you like Picker as a popup menu, you could use Menu instead of NavigationLink)
I have following problem. I want to create a vertical ScrollView with many rows. At the bottom of the view I have an info bar which appears over the scroll view because I put all the items in a ZStack. Here is my code and what it produces:
struct ProblemView: View {
var body: some View {
ZStack {
ScrollView(.vertical, showsIndicators: true) {
VStack {
ForEach(0..<100, id:\.self) {i in
HStack {
Text("Text \(i)")
.foregroundColor(.red)
Spacer()
Image(systemName: "plus")
.foregroundColor(.blue)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
Divider()
}
}
}
VStack {
Spacer()
HStack {
Text("Some Info here")
Image(systemName: "info.circle")
.foregroundColor(.blue)
}
.padding()
.frame(maxWidth: .infinity)
.ignoresSafeArea()
.background(.ultraThinMaterial)
}
}
}
}
struct ProblemView_Previews: PreviewProvider {
static var previews: some View {
ProblemView()
}
}
As you can see the drag indicator is hidden behind the info frame. Also the last item can't be seen because it is also behind the other frame. What
I want is that the drag indicator stops at this info frame. Why am I using a ZStack and not just a VStack? I want that this opacity effect behind the info frame, you get when you scroll.
A edit on my preview post has been added and therefore I cannot edit it... I am just gonna post the answer as an other one then.
This is the code that fixes your problem:
import SwiftUI
struct ProblemView: View {
var body: some View {
ScrollView {
VStack {
ForEach(0..<100, id:\.self) {i in
HStack {
Text("Text \(i)")
.foregroundColor(.red)
Spacer()
Image(systemName: "plus")
.foregroundColor(.blue)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
Divider()
}
}
.frame(maxWidth: .infinity)
}
.safeAreaInset(edge: .bottom) { // 👈🏻
VStack {
HStack {
Text("Some Info here")
Image(systemName: "info.circle")
.foregroundColor(.blue)
}
.padding()
.frame(maxWidth: .infinity)
.ignoresSafeArea()
.background(.ultraThinMaterial)
}
}
}
}
struct ProblemView_Previews: PreviewProvider {
static var previews: some View {
ProblemView()
}
}
We cannot control offset of indicator, but we can make all needed views visible by injecting last empty view with the same height (calculated dynamically) as info panel.
Here is possible approach. Tested with Xcode 13.2 / iOS 15.2
struct ProblemView: View {
#State private var viewHeight = CGFloat.zero
var body: some View {
ZStack {
ScrollView(.vertical, showsIndicators: true) {
VStack {
ForEach(0..<100, id:\.self) {i in
HStack {
Text("Text \(i)")
.foregroundColor(.red)
Spacer()
Image(systemName: "plus")
.foregroundColor(.blue)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
Divider()
}
Color.clear
.frame(minHeight: viewHeight) // << here !!
}
}
VStack {
Spacer()
HStack {
Text("Some Info here")
Image(systemName: "info.circle")
.foregroundColor(.blue)
}
.padding()
.frame(maxWidth: .infinity)
.ignoresSafeArea()
.background(.ultraThinMaterial)
.background(GeometryReader {
Color.clear.preference(key: ViewHeightKey.self,
value: $0.frame(in: .local).size.height)
})
}
}
.onPreferenceChange(ViewHeightKey.self) {
self.viewHeight = $0
}
}
}
struct ViewHeightKey: PreferenceKey {
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = value + nextValue()
}
}
In my app you go through the onboarding during sign-up. That works perfectly. However, you can go through it again via the Profile Page.
The profile page code in question looks like this (embedded in a top-level NavigationView of course)
NavigationLink(destination:
EndDateView().environmentObject(OnboardingVM(coordinator: viewModel.appCoordinator))
) {
HStack {
Image(systemName: "chart.pie.fill")
.font(.title)
Text("Edit Spending Plan")
.fontWeight(.bold)
.scaledFont("Avenir", 20)
}
}
.buttonStyle(ButtonWithIcon())
This leads you to a screen where you set a Date via a date picker. All is good at this point.
When you navigate to the third page of this flow (Profile -> Datepicker -> Set Income) and interact with a SwiftUI TextField, the #EnvironmentObject reinitializes itself.
Below you will see the code snippets that show how we navigate/pass the env object around
DatePicker Navigation Code
NavigationLink(destination: SetIncomeView().environmentObject(onboardingVM)) {
PurpleNavigationButton(buttonText: onboardingVM.continueButton)
}
SetIncome Code
struct SetIncomeView: View {
#EnvironmentObject var onboardingVM: OnboardingVM
#ObservedObject var setIncomeVM = SetIncomeVM()
var body: some View {
VStack {
HStack {
CustomHeader1(text: SetIncomeContent.title)
Button(action: {
setIncomeVM.info.toggle()
}) {
Image(systemName: "info.circle")
}
}
.alert(isPresented: $setIncomeVM.info) {
Alert(title: Text(SetIncomeContent.title),
message: Text(SetIncomeContent.header),
dismissButton: .default(Text(SetIncomeContent.dismiss)))
}.padding()
Spacer()
ScrollView {
HStack {
CustomHeader2(text: SetIncomeContent.income)
TextField("", text: $onboardingVM.expectedIncomeAmount)
.keyboardType(.numberPad)
.frame(width: 100, height: 35, alignment: .center)
.scaledFont("Avenir", 20)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
HStack {
CustomHeader2(text: SetIncomeContent.onBasis)
Picker(selection: $onboardingVM.selectedBasis, label: Text("")) {
ForEach(0 ..< self.onboardingVM.basis.count) {
Text(self.onboardingVM.basis[$0])
}
}
.frame(width: 100)
.clipped()
CustomHeader2(text: SetIncomeContent.basis)
}
Button(action: {
setIncomeVM.otherIncome.toggle()
}) {
if setIncomeVM.otherIncome {
Image(systemName: "minus.circle")
} else {
Image(systemName: "plus.circle")
}
Text(SetIncomeContent.anotherSource)
.foregroundColor(.black)
.underline()
.fixedSize(horizontal: false, vertical: true)
.padding()
}
//TODO: I am getting a bug where if i type or scroll it closes the view below
HStack {
CustomHeader2(text: SetIncomeContent.income)
TextField("", text: $onboardingVM.additionalIncome)
.keyboardType(.numberPad)
.frame(width: 100, height: 35, alignment: .center)
.scaledFont("Avenir", 20)
.textFieldStyle(RoundedBorderTextFieldStyle())
}.isHidden(!setIncomeVM.otherIncome)
HStack {
CustomHeader2(text: SetIncomeContent.onBasis)
Picker(selection: $onboardingVM.additionalBasis, label: Text("")) {
ForEach(0 ..< self.onboardingVM.basis.count) {
Text(self.onboardingVM.basis[$0])
}
}
.frame(width: 100)
.clipped()
CustomHeader2(text: SetIncomeContent.basis)
}.isHidden(!setIncomeVM.otherIncome)
}
Spacer()
NavigationLink(destination: SetSavingsView().environmentObject(onboardingVM),
isActive: $setIncomeVM.savingsLink1Active) {
Button(action: {
setIncomeVM.savingsLink1Active.toggle()
}) {
Text(SetIncomeContent.noIncome)
.foregroundColor(.black)
.underline()
.fixedSize(horizontal: false, vertical: true)
.padding()
}
}
NavigationLink(destination: SetSavingsView().environmentObject(onboardingVM), isActive: $setIncomeVM.savingsLink2Active) {
Button(action: {
self.onboardingVM.saveIncomeBasis()
if !setIncomeVM.savingsLink2Active {
setIncomeVM.savingsLink2Active.toggle()
}
}) {
PurpleNavigationButton(buttonText: onboardingVM.continueButton)
}
}
}
Spacer()
}
}
Any idea why this happens?
I am creating a custom list displaying time information (minutes and seconds, not used in the snippet below to simplify the code). I managed to implement a nice animation when the user adds an entry to the list, but deleting an entry has no animation (1st GIF).
With iOS 14, the animation is working, however, the animation only removes the last rectangle from the list and then updates the text in each row (2nd GIF). That's not what I want - My goal is if a row has been deleted, the other rows should fill up that space and move accordingly - with an animation.
Probably something is wrong with the IDs of the rows but I just wasn't able to fix that. Thanks for helping!
struct ContentView: View {
#State var minutes = [0]
#State var seconds = [0]
#State var selectedElement = 0
var body: some View {
ScrollView(){
VStack{
ForEach(minutes.indices, id: \.self){ elem in
ZStack{
EntryBackground()
Text("\(self.minutes[elem])")
.transition(AnyTransition.scale)
HStack{
Button(action: {
withAnimation(.spring()){
self.seconds.remove(at: elem)
self.minutes.remove(at: elem)
}
})
{
Image(systemName: "minus.circle.fill")
.foregroundColor(Color.red)
.font(.system(size: 22))
.padding(.leading, 10)
}
Spacer()
}
}
.padding(.horizontal)
.padding(.top)
.contentShape(Rectangle())
.onTapGesture {
withAnimation(.spring()){
self.selectedElement = elem
}
}
}
}
Spacer()
Button(action: {
withAnimation{
self.minutes.append(self.minutes.count)
self.seconds.append(0)
}
})
{
ZStack{
EntryBackground()
Text("Add")
HStack{
Image(systemName: "plus.circle.fill")
.foregroundColor(Color.green)
.font(.system(size: 22))
.padding(.leading, 10)
Spacer()
}
}.padding()
}
}
}
}
struct EntryBackground: View {
var body: some View {
Rectangle()
.cornerRadius(12)
.frame(height: 40)
.foregroundColor(Color.gray.opacity(0.15))
}
}
You need to make each row uniquely identified, so animator know what is added and what is removed, so animate each change properly.
Here is possible approach. Tested with Xcode 12 / iOS 14
struct TimeItem: Identifiable, Equatable {
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.id == rhs.id
}
let id = UUID() // << identify item
let minutes: Int
let seconds: Int = 0
}
struct ContentView: View {
#State var items = [TimeItem]()
#State var selectedElement: TimeItem?
var body: some View {
ScrollView(){
VStack{
ForEach(items){ elem in // << work by item
ZStack{
EntryBackground()
Text("\(elem.minutes)")
.transition(AnyTransition.scale)
HStack{
Button(action: {
self.items.removeAll { $0.id == elem.id }
})
{
Image(systemName: "minus.circle.fill")
.foregroundColor(Color.red)
.font(.system(size: 22))
.padding(.leading, 10)
}
Spacer()
}
}
.padding(.horizontal)
.padding(.top)
.contentShape(Rectangle())
.onTapGesture {
withAnimation(.spring()){
self.selectedElement = elem
}
}
}
}
Spacer()
Button(action: {
self.items.append(TimeItem(minutes: self.items.count))
})
{
ZStack{
EntryBackground()
Text("Add")
HStack{
Image(systemName: "plus.circle.fill")
.foregroundColor(Color.green)
.font(.system(size: 22))
.padding(.leading, 10)
Spacer()
}
}.padding()
}
}.animation(.spring(), value: items) // << animate changes
}
}
struct EntryBackground: View {
var body: some View {
Rectangle()
.cornerRadius(12)
.frame(height: 40)
.foregroundColor(Color.gray.opacity(0.15))
}
}
I'm trying to change the navigation bar title and leading & trailing items in a SwiftUI app.
Here is the situation:
A user logs in, then he gets transferred to a view inside a TabView.
Before login, in the welcome screen and login & register screens I have no navigation bar title, but after login, I want to add the navigation bar items and title.
What is important to know is that my after-login-view is inside a TabView.
If I wrap my after-login-view in a new NavigationView and then change the navigation bar items and title it works! but it shows me 2 navigation bars:
which is not what I want.
here is the code I use :
This is the after-Login-View
import SwiftUI
struct DiscoveryView: View {
var body: some View {
List{
Text("List Items")
}.offset(y: 10)
.navigationBarTitle("", displayMode: .inline)
.navigationBarItems(leading:
Text("Discovery").font(Font.custom("Quicksand- Bold", size: 24))
, trailing:
Button(action: {
}) {
HStack{
Text("120").font(Font.custom("Quicksand-Bold", size: 15)).foregroundColor(Color("BlueColor"))
Text("following").font(Font.custom("Quicksand-Bold", size: 15)).foregroundColor(Color.black)
}
}
).navigationBarBackButtonHidden(true)
}
}
This is the TabView:
struct TabController : View {
#State private var selection = 0
var body: some View {
TabView(selection: $selection){
DiscoveryView()
.tabItem {
VStack {
Image(systemName: "list.dash")
Text("Discover")
}
}.tag(1)
ExploreView()
.tabItem {
VStack {
Image(systemName: "square.and.pencil")
Text("Explore")
}
}.tag(2)
SelfProfileView()
.tabItem{
VStack {
Image(systemName: "person.circle")
Text("Profile")
}
}.tag(3)
}.accentColor(Color("BlueColor"))
}
}
This is the code of the login page:
import SwiftUI
struct LoginView: View {
var body: some View {
ZStack{
VStack{
Image("mainLogo").resizable().frame(width: 250, height: 125)
Text("").frame(width: UIScreen.main.bounds.width, height: 100)
HStack{
TextField("Username / Email", text: $email)
.padding(.leading, 10)
.frame(width: 313, height: 49)
.background(RoundedRectangle(cornerRadius: 4).stroke( Color.black.opacity(0.3)).frame(width: 313, height: 39).background(Color("GrayColor")))
}
Text("").frame(width: UIScreen.main.bounds.width, height: 40)
HStack {
HStack{
if self.visable{
TextField("Password", text: $password)
.padding(.horizontal)
} else {
SecureField("Password", text: $password)
.padding(.horizontal)
}
Button(action: {
self.visable.toggle()
}){
Image(systemName: self.visable ? "eye.slash" : "eye")
.padding(.trailing, 20)
.foregroundColor(Color.black)
}
}.background(RoundedRectangle(cornerRadius: 4).stroke( Color.black.opacity(0.3)).frame(width: 313, height: 39).background(Color("GrayColor")) )
}.padding(.horizontal, 40).padding(.vertical)
Text("").frame(width: UIScreen.main.bounds.width, height: 100)
Button(action: {
//pass email password and conpassword to cognito
DSManager().signIn(username: self.email, password: self.password, error: {
error in
if let error = error{
self.error = error.errorString
self.alert.toggle()
print(error.errorString)
}
else{
DSManager().getSelfUserInformation(response: {
userInfo, userCollections,dsError in
if let dsError = dsError{
self.error = dsError.errorString
self.alert.toggle()
print(dsError.errorString)
}
if let userInfo = userInfo{
print("success")
//use userInfo to load stuff for profile page
if let userCollections = userCollections{
self.profileInfo.setProperties(userInfo: userInfo, collections: userCollections)
}
else{
self.profileInfo.setProperties(userInfo: userInfo, collections: [:])
}
self.isComplete.toggle()
}
})
}
})
}) {
Text("Login")
.fontWeight(.semibold)
.frame(width: 313, height: 48)
.background(fillAllFields() ? Color("YellowColor") : Color.gray)
.foregroundColor(Color.white)
.font(.system(size: 17))
.cornerRadius(15)
.shadow(color: Color("GrayColor"), radius: 0, x: 3, y: 3)
}.disabled(!fillAllFields())
NavigationLink(destination: ProfileView(), isActive: $isComplete) {
EmptyView()
}
Spacer()
}
.padding()
.navigationBarTitle("", displayMode: .inline)
if self.alert {
ErrorView(err: $error, alert: $alert)
}
}
}
func fillAllFields() -> Bool {
if self.email == "" || self.password == "" {
return false
}
return true
}
}
As mentioned, I'm trying to edit bar items and title of a view inside and tab view .
Thanks!
So as per your updated question, I added DiscoveryView Inside NavigationView and it worked as expected. I have added code and screenshot as well.
struct TabController : View {
#State private var selection = 0
var body: some View {
TabView(selection: $selection) {
NavigationView {
DiscoveryView()
}
.tabItem {
VStack {
Image(systemName: "list.dash")
Text("Discover")
}
}.tag(1)
Text("Explore View")
.tabItem {
VStack {
Image(systemName: "square.and.pencil")
Text("Explore")
}
}.tag(2)
Text("SelfProfileView")
.tabItem{
VStack {
Image(systemName: "person.circle")
Text("Profile")
}
}.tag(3)
}.accentColor(Color("BlueColor"))
}}