How to set the List Height when List is empty? - swiftui

I got my data from API and put them in a list. My problem is that is it possible to set fixed height when the array in the list were all deleted? I use environment(.defaultMinListRowHeight, 80) but it didn't work.Please help. Thank you
func containedView() -> AnyView {
switch self.selectedIndex {
case 0:
return AnyView(
List(userNotifications1.userNotificationsArray) { userNotification in
UserNotificationCellView(userNotification: userNotification,userNotifications: self.userNotifications1)
}.environment(\.defaultMinListRowHeight, 80)
.environment(\.defaultMinListHeaderHeight, 10)
)
case 1:
return AnyView(
List {
ForEach(managerNotifications, id: \.id) { (managernotification) in
ManagerNotificationCellView(managerNotification : managernotification)
}.onDelete(perform: self.deleteManagerNotification)
}
)
default:
return AnyView(Text("22").padding(40))
}
when list has data, the cell's height are bigger
when list is empty,the cell's height was small

Make sure to set environment variable in correct place. Below tested as works with Xcode 11.2 / iOS 13.2.
List {
// ... list content here
}
.environment(\.defaultMinListRowHeight, 80) // << should be for List

Related

SwiftUI - Picker has two sets of init - what are the second set for? and how do i get selected item?

Im going through SwiftUI Controls in detail and writing example code for each init.
Theres two sets of inits for Picker.
One where you fill your list from an array etc. and what you pick goes into selection: binding.
But whats the second set of inits for?
Theyre under section 'Creating a picker for a collection'
I can fill the array from a collection using both these inits ok
But how do you get the selected item using the 2nd set of inits?
The selection: param is no longer a binding to an ivar but a Keypath to fill the list.
My question is how do I get the selected item using the 2nd set of inits.
See inits here:
https://developer.apple.com/documentation/swiftui/picker
For Picker there are 6 inits.
3 under 'Creating a picker'
these are ok. I fill the list from an array for example and store the selected item in a single result specified by the selection: param. It binds the result to one ivar.
There are also 3 inits under 'Creating a picker for a collection'
I got this to display the items from a collection
e.g. I modified the example code in the apple docs. The code in the docs doesn't compile so apple may be missing stuff.
import SwiftUI
enum Thickness: String, CaseIterable, Identifiable {
case thin
case regular
case thick
var id: String { rawValue }
}
//to use in ist must be Hashable
struct Border: Identifiable {
var color: Color
var thickness: Thickness
//Identifiable > Hashable > id > String
//var id: String { return "\(color.hashValue)" }
let id = UUID()
}
extension Color{
func colorName() -> String{
if self == Color.black{
return "black"
}
else if self == Color.red{
return "red"
}
else{
return "UNHANDLED"
}
}
}
struct CLCPickers_selection_FromCollection_View: View {
#State private var selectedObjectBorders = [
Border(color: .black, thickness: .thin),
Border(color: .red, thickness: .thick)
]
var body: some View {
VStack{
//------------------------------------------------------------------
Picker(
"Border Thickness",
sources: $selectedObjectBorders,
selection: \.thickness
) {
//------------------------------------------------------------------
//I added
//id: \.self
//Picker: the selection "thin" is invalid and does not have an associated tag, this will give undefined results.
//------------------------------------------------------------------
ForEach(Thickness.allCases,
id: \.self)
{ thickness in
Text(thickness.rawValue)
}
}
//------------------------------------------------------------------
Divider()
//------------------------------------------------------------------
//This just lists the colors in the arrays of Border
//QUESTION - how do I find out the currenly selected one?
//normaly selection: in the picker would be bound to the picked item
//but for this init selection: is a keypath
//selection: \.thickness
//so I can fill the Picker list using the keypath into the Border array.
//BUT HOW DO I FIND OUT THE CURRENTLY SELECTED ITEM?
//theres no binding?
//is there a .selectedItem property some where?
List(selectedObjectBorders) {
Text("\($0.color.colorName())")
}
}
}
}
Question was answered but poster removed it for some reason.
answer: this picker init which set the thinkness ivar of EVERY Border object in the collection.
To see the change I should have displayed the result to show thickness.rawvalue to see the change in every Border object
List(selectedObjectBorders) { border in
HStack{
Text("\(border.color.colorName())")
Text("\(border.thickness.rawValue)") //<<- will change when you select an item. All will match.
}
}

How to get a row count in SwiftUI List

