Is there a problem with the way I'm structuring my SwiftUI project that causes .navigationTitle to not appear? - ios

My SwiftUI project refuses to display the navigation title after a certain point. I'm using a navigation structure that I haven't seen implemented on any example projects I've seen, but it makes sense to me and has been seeming to work thus far. My suspicion is that since I'm using a different navigation structure that it is part of the problem. The .navigationBar is there on every page, but the title doesn't display.
SettingsView.swift screen
I've tried many solutions on Stack Overflow and otherwise. I've tried every combination of .navigationBarHidden(false), .navigationBarTitle() and .navigationBarBackButtonHidden(true) on every page listed below, with no change. I've also tried every location I could think of to place these combinations of .navigationBar modifiers.
Recently, I discovered .toolbar, and this changes nothing either. My suspicion is that (as seen in the code snippets below) since the NavigationView is in the first view (WelcomeUI.swift), I can't place the .navigationBarTitle deeper in the code.
Below is my current navigation structure, and bits of code from each file:
WelcomeUI.swift
struct WelcomeUI: View {
var body: some View {
NavigationView {
VStack {
//NavigationLink(destination: SignupUI(), label: {
//Text("Sign Up")
//}
NavigationLink(destination: LoginUI(), label: {
Text("Log In")
}
}
}
}
}
LoginUI.swift
struct LoginUI: View {
var body: some View {
VStack {
NavigationLink(destination: MainUI(), label: { Text("Log In") })
//Button(action: { ... }
}
.navigationBarHidden(false)
}
}
Note: SignupUI.swift is essentially the same as LoginUI.swift
MainUI.swift
struct MainUI: View {
var body: some View {
TabView {
//SpendingView()
//.tabItem {
//Image(...)
//Text("Spending")
//}
//SavingView()
//.tabItem {
//Image(...)
//Text("Saving")
//}
//AddView()
//.tabItem {
//Image(...)
//Text("Add")
//}
//EditView()
//.tabItem {
//Image(...)
//Text("Edit")
//}
SettingsView()
.tabItem {
//Image(...)
Text("Settings")
}
}
.navigationBarBackButtonHidden(true)
}
}
Note: All views in MainUI.swift are structured the same.
SettingsView.swift
struct SettingsView: View {
var body: some View {
ZStack {
Form {
Section(header: Text("Section Header")) {
NavigationLink(destination: WelcomeUI()) {
Text("Setting Option")
}
}
Section {
//Button("Log Out") {
//self.logout()
//}
Text("Log Out")
}
}
.navigationBarTitle("Settings") // This has no effect on code no matter where it is place in SettingsView.swift
}
}
}
I should also note that only the pages after MainUI.swift is affected by this. WelcomeUI.swift and LoginUI.swift work as expected.

Look at the MainUI navigationTitle. I just put a title in every View to find what was going on.
import SwiftUI
struct SubSpendingView: View {
var body: some View {
ScrollView{
Text("SubSpendingView")
}.navigationBarTitle("SubSpending"
//, displayMode: .inline
)
}
}
struct SpendingView: View {
var body: some View {
ScrollView{
Text("SpendingView")
NavigationLink("subSpending", destination: SubSpendingView())
}.padding()
}
}
struct WelcomeUI: View {
var body: some View {
NavigationView {
VStack {
//NavigationLink(destination: SignupUI(), label: {
//Text("Sign Up")
//}
NavigationLink(destination: LoginUI(), label: {
Text("Go to Log In")
})
}.navigationTitle(Text("WelcomeUI"))
}
}
}
struct SettingsView: View {
var body: some View {
VStack{
ZStack {
Form {
Section(header: Text("Section Header")) {
NavigationLink(destination: WelcomeUI()) {
Text("Setting Option")
}
}
Section {
//Button("Log Out") {
//self.logout()
//}
Text("Log Out")
}
}
Button("say-high", action: {print("Hi")})
// This has no effect on code no matter where it is place in SettingsView.swift
}
}//.navigationBarTitle("Settings")
}
}
struct LoginUI: View {
var body: some View {
VStack {
NavigationLink(destination: MainUI(), label: { Text("Log In") })
//Button(action: { ... }
}.navigationTitle(Text("LoginUI"))
.navigationBarHidden(false)
}
}
struct MainUI: View {
#State var selectedTab: Views = .adding
var body: some View {
TabView(selection: $selectedTab) {
SpendingView()
.tabItem {
Image(systemName: "bag.circle")
Text("Spending")
}.tag(Views.spending)
//SavingView()
//.tabItem {
//Image(...)
//Text("Saving")
//}
Text("Adding View")
.tabItem {
Image(systemName: "plus")
Text("Add")
}.tag(Views.adding)
Text("Edit View")
.tabItem {
Image(systemName: "pencil")
Text("Edit")
}.tag(Views.edit)
SettingsView()
.tabItem {
Image(systemName: "gear")
Text("Settings")
}.tag(Views.settings)
}
//This overrides the navigationTitle in the tabs
.navigationBarTitle(Text(selectedTab.rawValue)
//, displayMode: .inline
)
.navigationBarBackButtonHidden(true)
}
}
enum Views: String{
case settings = "Settings"
case spending = "Spending"
case adding = "Add"
case edit = "Edit"
}
struct PaddyNav: View {
var body: some View {
WelcomeUI()
//Wont work
.navigationTitle(Text("PaddyNav"))
}
}
struct PaddyNav_Previews: PreviewProvider {
static var previews: some View {
PaddyNav()
}
}

Related

Refreshable Indicator is presented on view's appear

Once a view appears refreshable indicator is already visible without the necessity of performing the swipe on list. When I swipe the list up it hides and then pull to refresh can be performed in correct way (it shows, performs actions and hide).
My View:
struct OrdersView: View {
#EnvironmentObject private var tabBarStateManager: TabBarStateManager
#EnvironmentObject private var profileViewModel: ProfileViewModel
#StateObject private var ordersViewModel: OrdersViewModel = OrdersViewModel()
#Environment(\.dismiss) private var dismiss: DismissAction
var body: some View {
List {
ForEach(ordersViewModel.datesForOrdersViewListSections, id: \.self) { stringDate in
Section {
ForEach(ordersViewModel.getOrdersFor(date: stringDate), id: \.self) { order in
NavigationLink(destination: OrderDetailsView(order: order,
orderProductsList: ordersViewModel.getOrderProductsFor(order: order))
.environmentObject(ordersViewModel)) {
VStack(alignment: .leading, spacing: 20) {
HStack(spacing: 10) {
Text(order.id)
.font(.ssCallout)
Spacer()
Text(Date.getDayAndMonthFrom(date: order.orderDate))
.font(.ssTitle3)
.foregroundColor(.accentColor)
}
Text("$\(order.totalCost, specifier: "%.2f")")
.font(.ssTitle3)
.foregroundColor(.accentColor)
VStack(alignment: .leading) {
HStack {
Text(TexterifyManager.localisedString(key: .ordersView(.products)))
.font(.ssCallout)
Text("\(ordersViewModel.getOrderProductsFor(order: order).count)")
.font(.ssTitle3)
.foregroundColor(.accentColor)
}
HStack {
Text(TexterifyManager.localisedString(key: .ordersView(.orderStatus)))
.font(.ssCallout)
Text(order.status.rawValue)
.font(.ssTitle3)
.foregroundColor(.accentColor)
}
}
}
.padding(.vertical)
}
}
} header: {
Text(stringDate)
.font(.ssTitle1)
.foregroundColor(.accentColor)
}
}
}
.listStyle(.grouped)
.refreshable {
profileViewModel.fetchUserOrders {
ordersViewModel.userOrders = profileViewModel.userOrders
}
}
.navigationTitle(TexterifyManager.localisedString(key: .ordersView(.navigationTitle)))
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
dismiss()
} label: {
Image(systemName: "arrow.backward.circle.fill")
.resizable()
.frame(width: 30, height: 30)
.foregroundColor(.accentColor)
}
}
}
.onAppear {
ordersViewModel.userOrders = profileViewModel.userOrders
}
}
}
Changing .refreshable modifier order does not fix the problem
Changing .listStyle also does not help
The problem only occurs on physical device on iPhone 13 Pro Max (iOS 16.1). The same version of simulator does not have the problem.
EDIT:
I discovered that my problem only occurs when .navigationBarTitleDisplayMode is set to .inline instead of default .large
Screenshot:
Here is an example implementation, not exactly yours because you have complex structures that I was not able to reproduce. I hope you get some good from this example:
//
// ContentView.swift
// Refreshable
//
// Created by Allan Garcia on 11/11/22.
//
import SwiftUI
struct ContentView: View {
#State private var isLoading = true
// You may start the view starting with a loading state, before the data was loaded
#State private var myList = [String]() {
didSet {
isLoading = false
}
}
// Once the data is set isLoading (the loading state) is turned off
var body: some View {
NavigationView {
List {
if isLoading {
ProgressView()
.progressViewStyle(.circular)
.font(.largeTitle)
}
ForEach(myList, id: \.self) { item in
Text(item)
}
}
.listStyle(.plain)
.onAppear {
DispatchQueue.main.async {
isLoading = true
withAnimation {
self.myList = ContentView.fetchedList[0..<10].map { $0.uppercased() }
}
}
// On Appear you will probably fetch "some" data with pagination
}
.refreshable {
DispatchQueue.main.async {
withAnimation {
self.myList = ContentView.fetchedList.map { $0.uppercased() }
// A note here... refreshable is good when new data comes on top. If the data comes from bellow is
// a infinite scrolling approach much more advisable.
}
}
// .refreshable works fine here... ir will fetch more data... here it fetchs all, but is probably a
// good practice to fetch "some" more, and let the user read through until he wants to fetch more and
// trigger refreshable again.
}
}
.padding()
}
static let fetchedList = ["a","abandon","ability","able","abortion","about","above","abroad","absence","absolute","absolutely","absorb","abuse","academic","accept","access","accident","accompany","accomplish","according","account","accurate","accuse","achieve","achievement","acid","acknowledge","acquire","across","act","action","active","activist","activity","actor","actress","actual","actually","ad","adapt","add","addition","additional","address","adequate","adjust","adjustment","administration","administrator","admire","admission","admit","adolescent","adopt","adult","advance","advanced","advantage","adventure","advertising","advice","advise","adviser","advocate","affair","affect","afford","afraid","African","African-American","after","afternoon","again","against","age","agency","agenda","agent","aggressive","ago","agree","agreement","agricultural","ah","ahead","aid","aide","AIDS","aim","air","aircraft","airline","airport","album","alcohol","alive","all","alliance","allow","ally","almost","alone","along","already","also","alter","alternative","although","always","AM","amazing","American","among","amount","analysis","analyst","analyze","ancient","and","anger","angle","angry","animal","anniversary","announce","annual","another","answer","anticipate","anxiety","any","anybody","anymore","anyone","anything","anyway","anywhere","apart","apartment","apparent","apparently","appeal","appear","appearance","apple","application","apply","appoint","appointment","appreciate","approach","appropriate","approval","approve","approximately","Arab","architect","area","argue","argument","arise","arm","armed","army","around","arrange","arrangement","arrest","arrival","arrive","art","article","artist","artistic","as","Asian","aside","ask","asleep","aspect","assault","assert","assess","assessment","asset","assign","assignment","assist","assistance","assistant","associate","association","assume","assumption","assure","at","athlete","athletic","atmosphere","attach","attack","attempt","attend","attention","attitude","attorney","attract","attractive","attribute","audience","author","authority","auto","available","average","avoid","award","aware","awareness","away","awful","baby","back","background","bad","badly","bag","bake","balance","ball","ban","band","bank","bar","barely","barrel","barrier","base","baseball","basic","basically","basis","basket","basketball","bathroom","battery","battle","be","beach","bean","bear","beat","beautiful","beauty","because","become","bed","bedroom","beer","before","begin","beginning","behavior","behind","being","belief","believe","bell","belong","below","belt","bench","bend","beneath","benefit","beside","besides","best","bet","better","between","beyond","Bible","big","bike","bill","billion","bind","biological","bird","birth","birthday","bit","bite","black","blade","blame","blanket","blind","block","blood","blow","blue","board","boat","body","bomb","bombing","bond","bone","book","boom","boot","border","born","borrow","boss","both","bother","bottle","bottom","boundary","bowl","box","boy","boyfriend","brain","branch","brand","bread","break","breakfast","breast","breath","breathe","brick","bridge","brief","briefly","bright","brilliant","bring","British","broad","broken","brother","brown","brush","buck","budget","build","building","bullet","bunch","burden","burn","bury","bus","business","busy","but","butter","button","buy","buyer","by","cabin","cabinet","cable","cake","calculate","call","camera","camp","campaign","campus","can","Canadian","cancer","candidate","cap","capability","capable","capacity","capital","captain","capture","car","carbon","card","care","career","careful","carefully","carrier","carry","case","cash","cast","cat","catch","category","Catholic","cause","ceiling","celebrate","celebration","celebrity","cell","center","central","century","CEO","ceremony","certain","certainly","chain","chair","chairman","challenge","chamber","champion","championship","chance","change","changing","channel","chapter","character","characteristic","characterize","charge","charity","chart","chase","cheap","check","cheek","cheese","chef","chemical","chest","chicken","chief","child","childhood","Chinese","chip","chocolate","choice","cholesterol","choose","Christian","Christmas","church","cigarette","circle","circumstance","cite","citizen","city","civil","civilian","claim","class","classic","classroom","clean","clear","clearly","client","climate","climb","clinic","clinical","clock","close","closely","closer","clothes","clothing","cloud","club","clue","cluster","coach","coal","coalition","coast","coat","code","coffee","cognitive","cold","collapse","colleague","collect","collection","collective","college","colonial","color","column","combination","combine","come","comedy","comfort","comfortable","command","commander","comment","commercial","commission","commit","commitment","committee","common","communicate","communication","community","company","compare","comparison","compete","competition","competitive","competitor","complain","complaint","complete","completely","complex","complicated","component","compose","composition","comprehensive","computer","concentrate","concentration","concept","concern","concerned","concert","conclude","conclusion","concrete","condition","conduct","conference","confidence","confident","confirm","conflict","confront","confusion","Congress","congressional","connect","connection","consciousness","consensus","consequence","conservative","consider","considerable","consideration","consist","consistent","constant","constantly","constitute","constitutional","construct","construction","consultant","consume","consumer","consumption","contact","contain","container","contemporary","content","contest","context","continue","continued","contract","contrast","contribute","contribution","control","controversial","controversy","convention","conventional","conversation","convert","conviction","convince","cook","cookie","cooking","cool","cooperation","cop","cope","copy","core","corn","corner","corporate","corporation","correct","correspondent","cost","cotton","couch","could","council","counselor","count","counter","country","county","couple","courage","course","court","cousin","cover","coverage","cow","crack","craft","crash","crazy","cream","create","creation","creative","creature","credit","crew","crime","criminal","crisis","criteria","critic","critical","criticism","criticize","crop","cross","crowd","crucial","cry","cultural","culture","cup","curious","current","currently","curriculum","custom","customer","cut","cycle","dad","daily","damage","dance","danger","dangerous","dare","dark","darkness","data","date","daughter","day","dead","deal","dealer","dear","death","debate","debt","decade","decide","decision","deck","declare","decline","decrease","deep","deeply","deer","defeat","defend","defendant","defense","defensive","deficit","define","definitely","definition","degree","delay","deliver","delivery","demand","democracy","Democrat","democratic","demonstrate","demonstration","deny","department","depend","dependent","depending","depict","depression","depth","deputy","derive","describe","description","desert","deserve","design","designer","desire","desk","desperate","despite","destroy","destruction","detail","detailed","detect","determine","develop","developing","development","device","devote","dialogue","die","diet","differ","difference","different","differently","difficult","difficulty","dig","digital","dimension","dining","dinner","direct","direction","directly","director","dirt","dirty","disability","disagree","disappear","disaster","discipline","discourse","discover","discovery","discrimination","discuss","discussion","disease","dish","dismiss","disorder","display","dispute","distance","distant","distinct","distinction","distinguish","distribute","distribution","district","diverse","diversity","divide","division","divorce","DNA","do","doctor","document","dog","domestic","dominant","dominate","door","double","doubt","down","downtown","dozen","draft","drag","drama","dramatic","dramatically","draw","drawing","dream","dress","drink","drive","driver","drop","drug","dry","due","during","dust","duty","each","eager","ear","early","earn","earnings","earth","ease","easily","east","eastern","easy","eat","economic","economics","economist","economy","edge","edition","editor","educate","education","educational","educator","effect","effective","effectively","efficiency","efficient","effort","egg","eight","either","elderly","elect","election","electric","electricity","electronic","element","elementary","eliminate","elite","else","elsewhere","e-mail","embrace","emerge","emergency","emission","emotion","emotional","emphasis","emphasize","employ","employee","employer","employment","empty","enable","encounter","encourage","end","enemy","energy","enforcement","engage","engine","engineer","engineering","English","enhance","enjoy","enormous","enough","ensure","enter","enterprise","entertainment","entire","entirely","entrance","entry","environment","environmental","episode","equal","equally","equipment","era","error","escape","especially","essay","essential","essentially","establish","establishment","estate","estimate","etc","ethics","ethnic","European","evaluate","evaluation","even","evening","event","eventually","ever","every","everybody","everyday","everyone","everything","everywhere","evidence","evolution","evolve","exact","exactly","examination","examine","example","exceed","excellent","except","exception","exchange","exciting","executive","exercise","exhibit","exhibition","exist","existence","existing","expand","expansion","expect","expectation","expense","expensive","experience","experiment","expert","explain","explanation","explode","explore","explosion","expose","exposure","express","expression","extend","extension","extensive","extent","external","extra","extraordinary","extreme","extremely","eye","fabric","face","facility","fact","factor","factory","faculty","fade","fail","failure","fair","fairly","faith","fall","false","familiar","family","famous","fan","fantasy","far","farm","farmer","fashion","fast","fat","fate","father","fault","favor","favorite","fear","feature","federal","fee","feed","feel","feeling","fellow","female","fence","few","fewer","fiber","fiction","field","fifteen","fifth","fifty","fight","fighter","fighting","figure","file","fill","film","final","finally","finance","financial","find","finding","fine","finger","finish","fire","firm","first","fish","fishing","fit","fitness","five","fix","flag","flame","flat","flavor","flee","flesh","flight","float","floor","flow","flower","fly","focus","folk","follow","following","food","foot","football","for","force","foreign","forest","forever","forget","form","formal","formation","former","formula","forth","fortune","forward","found","foundation","founder","four","fourth","frame","framework","free","freedom","freeze","French","frequency","frequent","frequently","fresh","friend","friendly","friendship","from","front","fruit","frustration","fuel","full","fully","fun","function","fund","fundamental","funding","funeral","funny","furniture","furthermore","future","gain","galaxy","gallery","game","gang","gap","garage","garden","garlic","gas","gate","gather","gay","gaze","gear","gender","gene","general","generally","generate","generation","genetic","gentleman","gently","German","gesture","get","ghost","giant","gift","gifted","girl","girlfriend","give","given","glad","glance","glass","global","glove","go","goal","God","gold","golden","golf","good","government","governor","grab","grade","gradually","graduate","grain","grand","grandfather","grandmother","grant","grass","grave","gray","great","greatest","green","grocery","ground","group","grow","growing","growth","guarantee","guard","guess","guest","guide","guideline","guilty","gun","guy","habit","habitat","hair","half","hall","hand","handful","handle","hang","happen","happy","hard","hardly","hat","hate","have","he","head","headline","headquarters","health","healthy","hear","hearing","heart","heat","heaven","heavily","heavy","heel","height","helicopter","hell","hello","help","helpful","her","here","heritage","hero","herself","hey","hi","hide","high","highlight","highly","highway","hill","him","himself","hip","hire","his","historian","historic","historical","history","hit","hold","hole","holiday","holy","home","homeless","honest","honey","honor","hope","horizon","horror","horse","hospital","host","hot","hotel","hour","house","household","housing","how","however","huge","human","humor","hundred","hungry","hunter","hunting","hurt","husband","hypothesis","I","ice","idea","ideal","identification","identify","identity","ie","if","ignore","ill","illegal","illness","illustrate","image","imagination","imagine","immediate","immediately","immigrant","immigration","impact","implement","implication","imply","importance","important","impose","impossible","impress","impression","impressive","improve","improvement","in","incentive","incident","include","including","income","incorporate","increase","increased","increasing","increasingly","incredible","indeed","independence","independent","index","Indian","indicate","indication","individual","industrial","industry","infant","infection","inflation","influence","inform","information","ingredient","initial","initially","initiative","injury","inner","innocent","inquiry","inside","insight","insist","inspire","install","instance","instead","institution","institutional","instruction","instructor","instrument","insurance","intellectual","intelligence","intend","intense","intensity","intention","interaction","interest","interested","interesting","internal","international","Internet","interpret","interpretation","intervention","interview","into","introduce","introduction","invasion","invest","investigate","investigation","investigator","investment","investor","invite","involve","involved","involvement","Iraqi","Irish","iron","Islamic","island","Israeli","issue","it","Italian","item","its","itself","jacket","jail","Japanese","jet","Jew","Jewish","job","join","joint","joke","journal","journalist","journey","joy","judge","judgment","juice","jump","junior","jury","just","justice","justify","keep","key","kick","kid","kill","killer","killing","kind","king","kiss","kitchen","knee","knife","knock","know","knowledge","lab","label","labor","laboratory","lack","lady","lake","land","landscape","language","lap","large","largely","last","late","later","Latin","latter","laugh","launch","law","lawn","lawsuit","lawyer","lay","layer","lead","leader","leadership","leading","leaf","league","lean","learn","learning","least","leather","leave","left","leg","legacy","legal","legend","legislation","legitimate","lemon","length","less","lesson","let","letter","level","liberal","library","license","lie","life","lifestyle","lifetime","lift","light","like","likely","limit","limitation","limited","line","link","lip","list","listen","literally","literary","literature","little","live","living","load","loan","local","locate","location","lock","long","long-term","look","loose","lose","loss","lost","lot","lots","loud","love","lovely","lover","low","lower","luck","lucky","lunch","lung","machine","mad","magazine","mail","main","mainly","maintain","maintenance","major","majority","make","maker","makeup","male","mall","man","manage","management","manager","manner","manufacturer","manufacturing","many","map","margin","mark","market","marketing","marriage","married","marry","mask","mass","massive","master","match","material","math","matter","may","maybe","mayor","me","meal","mean","meaning","meanwhile","measure","measurement","meat","mechanism","media","medical","medication","medicine","medium","meet","meeting","member","membership","memory","mental","mention","menu","mere","merely","mess","message","metal","meter","method","Mexican","middle","might","military","milk","million","mind","mine","minister","minor","minority","minute","miracle","mirror","miss","missile","mission","mistake","mix","mixture","mm-hmm","mode","model","moderate","modern","modest","mom","moment","money","monitor","month","mood","moon","moral","more","moreover","morning","mortgage","most","mostly","mother","motion","motivation","motor","mount","mountain","mouse","mouth","move","movement","movie","Mr","Mrs","Ms","much","multiple","murder","muscle","museum","music","musical","musician","Muslim","must","mutual","my","myself","mystery","myth","naked","name","narrative","narrow","nation","national","native","natural","naturally","nature","near","nearby","nearly","necessarily","necessary","neck","need","negative","negotiate","negotiation","neighbor","neighborhood","neither","nerve","nervous","net","network","never","nevertheless","new","newly","news","newspaper","next","nice","night","nine","no","nobody","nod","noise","nomination","none","nonetheless","nor","normal","normally","north","northern","nose","not","note","nothing","notice","notion","novel","now","nowhere","n't","nuclear","number","numerous","nurse","nut","object","objective","obligation","observation","observe","observer","obtain","obvious","obviously","occasion","occasionally","occupation","occupy","occur","ocean","odd","odds","of","off","offense","offensive","offer","office","officer","official","often","oh","oil","ok","okay","old","Olympic","on","once","one","ongoing","onion","online","only","onto","open","opening","operate","operating","operation","operator","opinion","opponent","opportunity","oppose","opposite","opposition","option","or","orange","order","ordinary","organic","organization","organize","orientation","origin","original","originally","other","others","otherwise","ought","our","ourselves","out","outcome","outside","oven","over","overall","overcome","overlook","owe","own","owner","pace","pack","package","page","pain","painful","paint","painter","painting","pair","pale","Palestinian","palm","pan","panel","pant","paper","parent","park","parking","part","participant","participate","participation","particular","particularly","partly","partner","partnership","party","pass","passage","passenger","passion","past","patch","path","patient","pattern","pause","pay","payment","PC","peace","peak","peer","penalty","people","pepper","per","perceive","percentage","perception","perfect","perfectly","perform","performance","perhaps","period","permanent","permission","permit","person","personal","personality","personally","personnel","perspective","persuade","pet","phase","phenomenon","philosophy","phone","photo","photograph","photographer","phrase","physical","physically","physician","piano","pick","picture","pie","piece","pile","pilot","pine","pink","pipe","pitch","place","plan","plane","planet","planning","plant","plastic","plate","platform","play","player","please","pleasure","plenty","plot","plus","PM","pocket","poem","poet","poetry","point","pole","police","policy","political","politically","politician","politics","poll","pollution","pool","poor","pop","popular","population","porch","port","portion","portrait","portray","pose","position","positive","possess","possibility","possible","possibly","post","pot","potato","potential","potentially","pound","pour","poverty","powder","power","powerful","practical","practice","pray","prayer","precisely","predict","prefer","preference","pregnancy","pregnant","preparation","prepare","prescription","presence","present","presentation","preserve","president","presidential","press","pressure","pretend","pretty","prevent","previous","previously","price","pride","priest","primarily","primary","prime","principal","principle","print","prior","priority","prison","prisoner","privacy","private","probably","problem","procedure","proceed","process","produce","producer","product","production","profession","professional","professor","profile","profit","program","progress","project","prominent","promise","promote","prompt","proof","proper","properly","property","proportion","proposal","propose","proposed","prosecutor","prospect","protect","protection","protein","protest","proud","prove","provide","provider","province","provision","psychological","psychologist","psychology","public","publication","publicly","publish","publisher","pull","punishment","purchase","pure","purpose","pursue","push","put","qualify","quality","quarter","quarterback","question","quick","quickly","quiet","quietly","quit","quite","quote","race","racial","radical","radio","rail","rain","raise","range","rank","rapid","rapidly","rare","rarely","rate","rather","rating","ratio","raw","reach","react","reaction","read","reader","reading","ready","real","reality","realize","really","reason","reasonable","recall","receive","recent","recently","recipe","recognition","recognize","recommend","recommendation","record","recording","recover","recovery","recruit","red","reduce","reduction","refer","reference","reflect","reflection","reform","refugee","refuse","regard","regarding","regardless","regime","region","regional","register","regular","regularly","regulate","regulation","reinforce","reject","relate","relation","relationship","relative","relatively","relax","release","relevant","relief","religion","religious","rely","remain","remaining","remarkable","remember","remind","remote","remove","repeat","repeatedly","replace","reply","report","reporter","represent","representation","representative","Republican","reputation","request","require","requirement","research","researcher","resemble","reservation","resident","resist","resistance","resolution","resolve","resort","resource","respect","respond","respondent","response","responsibility","responsible","rest","restaurant","restore","restriction","result","retain","retire","retirement","return","reveal","revenue","review","revolution","rhythm","rice","rich","rid","ride","rifle","right","ring","rise","risk","river","road","rock","role","roll","romantic","roof","room","root","rope","rose","rough","roughly","round","route","routine","row","rub","rule","run","running","rural","rush","Russian","sacred","sad","safe","safety","sake","salad","salary","sale","sales","salt","same","sample","sanction","sand","satellite","satisfaction","satisfy","sauce","save","saving","say","scale","scandal","scared","scenario","scene","schedule","scheme","scholar","scholarship","school","science","scientific","scientist","scope","score","scream","screen","script","sea","search","season","seat","second","secret","secretary","section","sector","secure","security","see","seed","seek","seem","segment","seize","select","selection","self","sell","Senate","senator","send","senior","sense","sensitive","sentence","separate","sequence","series","serious","seriously","serve","service","session","set","setting","settle","settlement","seven","several","severe","sex","sexual","shade","shadow","shake","shall","shape","share","sharp","she","sheet","shelf","shell","shelter","shift","shine","ship","shirt","shit","shock","shoe","shoot","shooting","shop","shopping","shore","short","shortly","shot","should","shoulder","shout","show","shower","shrug","shut","sick","side","sigh","sight","sign","signal","significance","significant","significantly","silence","silent","silver","similar","similarly","simple","simply","sin","since","sing","singer","single","sink","sir","sister","sit","site","situation","six","size","ski","skill","skin","sky","slave","sleep","slice","slide","slight","slightly","slip","slow","slowly","small","smart","smell","smile","smoke","smooth","snap","snow","so","so-called","soccer","social","society","soft","software","soil","solar","soldier","solid","solution","solve","some","somebody","somehow","someone","something","sometimes","somewhat","somewhere","son","song","soon","sophisticated","sorry","sort","soul","sound","soup","source","south","southern","Soviet","space","Spanish","speak","speaker","special","specialist","species","specific","specifically","speech","speed","spend","spending","spin","spirit","spiritual","split","spokesman","sport","spot","spread","spring","square","squeeze","stability","stable","staff","stage","stair","stake","stand","standard","standing","star","stare","start","state","statement","station","statistics","status","stay","steady","steal","steel","step","stick","still","stir","stock","stomach","stone","stop","storage","store","storm","story","straight","strange","stranger","strategic","strategy","stream","street","strength","strengthen","stress","stretch","strike","string","strip","stroke","strong","strongly","structure","struggle","student","studio","study","stuff","stupid","style","subject","submit","subsequent","substance","substantial","succeed","success","successful","successfully","such","sudden","suddenly","sue","suffer","sufficient","sugar","suggest","suggestion","suicide","suit","summer","summit","sun","super","supply","support","supporter","suppose","supposed","Supreme","sure","surely","surface","surgery","surprise","surprised","surprising","surprisingly","surround","survey","survival","survive","survivor","suspect","sustain","swear","sweep","sweet","swim","swing","switch","symbol","symptom","system","table","tablespoon","tactic","tail","take","tale","talent","talk","tall","tank","tap","tape","target","task","taste","tax","taxpayer","tea","teach","teacher","teaching","team","tear","teaspoon","technical","technique","technology","teen","teenager","telephone","telescope","television","tell","temperature","temporary","ten","tend","tendency","tennis","tension","tent","term","terms","terrible","territory","terror","terrorism","terrorist","test","testify","testimony","testing","text","than","thank","thanks","that","the","theater","their","them","theme","themselves","then","theory","therapy","there","therefore","these","they","thick","thin","thing","think","thinking","third","thirty","this","those","though","thought","thousand","threat","threaten","three","throat","through","throughout","throw","thus","ticket","tie","tight","time","tiny","tip","tire","tired","tissue","title","to","tobacco","today","toe","together","tomato","tomorrow","tone","tongue","tonight","too","tool","tooth","top","topic"]
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Creating two sidebars in iPadOS application using SwiftUI

