SwiftUI List - Enable Multiselection only on ONE section of List - swiftui

Goal:
Have two lists on one screen.
List 1:Should have multiple selections and reorder capability.
List 2:- My Lists: Should have Delete and reorder capabilty
Problem:
If i create 1 list with selections enabled, then it automatically applies this to all the sections of the list.
Code:
ZStack{
VStack {
//selection adds a checkmark to the list
List(selection:$categoryCollection.selectedCategories){
Section{
ForEach(categoryCollection.categories, id: \.self) { category in
CategoryListItem(name: category.name, icon: category.icon)
}
}
}
}
Section(header: Text("My lists"))
{
ForEach( todoListCollection.todoLists){ list in
TodoListRowView(todoList: list)
}
//THIS IS BEING OVERRIDEN BY SELECTION
.onDelete{
todoListCollection.removeList(indexSet: $0)
print("list removed")
}
.onMove {
todoListCollection.moveList(from: $0, to: $1)
print("list moved")
}
}.headerProminence(.increased)
}//list
.listStyle(InsetGroupedListStyle())
.toolbar {
EditButton()
}
Spacer()
Footer()
}
//VStack
.environment(\.editMode, $editMode)
.searchable(text: $queryString)
.searchable(text: $queryString,placement: .navigationBarDrawer(displayMode: .always))
}
}//navigationView

Related

How to add horizontal carousel above List in SwiftUI

I'm trying to recreate the layout of the native Watch app which has a carousel with a List underneath it. How can get the carousel in the first section to scroll off the edges of the screen instead of cut off?
Here's the code I'm trying:
let data: [String] = (0..<25).map { "Item \($0)" }
let data2: [String] = (0..<3).map { "Item \($0)" }
NavigationView {
List {
Section {
ScrollView(.horizontal) {
HStack {
ForEach(data) { element in
VStack {
Text(element)
}
.padding()
.background(Color(.secondarySystemBackground))
.cornerRadius(10)
}
}
}
}
.listRowBackground(Color.clear)
.listRowInsets(.init())
Section("Section 1") {
ForEach(data2) { element in
NavigationLink {
Text("Destination")
} label: {
Label(element, systemImage: "calendar.circle.fill")
}
}
}
}
.searchable(text: .constant(""), placement: .navigationBarDrawer(displayMode: .always))
.navigationTitle("Watch")
}
This is the native watch app I'm trying to replicate:

How to add a List with a TabView that has a List inside in SwftUI

I am wanting to add a TabView with a List, inside another List. The issue is that adding a list with a TabView that has a list inside makes it so that the view is small. Can't figure out if this scenario is possible.
The reason it needs two List is because i am going to add the Tab Selector as a sticky header, which comes built in by using Section inside the List.
#State private var selectedTab = 1
var body: some View {
List {
// TAB SELECTOR
HStack {
Spacer()
Button(action: {selectedTab = 1}) {
Text("First Tab")
}
Spacer()
Button(action: {selectedTab = 2}) {
Text("Second Tab")
}
Spacer()
Button(action: {selectedTab = 3}) {
Text("Thrid Tab")
}
Spacer()
}
// TABS
TabView(selection: $selectedTab) {
Text("First Tab View")
.tag(1)
VStack {
List {
ForEach(0 ..< 20) { index in
Text("This is index \(index)")
}
}
}
.tag(2)
Text("Third Tab View")
.tag(3)
}
}
}

SwiftUI List with Tow Functions in Edit Mode

I try to get two functions for list rows when the view became in edit mode as shown in the photo bellow one section for select and other section for deleting, I already separate them into two section in my code any try many things but it's not work.
And this is my code, and example for a section
var body: some View {
NavigationView {
List(selection: $selection) {
if isEditMode || !groupData.rowsGroup[0].filter({$0.isOnMain}).isEmpty {
firstSection
}
if !sortedFavoriteLists.isEmpty {
favoriteSection
}
if isEditMode || !groupData.rowsGroup[1].filter({$0.isOnMain}).isEmpty {
secondSection
}
}
.listStyle(InsetGroupedListStyle())
}
}
// This is the section and each section is "ForEach" View
private var firstSection: some View {
Section {
ForEach(firstSectionData, content: MainMenuRowView.init)
.onMove { indices, newOffset in
groupData.rowsGroup[0].move(fromOffsets: indices, toOffset: newOffset)
}
}
}
One problem solved by embed everything inside "Form", but know when I activate edit mode the Lise select not appear, anyone have an answer for how to activate the selection circle in the list???
This is example code
NavigationView{
Form{
List(selection: $selection) {
ForEach(data, id: \.self) { item in
Text(item)
}.onMove(perform: { indices, newOffset in
//
})
}
Section{
ForEach(data, id: \.self) { item in
Text(item)
}
.onDelete(perform: { indexSet in
//
})
.onMove(perform: { indices, newOffset in
//
})
}
}
.navigationBarTitle("Tilte")
.navigationBarTitle("Main Menu", displayMode: .inline)
.toolbar(content: {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
})
}
And this is how its look

SwiftUI EditButton in HStack not activating edit mode

As part of a bigger Form I'd like to have a Section with a List whose entries can be reordered.
In the whole view it should be only possible to edit that particular list, nothing else. Therefore I'd like to have the EditButton near the List.
If I just set the EditButton as the Section header, reordering List items works but I can't display a section title:
struct ContentView: View {
private let items = Range(1...4).map { "Item " + String($0) }
var body: some View {
Form {
Section(header: EditButton()) {
ForEach(items, id: \.self) { item in
Text(item)
}
.onMove(perform: reorderItems)
.onDelete(perform: deleteItems)
}
}
}
func reorderItems(from sourceIndices: IndexSet, to destinationIndex: Int) { /* ... */ }
func deleteItems(at offsets: IndexSet) { /* ... */ }
}
But if I wrap the EditButton in a HStack to display the button on the right, a tap on "Edit" changes the button's title to "Done" but doesn't start List's edit mode anymore:
struct ContentView: View {
#Environment(\.editMode) var editMode
private let items = Range(1...4).map { "Item " + String($0) }
var body: some View {
Form {
Section(header: HStack {
Text("Section title")
Spacer()
EditButton()
}.environment(\.editMode, self.editMode)) {
ForEach(items, id: \.self) { item in
Text(item)
}
.onMove(perform: reorderItems)
.onDelete(perform: deleteItems)
}
}
}
func reorderItems(from sourceIndices: IndexSet, to destinationIndex: Int) { /* ... */ }
func deleteItems(at offsets: IndexSet) { /* ... */ }
}
I also tried, as the code shows, passing the editMode environment variable to the HStack, but nothing helped.
Is there any way to get the EditButton inside an HStack working?
(Remark: As the List is part of a bigger Form, placing the EditButton out of the Section as suggested here is not an option in my case.)
Here is working solution - looks like they require that EditButton was a root view of section, so we can construct everything else above it. (tested with Xcode 11.4 / iOS 13.4)
Note: #Environment(\.editMode) var editMode is not needed
Section(header:
EditButton().frame(maxWidth: .infinity, alignment: .trailing)
.overlay(Text("Header"), alignment: .leading)
)
{
ForEach(items, id: \.self) { item in
Text(item)
}
.onMove(perform: reorderItems)
.onDelete(perform: deleteItems)
}

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())
}