Home > Software design >  items in ForEach iterating over each other
items in ForEach iterating over each other

Time:03-30

I created ListView which represents HStack with 5 elements:

var body: some View {
    
    GeometryReader { geo in
        HStack(alignment: .center) {
            renderHomeListItem(value: "\(title)", color: .black)
                .frame(width: geo.size.width * 0.3)
                
            renderHomeListItem(value: "\(confirmed)", color: Color(UIColor.systemRed))
                .frame(width: geo.size.width * 0.15)
            
            renderHomeListItem(value: "\(active)", color: Color(UIColor.systemBlue))
                .frame(width: geo.size.width * 0.15)
            
            renderHomeListItem(value: "\(recovered)", color: Color(UIColor.systemGreen))
                .frame(width: geo.size.width * 0.15)
            
            renderHomeListItem(value: "\(deaths)", color: Color(UIColor.systemGray))
                .frame(width: geo.size.width * 0.15)
        }
        .fixedSize()
    }
}

renderHomeListItem is representing one element in HStack:

@ViewBuilder
private func renderHomeListItem(value: String, color: Color) -> some View {
    
    Text(value)
        .padding()
        .commonFont(firstListItem == true ? .bold : .regular, style: .caption2)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .foregroundColor(firstListItem == true ? color : .black)
        .background(colorScheme == .light ? Color(UIColor.systemGray5) : itemDarkModeBackground)
        .cornerRadius(5)
}

And I am calling ListView like this:

@ViewBuilder
private func renderHomeList() -> some View {
    
    LazyVStack {
        HomeListItemView(title: homeViewModel.useCaseSelection == .worldwide ? "State" : "Date", confirmed: "C", active: "A", deaths: "D", recovered: "R")
        
        ForEach(homeViewModel.homeScreenDomainItem.listStats) { value in
            HomeListItemView(title: value.title,
                             confirmed: "\(value.confirmed.formatUsingAbbrevation())",
                             active: "\(value.active.formatUsingAbbrevation())",
                             deaths: "\(value.deaths.formatUsingAbbrevation())",
                             recovered: "\(value.recovered.formatUsingAbbrevation())")
        }
    }
    .padding()
}

Problem is that height of elements in ForEach is iterating over each other so I am getting something like this:

enter image description here

I tried to use padding() everywhere, but it is not answer.

CodePudding user response:

That's because of the GeometryReader.

The simplest solution, if it works in your layout, is to fix the size of the GeometryReader:

var body: some View {
    
    GeometryReader { geo in
        HStack(alignment: .center) {
            // renderHomeListItem x 5
        }
        .fixedSize()
    }

    // This will avoid the overlaps
    .frame(height: someValueHere)
}

Otherwise, if the height cannot be fixed, you need to move the GeometryReader to wrap the whole LazyVStack and then pass geo to HomeListItemView.

Like this (very schematic):

private func renderHomeList() -> some View {

  // Delete the GeometryReader from the HomeListItemView and move it here at the top
  GeometryReader { geo in    
    LazyVStack {

        // Create a new parameter in HomeListItemView to pass the geo variable
        HomeListItemView(geometry: geo, title: homeViewModel.useCaseSelection == .worldwide ? "State" : "Date", confirmed: "C", active: "A", deaths: "D", recovered: "R")
        
        ForEach(homeViewModel.homeScreenDomainItem.listStats) { value in

            // Create a new parameter in HomeListItemView to pass the geo variable
            HomeListItemView(geometry: geo, title: value.title,
                             confirmed: "\(value.confirmed.formatUsingAbbrevation())",
                             active: "\(value.active.formatUsingAbbrevation())",
                             deaths: "\(value.deaths.formatUsingAbbrevation())",
                             recovered: "\(value.recovered.formatUsingAbbrevation())")
        }
    }
    .padding()
  }
}
  • Related