I have created one sidebar with NavigationView, which by default appends to the left of the landscape view of application. However I wanted to have another on the right side.
NavigationView {
List {
Label("Pencil", systemImage: "pencil")
Label("Paint", systemImage: "paintbrush.fill")
Label("Erase", systemImage: "quote.opening")
Label("Cutter", systemImage: "scissors")
Label("Eyedropper", systemImage: "eyedropper.halffull")
Label("Draw Line", systemImage: "line.diagonal")
}
.listStyle(SidebarListStyle())
}
Here's a simple working example made with SwiftUI:
struct ContentView: View {
var body: some View {
NavigationView{
TagView()
Text("Default second View")
Text("Default Third View")
}
}
}
struct TagView: View {
let tags = ["Apple", "Google"]
var body: some View {
List{
ForEach(tags, id: \.self) { name in
NavigationLink {
ProductView(tag: name)
} label: {
Text(name)
}
}
}
}
}
struct ProductView: View {
var tag: String
var products: [String] {
if tag == "Apple" {
return ["iPhone", "iPad", "MacBook"]
} else {
return ["resuable stuff"]
}
}
var body: some View {
List{
ForEach(products, id: \.self) { name in
NavigationLink {
DetailsView()
} label: {
Text(name)
}
}
}
}
}
struct DetailsView: View {
var body: some View {
Text("Detailed explanation about product")
}
}

