I've started to develop on SwiftUI very recently (hence the simple question), so as an exercise to work with layouts, I'm trying to recreate Apple's own Music app. The main issue I'm facing is NavigationStack and lack of resources about it considering how new it is.
I've written the following code to replicate the Library tab:
NavigationStack{
List(menuCategories) {
menuCategory in NavigationLink(value: menuCategory
){
Label{
Text(menuCategory.name)
.font(.title2)
} icon:{ Image(systemName: menuCategory.imageName).foregroundStyle(.red)
}
}
.padding(.horizontal, -20)
}.navigationDestination(for: MenuCategory.self) {
menuCategory in
Text(menuCategory.name)
}
ScrollView(.vertical, showsIndicators: true){
VStack(alignment: .leading){
Text("Recently Added")
.font(.headline)
.padding(.horizontal, 20.0)
LazyVGrid(columns: [GridItem(.adaptive(minimum: 130), spacing: 20)]
){
ForEach(recentAlbums, id: \.self) {
item in
VStack(alignment: .leading){
ZStack{
Color(item.color)
Text(item.name)
}
.cornerRadius(10)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.aspectRatio(1.0, contentMode: .fit)
Text(item.name)
Text(item.artist)
.foregroundStyle(Color(.gray))
}
.padding(.bottom, 10.0)
.font(.body)
.lineLimit(1)
}
}
.padding(.horizontal, 20.0)
}
.navigationTitle("Library")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Edit") {
self.screen = 0;
}
}
}
}
}
.scrollContentBackground(.hidden)
.tabItem {
Image(systemName: "play.square.stack")
Text("Library")
}
Here's a preview of how it's looking:
The issue is, on both the Preview and the Simulator, the top List (Artists, Albums, etc) and the bottom Grid (Recently Added albums) have separate scrolling, so the whole page can't be scrolled down, you scroll on either of the areas, see the bottom area of the following screenshot as an example:
I've tried to move the top List into the ScrollView, but the whole List disappears and only the Grid is shown on screen. I've tried to move the different elements around but haven't found a combination that works yet... Any help will be greatly appreciated.
Thank you!
From my experience it's very hard to get any good result if you are using List
with anything else. So I suggest one of 2 options:
List
. It doesn't have to contain all the same items. You can put your links on top, and LazyVGrid
at the bottom, e.g.:struct HorizontalRow: View { // <-- first item type in the list
var text: String
var systemName: String
var body: some View {
HStack {
Text(text)
Image(systemName: systemName)
}
}
}
struct GridView: View { // <-- second item type in the list
var recentAlbums = [ "A", "B", "C" ]
var body: some View {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 130), spacing: 20)]){
ForEach(recentAlbums, id: \.self) { item in
VStack {
Image(systemName: "mic")
Text(item)
}
}
}
}
}
struct MainScreenView: View {
var listItems = ["One", "Two", "Three"]
var body: some View {
List { // <-- the list with different items
ForEach(listItems, id: \.self) { item in
HorizontalRow(text: item, systemName: "keyboard")
}
GridView()
}
}
}
ScrollView { LazyVStack {
, and place your elements (including grid) directly in LazyVStack
. This is better if you want a full control of how things look. But downside is you need to provide more styling where list already has it.