List Is scrolling only in single row - list

I am trying to display a list of enums with a section head.
I am iterating through 2 enums to display them in the same row.
The problem I am having is that the complete list is only showing in one row instead of each individual item displaying on its own row.
Why is this happening?
struct DisplayRow: View {
var body: some View {
List(0..<flaps.allCases.count, id: \.self) {index in
HStack {
Text(flaps.allCases[index].rawValue)
.frame(maxWidth:.infinity, alignment: .leading)
Text(woundscode.allCases[index].rawValue)
}
.padding(.all)
.border(Color.gray)
}
}
struct ContentView: View {
var body: some View {
List {
Section(header: Text("Flaps")) {
DisplayRow()
}
Section(header: Text("test")) {
Text("2")
Text("3")
}
}
I placed the 2nd section just as test.
Thanks in advance.
screenshot

Related

Picker scroll through one element horizontally

I have a SwiftUI Picker in which an item is selected. The text of one element can be large, so I used UIKit UIPickerView and set the manual height to 100, but at some point it became not enough. Is it possible to make scrolling horizontal for each element?
I want to get something like this:
Picker("Items", select: self._selectItem) {
ForEach(self.items, id: \.self) { item in
ScrollView(.horizontal, showsIndicators: false) {
Text(item.description)
}
.tag(item)
}
}
That should work fine. If you only want to scroll one item, you would have to insert a check of the item length.
let items = [
"A long item text.",
"And a even longer item text which is really going further.",
"Another item text which is really going further."
]
struct ContentView: View {
#State private var select = ""
var body: some View {
VStack {
Text("Make your selection!")
List(items, id: \.self) { item in
ScrollView(.horizontal) {
Text(item)
}
.listRowBackground(item == select ? Color.red : Color.white)
.onTapGesture {
select = item
}
}
}
}
}
I would strongly suggest to separate the picking from the text display and scrolling, e.g. like this:
struct ContentView: View {
#State private var select = items[0]
var body: some View {
VStack {
Text("Make your selection!")
Picker("Items", selection: $select) {
ForEach(items) { item in
Text(item.title)
.tag(item)
}
}
ScrollView {
Text(select.text)
}
.padding()
.frame(height: 200)
}
}
}

How to recreate the grid (in screenshot) in SwiftUI without breaking navigation?

I am trying to recreate a layout similar to the Reminders app. Looking at it makes me think it was built with SwiftUI. I also believe Apple mentioned so in one of the WWDC videos (can't remember which one).
This above screenshot seems to be a List, with a LazyVGrid as the first View inside the List. Tapping on each of the items in the LazyVGrid, such as Today, Scheduled, All and Flagged, navigates to the relevant screen, which means they are all NavigationLinks. Also note that the LazyVGrid has 2 columns.
And then there is another section "My Lists" which has rows which look like regular list rows in a List with style .insetGrouped. Also, every item in this Section is a NavigationItem, and thus comes with the disclosure indicator on the right as usual. Recreating this is trivial, so it has been left out from the MRE.
I am having trouble recreating the first section, which has that LazyVGrid. I faced 3 problems (as mentioned in the image), of which I have been able to solve the first one only. The other two problems remain. I want to know if this MRE can be fixed, or is my entire approach incorrect.
I am including a minimum reproducible example below.
import SwiftUI
#main
struct TestApp: App {
var body: some Scene {
WindowGroup {
RemindersView()
}
}
}
struct RemindersView: View {
private var columns: [GridItem] = [GridItem(.adaptive(minimum: 150))]
private var smartLists: [SmartList] = SmartList.sampleLists
var body: some View {
NavigationView {
List {
Section(header: Text("Using LazyVGrid")) {
grid
}
Section(header: Text("Using HStack")) {
hstack
}
}
.navigationTitle("Store")
}
.preferredColorScheme(.dark)
}
private var grid: some View {
LazyVGrid(columns: columns, spacing: 8) {
ForEach(smartLists) { smartList in
// This use of **ZStack with an EmptyView with opacity 0** is a hack being used to avoid the disclosure indicator on each item in the grid
ZStack(alignment: .leading) {
NavigationLink( destination: SmartListView(list: smartList)) {
EmptyView()
}
.opacity(0)
SmartListView(list: smartList)
}
}
}
.listRowInsets(EdgeInsets())
.listRowBackground(Color.clear)
}
private var hstack: some View {
ScrollView(.horizontal) {
HStack {
ForEach(smartLists) { smartList in
NavigationLink(destination: SmartListView(list: smartList)) {
SmartListView(list: smartList)
}
.buttonStyle(.plain)
}
}
}
.listRowInsets(EdgeInsets())
.listRowBackground(Color.clear)
}
}
struct RemindersView_Previews: PreviewProvider {
static var previews: some View {
RemindersView()
}
}
struct SmartList: Identifiable {
var id: UUID = UUID()
var title: String
var count: Int
var icon: String
var iconColor: Color
static var sampleLists: [SmartList] {
let today = SmartList(title: "Today", count: 5, icon: "20.circle.fill", iconColor: .blue)
let scheduled = SmartList(title: "Scheduled", count: 12, icon: "calendar.circle.fill", iconColor: .red)
let all = SmartList(title: "All", count: 77, icon: "tray.circle.fill", iconColor: .gray)
let flagged = SmartList(title: "Flagged", count: 5, icon: "flag.circle.fill", iconColor: .orange)
return [today, scheduled, all, flagged]
}
}
struct SmartListView: View {
var list: SmartList
var body: some View {
VStack(alignment: .leading, spacing: 8) {
HStack(alignment: .center) {
Image(systemName: list.icon)
.renderingMode(.original)
.font(.title)
.foregroundColor(list.iconColor)
Spacer()
Text("\(list.count)")
.font(.system(.title, design: .rounded))
.fontWeight(.bold)
.padding(.horizontal, 8)
}
Text(list.title)
.font(.system(.headline, design: .rounded))
.foregroundColor(.secondary)
}
.padding(8)
.background(
RoundedRectangle(cornerRadius: 12)
.foregroundColor(.gray.opacity(0.25))
)
.padding(2)
.frame(minWidth: 150)
}
}
EDIT 1: Adding video demo of what editing the dynamic Grid looks like and how the Grid has dynamic grid items (via the Edit button at the top right): https://imgur.com/a/TV0kifY

SwiftUI bug on NavigationLink when showing items as GridItem in List

Ok, I'm pretty sure this is a bug on Apple's part.
I fetch data using #SectionedFetchRequest.
I want to show links to detail in grids divided by sections (a bit like iOS Photos, where individual photos show as rectangles separated by a certain period, e.g. November 2021.
However, NavigationLink always opens the last item in a given grid, even if I tap some other item in this grid.
The important part: this issue does not occur when using ScrollView. It only occurs when using List.
A minimal example is below. Any fixes/workarounds will be much appreciated!
import SwiftUI
struct ItemsListView: View {
#EnvironmentObject var viewRouter: ViewRouter
#SectionedFetchRequest(
sectionIdentifier: SortModel.default.section,
sortDescriptors: SortModel.default.descriptors,
animation: .default
)
private var coreData: SectionedFetchResults<String, Item>
let layout = [GridItem(.adaptive(minimum: 100)),
GridItem(.adaptive(minimum: 100)),
GridItem(.adaptive(minimum: 100))]
var body: some View {
List { // **Bug disappears when List replaced with Scrollview**
ForEach(coreData) { section in
Section(header: Text(section.id)) {
LazyVGrid(columns: layout, spacing: 10) {
ForEach(section) { item in
Button(action: {
viewRouter.selectedItem = item
viewRouter.detailActive = true
}, label: {
LabelView(item: item)
})
} //: foreach
} //: LazyVGrid
} //: section
} //: ForEach section
} //: list
VStack(spacing: 0) {
NavigationLink(destination: ItemDetailView(item: viewRouter.selectedItem), isActive: $viewRouter.detailActive){ EmptyView() }
}
.hidden()
} //: body
} //: struct
struct LabelView: View {
let item: Item
var body: some View {
Image("\(item.image)") // some image
.resizable()
.scaledToFill()
.clipped()
.cornerRadius(12)
} //: body
} //: struct
struct ItemDetailView: View {
let item: Item
var body: some View {
VStack {
Text("This is the detail view for \(item.name)"
} //: vstack
} //: body
} //: struct

Multiple Picker views: Inconsistent, cycle drop down lists

I have a form with three different picker views. When I run the app and click on one of the pickers, the drop-down content is populated from another picker and it spontaneously cycles through the other two picker contents before returning to the main view. I am gogin to kick myself when someone points to something very fundamental and basic.... but here is the code . And thanks in advance!
var body: some View {
Form{
VStack {
HStack {
Text("PaO2")
TextField("mmHg", text: $PaO2)
.keyboardType(.numberPad)
Spacer()
Text("O2(%)")
TextField("%", text: $FiO2)
.keyboardType(.numberPad)
}
Toggle("Mechnical Ventilation", isOn: $MV)
HStack {
Text("Platelets")
TextField("(x1000)", text: $Platelets)
.keyboardType(.numberPad)
}
Picker(selection: $GCSSelected, label: Text("Glasgow Coma Scale")) {
ForEach(0..<GCS.count){ index1 in
Text(self.GCS[index1]).tag(index1)
}
}
Spacer()
Picker(selection: $HDSelected, label: Text("MAP/use of vasoactive Rx")){
ForEach(0..<HD.count){ index2 in
Text(self.HD[index2]).tag(index2)
}
}
HStack{
Text("Bilirubin")
TextField("mg/dL", text: $Bili)
.keyboardType(.numbersAndPunctuation)
}
Picker(selection: $RenalSelected, label: Text("Creatinine or Urine output")){
ForEach(0..<Renal.count){ index3 in
Text(self.Renal[index3]).tag(index3)
}
}
}
}
}
}
The issue is due to used single view for entire Form content, but you should not, so
var body: some View {
Form{
VStack { // << remove this container and let every picker be in own row

SwiftUI Add view below a list

I have a list with some items.
Below the list I'd like to have to button to load more items.
(As loading all items requires some user actions like entering a TAN, this should not be done automatically when the user scrolls to the end of the list, but only if he likes to.)
What I'd like to have is a view like this:
However, if I place the List and the Button in a VStack, the Button get always displayed at the bottom of the screen, not only when I scroll to the end of the List:
struct ContentView: View {
private let items = Range(0...15).map { "Item " + String($0) }
var body: some View {
VStack {
List(items, id: \.self) { item in
Text(item)
}
HStack {
Spacer()
Button("Load more") { print("Load more items") }
Spacer()
}
}
}
}
If I add the Button to the List, the Button obviously gets displayed as a List item with a white background and without any space to the list:
struct ContentView: View {
private let items = Range(0...15).map { "Item " + String($0) }
var body: some View {
List {
ForEach(items, id: \.self) { item in
Text(item)
}
HStack {
Spacer()
Button("Load more") { print("Load more items") }
Spacer()
}
}.listStyle(GroupedListStyle())
}
}
Is there any way to add a view that becomes visible when the user scrolls to the end of the List but that is not part of the List? (Or at least looks like being below the List and not part of it?)
You should use second variant, but a bit tuned, like below (colors/spaces modify per your needs
var body: some View {
List {
ForEach(items, id: \.self) { item in
Text(item)
}
HStack {
Button("Load more") { print("Load more items") }
}
.listRowInsets(EdgeInsets())
.frame(maxWidth: .infinity, minHeight: 60)
.background(Color(UIColor.systemGroupedBackground))
}.listStyle(GroupedListStyle())
}