Swiftui how to add a view above a tabview?

The requirement is to display a banner above the tabbar. So that the banner does not disappear when the tabs are changed? How can I achieve it?
I can think of starting points, to help you see ways to approach this, but I don't think either idea really meets your requirements. It will depend on the details of whether the banner is permanent, where its content comes from, etc.
The first idea:
struct BannerView : View {
var text : String
var body: some View {
VStack {
Spacer()
HStack {
Spacer()
Text(text)
Spacer()
}.background(Color.orange)
}
}
}
Then you can include this in a ZStack along with your tabs:
TabView {
ZStack {
Text("Tab 1")
BannerView("BANNER")
}.tabItem { Text("Home") }
ZStack {
Text("Tab 2")
BannerView("BANNER")
}.tabItem { Text("History") }
}
The second idea uses the BannerView from the first idea, but in a slightly cleaner way, still not great:
struct TabWrapperWithOptionalBanner<Content> : View where Content : View {
var showBanner : Bool
var content : Content
init(showBanner : Bool, #ViewBuilder content: () -> Content) {
self.showBanner = showBanner
self.content = content()
}
var body: some View {
ZStack {
content
if showBanner {
BannerView(text: "BANNER")
}
}
}
}
then your ContentView looks like this:
TabView {
TabWrapperWithOptionalBanner(showBanner: showBanner) {
Text("Tab 1")
}.tabItem { Text("Home") }
TabWrapperWithOptionalBanner(showBanner: showBanner) {
Text("Tab 2")
}.tabItem { Text("History") }
}
Update Try a pair of TabViews bound to the same State:
struct BanneredTabView: View {
#State private var selected = panels.one
var body: some View {
VStack {
TabView(selection: $selected) {
panels.one.label.tag(panels.one)
panels.two.label.tag(panels.two)
panels.three.label.tag(panels.three)
}
.tabViewStyle(PageTabViewStyle())
Text("Banner")
.frame(height: 40, alignment: .top)
TabView(selection: $selected) {
ForEach(panels.allCases) { panel in
Text("").tabItem {
panel.label
}
.tag(panel)
}
}
.frame(height: 30)
}
}
enum panels : Int, CaseIterable, Identifiable {
case one = 1
case two = 2
case three = 3
var label : some View {
switch self {
case .one:
return Label("Tab One", systemImage: "1.circle")
case .two:
return Label("Tab Two", systemImage: "2.square")
case .three:
return Label("Tab Three", systemImage: "asterisk.circle")
}
}
// so the enum can be identified when enumerated
var id : Int { self.rawValue }
}
}

