So I have a tabview and a search with a NavigationView. If you click on a user you go to profile page and the profile page has a scrollview with grid where you can click and go to post details. If I remove the NavigationView from profileView it goes to post details but then back to profile. If I add the NavigationView it stays on the post details but then there are two navigation bars.
SearchView:
// MARK: - LIST OF USERS
// LIST DIDN'T WORK, HAD TO USE SCROLLVIEW
ScrollView {
LazyVStack(alignment: .leading) {
ForEach(userListVM.users.filter { searchText.isEmpty ? true : $0.fullname.localizedCaseInsensitiveContains(searchText)}, id: \.id) { user in
NavigationLink(
destination: UserProfileView(userVM: UserViewModel(user: user)),
label: {
SearchUserCellView(user: user)
}
)
}
} // END:LAZYVSTACK
} // END:SCROLLVIEW
ProfileView:
ScrollView {
UserProfileGridView(userVM: userVM)
} // END:SCROLLVIEW
GridView:
// MARK: - BODY
var body: some View {
LazyVGrid(columns: items, spacing: 2, content: {
ForEach(postListVM.posts.filter {$0.ownerUid == userVM.user.uid}, id: \.id) { post in
NavigationLink(
destination: CommentView(postVM: PostViewModel(post: post)),
label: {
if post.postImgUrl.isEmpty {
Image("dogs")
.resizable()
.scaledToFill()
.frame(width: width, height: width)
.clipped()
} else {
KFImage(URL(string: post.postImgUrl))
.resizable()
.scaledToFill()
.frame(width: width, height: width)
.clipped()
}
})
} // END:FOREACH
}) // END:LAZYVGRID
}
Related
I have added the .id(1) to the positions in the scrollview and can get it to work as expected if i add a button inside the scrollview but i want to use a picker to jump to the .id and outside the scrollview.
Im new to this.
I have this code:
if i use this button it works as expected although its placed inside the scrollview...
Button("Jump to position") {
value.scrollTo(1)
}
This is my picker...
// Main Picker
Picker("MainTab", selection: $mainTab) {
Text("iP1").tag(1)
Text("iP2").tag(2)
Text("Logo").tag(3)
Text("Canvas").tag(4)
}
.frame(width: 400)
.pickerStyle(.segmented)
ScrollViewReader { value in
ScrollView (.vertical, showsIndicators: false) {
ZStack {
RoundedRectangle(cornerRadius: 20)
// .backgroundStyle(.ultraThinMaterial)
.foregroundColor(.black)
.opacity(0.2)
.frame(width: 350, height:185)
// .foregroundColor(.secondary)
.id(1)
There are 2 things you are mixing here:
The tag modifier is to differentiate elements among certain selectable views. i.e. Picker TabView
You can't access the proxy reader from outside unless you make it available. In other words the tag in the Picker and the ScrollViewReader does not have a direct relationship, you have to create that yourself:
import SwiftUI
struct ScrollTest: View {
#State private var mainTab = 1
#State private var scrollReader: ScrollViewProxy?
var body: some View {
// Main Picker
Picker("MainTab", selection: $mainTab) {
Text("iP1").tag(1)
Text("iP2").tag(2)
Text("Logo").tag(3)
Text("Canvas").tag(4)
}
.frame(width: 400)
.pickerStyle(.segmented)
.onChange(of: mainTab) { mainTab in
withAnimation(.linear) {
scrollReader?.scrollTo(mainTab, anchor: .top)
}
}
ScrollViewReader { value in
ScrollView (.vertical, showsIndicators: false) {
ForEach(1...4, id: \.self) { index in
ZStack {
RoundedRectangle(cornerRadius: 20)
.foregroundColor(.black)
.opacity(0.2)
.frame(width: 350, height: 500)
Text("index: \(index)")
}
.id(index)
}
}
.onAppear {
scrollReader = value
}
}
}
}
Is it possible to add background color to the top of a picker view? I'm specifically interested in the area from the top of the view down to just below the navigation bar. I have made all my app tab and navigation views with the same header appearance but haven't had any luck with the pickers.
I would like to set the picker backgrounds to look like this:
Here is a picker view that I would like to add background color.
Here is what happens when adding call to DrawNavBox() just after the Picker (See code below). I need help pushing the green block to the top of the view.
The code below is what generates the Home Currency green header above
var body: some View {
GeometryReader { g in
VStack {
DrawNavBox(g: g) // draw green header
Text("Your home currency is:")
.padding(.top, g.size.height * 0.10)
Text("\(base.baseCur.baseCurrency) \(base.baseCur.baseCountry)")
.font(.body)
.fontWeight(.bold)
.foregroundColor(.white)
.padding(15)
.background(Color("Dark Green"))
.cornerRadius(20)
.padding(.trailing, g.size.width * 0.19)
.padding(.leading, g.size.width * 0.22)
Form {
Section(header: Text("Select Home Currency")) {
Picker("Home Currency", selection: $gotBase) {
DrawNavBox(g: g)
ForEach(0 ..< currCountry.count, id: \.self) { item in
VStack(alignment: .leading) {
Text(currCountry[item])
.font(.subheadline)
.padding(.leading, 25)
HStack {
Text(currSymbol[item])
Text(currName[item])
}
.font(.caption)
.padding(.leading, 25)
}
}
}
}
}
}
.navigationBarTitle(Text("Home Currency"), displayMode: .inline)
.navigationBarItems(trailing:
Button(action: {
// search for new base currency
self.changeBaseCurrency()
}) {
Text ("Save").bold()
}
)}
}
}
This is the code I have been using to set the navigation bar area green
struct DrawNavBox: View {
var g: GeometryProxy
var body: some View {
ZStack (alignment: .top) {
Color(.systemGreen)
.frame(height: (g.safeAreaInsets.top), alignment: .top)
.ignoresSafeArea()
}
}
}
I'm trying to reposition a list using scrollTo with a Slider and Button and have 2 problems. The list has Sections with id's and nested Texts below, so the scrolling (by Slider or Button) is to the Section heads only.
Here are the problems:
Slider works fine except that the animation briefly shows the list at the top (you can see the navigationTitle go to full size) before it scrolls to the desired position correctly.
The Button moves the Slider but appears to not find the id's in the Section, so it doesn't reposition to the right Section.
Anyone have any ideas?
struct Floors: Identifiable {
let id: String
let name: String
}
struct UnitLine: Identifiable {
let id=UUID()
let name: String
}
struct UnitKeyboardView: View {
#Environment(\.presentationMode) var presentationMode
#State private var sliderValue = 8.0
var body: some View {
let floors=[Floors(id:"8",name:"8"),Floors(id:"9",name:"9"),Floors(id:"10",name:"10"),Floors(id:"11",name:"11"),Floors(id:"12",name:"12"),Floors(id:"13",name:"13"),Floors(id:"14",name:"14"),Floors(id:"15",name:"15"),Floors(id:"16",name:"16"),Floors(id:"17",name:"17"),Floors(id:"18",name:"18"),Floors(id:"19",name:"19"),Floors(id:"20",name:"20"),Floors(id:"21",name:"21"),Floors(id:"22",name:"22"),Floors(id:"23",name:"23"),Floors(id:"24",name:"24"),Floors(id:"25",name:"25"),Floors(id:"26",name:"26"),Floors(id:"27",name:"27"),Floors(id:"28",name:"28"),Floors(id:"29",name:"29")]
let unitlines=[UnitLine(name:"01"),UnitLine(name:"02"),UnitLine(name:"03"),UnitLine(name:"04"),UnitLine(name:"05"),UnitLine(name:"06"),UnitLine(name:"07"),UnitLine(name:"08")]
NavigationView {
ScrollViewReader {proxy in
VStack {
Spacer()
List {
ForEach(floors) { i in
Section(header: Text("Floor \(i.name)")) {
ForEach(unitlines) { u in
Text(u.name)
.padding(.trailing,200)
.contentShape(Rectangle())
.onTapGesture {
print("tapped")
presentationMode.wrappedValue.dismiss()
}
}
}
}
}
HStack {
Spacer()
Text("Flr: \(Int(sliderValue))")
.font(.title)
.padding(10)
Button {
if sliderValue>8 {
sliderValue=sliderValue-1.0
proxy.scrollTo(String(Int(sliderValue)), anchor: .topLeading)
}
else { print("slider below (\(sliderValue))") }
print(proxy)
} label: {
Image(systemName: "minus")
}
.frame(width:30, height:15)
.padding(10)
.background(Color.red)
.clipShape(Capsule())
Slider(value: $sliderValue, in: 8...42, step: 1.0, onEditingChanged: {_ in
withAnimation {
proxy.scrollTo(String(Int(sliderValue)), anchor: .topLeading)
print(String(Int(sliderValue)))
}
}
)
.background(Color.cyan)
.border(Color.blue, width: 1)
.padding(10)
Button {
if sliderValue<42 {
print(sliderValue)
sliderValue=sliderValue+1.0
print(sliderValue)
proxy.scrollTo(String(Int(sliderValue)), anchor: .topLeading)
}
} label: {
Image(systemName: "plus")
}
.frame(width:30, height:15)
.padding(10)
.background(Color.green)
.clipShape(Capsule())
Spacer()
}
.background(Color.gray)
}
}
.navigationTitle("Select Address")
}
}
}
I'm trying to use my custom card view as label to navigation link. this navigation link is also a Grid item.
The result is a
My Card Code:
struct CityCard: View {
var cityData: CityData
var body: some View {
VStack {
Text("\(cityData.name)")
.padding([.top], 10)
Spacer()
Image(systemName: cityData.forecastIcon)
.resizable()
.frame(width: 45, height: 45)
Spacer()
HStack(alignment: .bottom) {
Text(String(format: "%.2f $", cityData.rate))
.padding([.leading, .bottom], 10)
Spacer()
Text(String(format: "%.2f °", cityData.degrees))
.padding([.trailing, .bottom], 10)
}
}.frame(width: 150, height: 150)
.background(Color.blue)
.cornerRadius(10)
.navigationTitle(cityData.name)
}
}
My List View:
struct CityList: View {
var cities: [CityData]
let columns = [
GridItem(.flexible(minimum: 150, maximum: 150)),
GridItem(.flexible(minimum: 150, maximum: 150))
]
var body: some View {
ScrollView {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(self.cities) { item in
NavigationLink(destination: Text(item.name), label: {
CityCard(cityData: item)
})
}
}
}
}
}
someone has a solution why it gives me this opacity?
Update:
The main contact view is:
It's greyed out because you don't yet have a NavigationView in your view hierarchy, which makes it possible to actually navigate to a new view.
You can, for example, wrap your ScrollView in a NavigationView:
var body: some View {
NavigationView {
ScrollView {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(self.cities) { item in
NavigationLink(destination: Text(item.name), label: {
CityCard(cityData: item)
})
}
}
}
}
}
Or, if it's only happening in your preview, add a NavigationView to your preview code:
NavigationView {
CityList(...)
}
Keep in mind that if you have the default accent color (blue, in light mode) that your links will become invisible (since they will be blue) on top of the blue background. You can set a custom accent color in your project or via the accentColor modifier:
NavigationView {
//content
}.accentColor(.black)
I have tried to use Buttons and Navigation Links from various examples when researched on this channel and on the net. The NavigationLink would be ok, except that the NavigationView is pushing everything down in my view.
I have a view that contains an image and a text like this: ( x Close) but when I use the code below, the Close button is not doing anything.
In ContentView() I have a (?) button that takes me from WalkthroughView(), then to the PageTabView, then to this view, TabDetailsView:
ContentView():
ZStack {
NavigationView {
VStack {
Text("Hello World")
.padding()
.font(.title)
.background(Color.red)
.foregroundColor(.white)
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
withAnimation {
showOnBoarding = true
}
} label: {
Image(systemName: "questionmark.circle.fill")
}
}
}
}
.accentColor(.red)
.disabled(showOnBoarding)
.blur(radius: showOnBoarding ? 3.0 : 0)
if showOnBoarding {
WalkthroughView(isWalkthroughViewShowing: $isWalkthroughViewShowing)
}
}
.onAppear {
if !isWalkthroughViewShowing {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation {
showOnBoarding.toggle()
isWalkthroughViewShowing = true
}
}
}
}
WalkthroughView():
var body: some View {
ZStack {
GradientView()
VStack {
PageTabView(selection: $selection)
// shows Previous/Next buttons only
ButtonsView(selection: $selection)
}
}
.transition(.move(edge: .bottom))
}
PageTabView():
var body: some View {
TabView(selection: $selection) {
ForEach(tabs.indices, id: \.self) { index in
TabDetailsView(index: index)
}
}
.tabViewStyle(PageTabViewStyle())
}
below, is the TabDetailsView():
At the top of the view is this Close button, when pressed, should send me back to ContentView, but nothing is happening.
struct TabDetailsView: View {
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
let index: Int
then, inside the body:
VStack(alignment: .leading) {
Spacer()
VStack(alignment: .leading) {
// Button to close each walkthrough page...
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "xmark.circle.fill")
Text("Close")
}
.padding(.leading)
.font(.title2)
.accentColor(.orange)
Spacer()
VStack {
Spacer()
Image(tabs[index].image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 415)
.padding(.leading, 10)
Text(tabs[index].title)
.font(.title)
.bold()
Text(tabs[index].text)
.padding()
Spacer()
}
.foregroundColor(.white)
}
}
if showOnBoarding {
WalkthroughView(isWalkthroughViewShowing: $isWalkthroughViewShowing)
}
Inserting view like above is not a presentation in standard meaning, that's why provided code does not work.
As this view is shown via showOnBoarding it should be hidden also via showOnBoarding, thus the solution is to pass binding to this state into view where it will be toggled back.
Due to deep hierarchy the most appropriate way is to use custom environment value. For simplicity let's use ResetDefault from https://stackoverflow.com/a/61847419/12299030 (you can rename it in your code)
So required modifications:
if showOnBoarding {
WalkthroughView(isWalkthroughViewShowing: $isWalkthroughViewShowing)
.environment(\.resetDefault, $showOnBoarding)
}
and in child view
struct TabDetailsView: View {
#Environment(\.resetDefault) var showOnBoarding
// .. other code
Button(action: {
self.showOnBoarding.wrappedValue.toggle()
}) {
Image(systemName: "xmark.circle.fill")
Text("Close")
}