I am trying to display the number of rows in a section in its header as shown below as COUNTHERE. The issue I'm running into is that I can't put any code inside the if statement that is not a view so I can't compute anything. Ideas?
struct Day1View: View {
var displayEmployees: [Employee]
var body: some View {
List {
Section(header: Text("Early (\(COUNTHERE)")) {
ForEach(displayEmployees) { employee in
if employee.shift == .early {
switch employee.post {
case .kitchen : Text(employee.name).foregroundColor(.blue)
case .floor : Text(employee.name).foregroundColor(.yellow)
case .upstairs : Text(employee.name).foregroundColor(.red)
case .greeting : Text(employee.name).foregroundColor(.green)
default : Text(employee.name).foregroundColor(.gray)
}
}
}
}
}
Since the section you showed is only for .early shift employees, you can get the count using a filtered version of the original array:
displayEmployees.filter({$0.shift == .early}).count
So your section becomes:
Section(header: Text("Early (\(displayEmployees.filter({$0.shift == .early}).count)")) {
Or, you can add a new computed property for the count:
var displayCount: Int {
return displayEmployees.filter({$0.shift == .early}).count
}
...
Section(header: Text("Early (\(displayCount)")) {

SwiftUI - Change List row background colour programatically

I'm trying to change the background colour of a row in a list based on a value
I have an Int16 value stored in card.owned and I want to change the background if this value is above 0, otherwise use the normal background.
Previously with a table view I could change it with the cellForRowAtIndexPath method, but not sure how to do it with SwiftUI without changing every row
Currently I have
List {
ForEach(cards) { section in
let header: String = nameForSectionHeader(sectionID: section.id)
Section(header: Text(header)) {
ForEach(section) { card in
NavigationLink(destination: CardView(card: card)) {
VStack(alignment: .leading) {
if let name = card.name, let id = card.cardID {
Text("\(id) - \(name)")
}
if let set = card.set, let setName = set.name {
Text("Set: \(setName)")
}
if card.owned > 0 {
Text("Owned: \(card.owned)")
}
}
}
}
}
}
.listRowBackground(lightGreen)
}

SwiftUI - Ternary operator on padding modifier crashes program

I've got a ZStack in SwiftUI filled with some components delivered by a ForEach, as follows:
ForEach(0..<arr.count) { i in
ZStack {
...
}
// I use i later in this code
...
}
The program runs perfectly like this.
But I want to add padding to the ZStack only if i == 0, so I tried adding this modifier to the ZStack: .padding(.top, i == 0 ? 70 : 0)
When I try to build it with this modifier it fails, but doesn't even say "build failed." It takes about 5 minutes attempting to build (when it usually takes 5 seconds) then decides to crash. Can anyone explain why this is happening and how I can get this conditional padding without breaking my program?
Try this:
ForEach(0..<arr.count) { i in
ZStack {
...
}
.padding(.top, getPadding(i))
// I use i later in this code
...
}
func getPadding(_ i: Int) -> CGFloat {
if i == 0 {
return CGFloat(70)
}
return CGFloat(0)
}
func setPadding(_ statement: String) -> CGFloat {
if statement == " Put your statement " {
return CGFloat(your requirement padding)
} else {
return CGFloat("According to your requirement padding")
}

iOS 15 NavigationLink pop automatically if destination is created dynamically

This is a problem on iOS 15 RC only. It works all good on iOS 14.
The problem is if my destination on NavigationLink is created dynamically, it pop automatically if i try push a view via NavigationLink. Here is a bit code snippet
NavigationLink(
destination: (createSettingNavigationLink(name: nameAndImage[0])),
label: {
CellButton(title: nameAndImage[0], image: nameAndImage[1])
}
func createSettingNavigationLink(name: String) -> some View {
if name == "shop.Settings" {
return ShopSettings()
}
if name == "shop.Goods" {
return ShopGoodsManagementPage()
}
if name == "shop.Order" {
return ShopOrderPage()
}
if name == "Customer Service" {
return ServiceListPage(isStore: true)
}
if name == "shop.Performance" {
return PerformanceManagementPage()
}
if name == "shop.Earnings" {
return CommissionSummaryPage()
}
if name == "shop.Increase_sales" {
return BCWebView(urlStr: Constants.increaseSalesGuide)
.navigationBarTitle(Text("Increase Sales Guide"), displayMode: .inline)
.navigationBarHidden(false)
)
}
return EmptyView()
}
)
By the way, the approach mentioned here SwiftUI Unexpectedly NavigationLink pops automatically does not help.
My final solution is to change the above function to struct view. I think it makes sense since the struct view seems to keep states while function is pure stateless.