How to use NavigationView and NavigationLink in SwiftUI?

Piece of code that I made for this question that runs in Playground:
import SwiftUI
struct Player {
let name: String
let surname: String
}
struct DetailView2: View {
var player: Player
var body: some View {
Text("\(player.name) \(player.surname)")
}
}
struct PlaygroundView: View {
// MARK: - Propertiers
#State private var selection = 0
private var players = [
Player(name: "Lionel", surname: "Messi"),
Player(name: "Diogo", surname: "Jota"),
]
// MARK: - View
var body: some View {
TabView(selection: $selection) {
NavigationView {
VStack {
Text("Settings").font(.title)
List(0..<players.count, id: \.self) { index in
NavigationLink(destination: DetailView2(player: players[index])) {
Text("\(index)")
}
}
}
.navigationTitle("Players")
.navigationBarTitleDisplayMode(.inline)
.navigationBarHidden(true)
}
.background(Color.white)
.tabItem {
Image(systemName: "house.fill")
Text("Players")
}
.tag(0)
VStack {
Text("Settings").font(.title)
List(0..<2, id: \.self) { index in
Text("#\(index)")
}
}
.tabItem {
Image(systemName: "book.fill")
Text("Foo")
}
.tag(1)
}
}
}
struct Playground_Previews: PreviewProvider {
static var previews: some View {
PlaygroundView()
}
}
Current Players bar:
Current Settings bar:
How can I fix the code such that "Players" bar will look like Settings bar (it terms of the styling of the title). It seems like I've got the tab item and navigation working already.
It seems you're looking something like below (prepared & tested with Xcode 12.1 / iOS 14.1)
var body: some View {
TabView(selection: $selection) {
VStack {
Text("Settings").font(.title)
NavigationView {
List(0..<players.count, id: \.self) { index in
NavigationLink(destination: DetailView2(player: players[index])) {
Text("\(index)")
}
}
.navigationBarTitleDisplayMode(.inline)
.navigationBarHidden(true)
}
}
.background(Color.white)
.tabItem {
Image(systemName: "house.fill")
Text("Players")
}
.tag(0)
VStack {
Text("Settings").font(.title)
List(0..<2, id: \.self) { index in
Text("#\(index)")
}
}
.tabItem {
Image(systemName: "book.fill")
Text("Foo")
}
.tag(1)
}
}

UI changes with ObservableObject just after switching tabs

I have a ObservableObject that I use to update my UI when new data is sent from the server (an a class which contains an array of custom structs).
For some reason, when the data is sent, the ContentView's body is called, but the data isn't changed. I even added a print statement to check if the data that the array contains is right and it is.
When I try to switch to another tab on my TabView, and then switch back to the main view, the UI does get updated. Does anybody know why the UI updates just when I switch tabs, although the body gets recalled to update the UI when the data changed?
HomeView
struct HomeView: View {
#ObservedObject private var fbData = firebaseData
var body: some View {
TabView {
//Home Tab
NavigationView {
ScrollView(showsIndicators: false) {
ForEach(self.fbData.posts.indices, id: \.self) { postIndex in
PostView(post: self.$fbData.posts[postIndex])
.listRowInsets(EdgeInsets())
.padding(.vertical, 5)
}
}
.navigationBarTitle("MyPhotoApp", displayMode: .inline)
.navigationBarItems(leading:
Button(action: {
print("Camera btn pressed")
}, label: {
Image(systemName: "camera")
.font(.title)
})
, trailing:
Button(action: {
print("Messages btn pressed")
}, label: {
Image(systemName: "paperplane")
.font(.title)
})
)
} . tabItem({
Image(systemName: "house")
.font(.title)
})
Text("Search").tabItem {
Image(systemName: "magnifyingglass")
.font(.title)
}
Text("Upload").tabItem {
Image(systemName: "plus.app")
.font(.title)
}
Text("Activity").tabItem {
Image(systemName: "heart")
.font(.title)
}
Text("Profile").tabItem {
Image(systemName: "person")
.font(.title)
}
}
.accentColor(.black)
.edgesIgnoringSafeArea(.top)
}
}
FirebaseData:
class FirebaseData : ObservableObject {
#Published var posts = [Post]()
let postsCollection = Firestore.firestore().collection("Posts")
init() {
self.fetchPosts()
}
//MARK: Fetch Data
private func fetchPosts() {
self.postsCollection.addSnapshotListener { (documentSnapshot, err) in
if err != nil {
print("Error fetching posts: \(err!.localizedDescription)")
return
} else {
documentSnapshot!.documentChanges.forEach { diff in
if diff.type == .added {
let post = self.createPostFromDocument(document: diff.document)
self.posts.append(post)
} else if diff.type == .modified {
self.posts = self.posts.map { (post) -> Post in
if post.id == diff.document.documentID {
return self.createPostFromDocument(document: diff.document)
} else {
return post
}
}
} else if diff.type == .removed {
for index in self.posts.indices {
if self.posts[index].id == diff.document.documentID {
self.posts.remove(at: index)
}
}
}
}
}
}
}
Your code example doesn't help to find the bug. Finally I've got how to demonstrate it. First, do it the "proper way" (copy - paste - try it yourself)
import SwiftUI
struct Data: Identifiable {
let id = UUID()
let text: String
}
class Model: ObservableObject {
#Published var data: [Data] = [Data(text: "alfa"), Data(text: "beta")]
}
struct ContentView: View {
#ObservedObject var model = Model()
var body: some View {
TabView {
View1(model: model).tabItem {
Text("View 1")
}
View2(model: model).tabItem {
Text("View 2")
}
}
}
}
struct View1: View {
#ObservedObject var model: Model
var body: some View {
VStack {
Text("View 1").font(.largeTitle)
DataView(data: model.data)
Button(action: {
self.model.data.append(Data(text: String("ABCDEFGH".shuffled())))
}) {
Text("Add random data")
}
}
}
}
struct View2: View {
#ObservedObject var model: Model
var body: some View {
VStack {
Text("View 2").font(.largeTitle)
DataView(data: model.data.filter({ (item) -> Bool in
item.text.count < 4
}))
// to distinguish from other DataView !! it seems to be a bug in SwiftUI
// try to remove it to see the difference
.id("view2")
Button(action: {
self.model.data.append(Data(text: String("ABC".shuffled())))
}) {
Text("Add random data")
}
}
}
}
struct DataView: View {
var data: [Data]
var body: some View {
List {
ForEach(data) { (item) in
Text(item.text)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I works as it should, you can modify the data from each tab, you see refreshed data, etc.
removing "fixed - user defined" .id modifier, it changes the behaviour dramatically
This looks like a serious bug in SwiftUI ...
I think is SwiftUI bug. I solve this problem like this.
Instead of rendering your PostView(post: self.$fbData.posts[postIndex])
implement post view inside ForEach.
ForEach(self.fbData.posts.indices, id: \.self) { postIndex in
Text(self.$fbData.posts[postIndex].comment)
Text(self.$fbData.posts[postIndex].date)
....
}

Resources