swiftui - Cómo generar una identificación única en ForEach con [Int]

CorePress2024-01-25  10

Estoy usando ForEach para construir una serie de vistas basadas en una serie de números enteros. Esta matriz de números enteros puede contener valores duplicados. Además, dado que un Int no es identificable, tengo que usar una ruta clave. Sin embargo, cuando uso \.self, obtengo malos resultados (los colores del rectángulo no están configurados correctamente) debido a los valores duplicados.

¿Cuál sería la forma más sencilla de crear identificadores únicos o rutas clave para solucionar este problema?

@ViewBuilder
func stackFor(bar: Bar, scale: CGFloat) -> some View {
    //sample data
    let values = [4,4,5,6]
    var index = 0
    //create stack of view
    //==> since an Int is not identifiable I have to use keypath
    //    however \.self is not unique as we have 2x the value 4 in the values
    //    this leads bad results because there are duplica ids
    ForEach(values, id: \.self) { value in
        Rectangle()
            .fill(colorForStackedBar(index: index))
            .frame(height: heightFor(value: value, scale: scale) )
        Rectangle()
            .fill(Color.clear)
            .frame(height: 1 )
        //the let _ = ... is just a "hack" for being able to update the index in @ViewBuilder
        let _ = index = index + 1
    }
}

func colorForStackedBar(index: Int) -> Color {
    return barColors[safeIndex: index] ?? .red
}

func heightFor(value: Int, scale: CGFloat) -> CGFloat {
    let height = CGFloat(value) * scale
    //at least 1 point so to see __ on the bottom for zero (or missing) entries (as used on other apps)
    return max(1, height)
}


------------------------------------

Encontré una solución envolviendo Int en una estructura única: identificable. Sin embargo, realmente no creo que esta sea la solución más hermosa. Lo más probable es que haya un¿Mejor manera?

struct Unique: Identifiable {
    let value: Int
    let id = UUID()
}

@ViewBuilder
func stackFor(bar: Bar, scale: CGFloat) -> some View {
    //sample data
    let values = [4,4,5,6]
    var index = 0
    //generate a uuid for the whole array of values
    let uniques = values.map({Unique(value: 
import SwiftUI


struct ContentView: View {

    var body: some View {

        stackFor(scale: 1.0)
        
    }
}

func stackFor(scale: CGFloat) -> some View {
    
    let values: [Int] = [4 ,4 ,4 ,4 ,4 ,20, 20, 20, 50, 50, 50]
    
    return VStack(spacing: 0.0) {
        
        ForEach(values, id: \.self) { value in
            
            Rectangle()
                .fill(colorForStackedBar(index: value))
                .frame(height: heightFor(value: value, scale: scale) )
            
            Rectangle()
                .frame(height: 5.0)
            
        }
        
    }
    
    
}
)}) ForEach(uniques) { unique in Rectangle() .fill(colorForStackedBar(index: index)) .frame(height: heightFor(value: unique.value, scale: scale) ) Rectangle() .fill(Color.clear) .frame(height: 1 ) //the let _ = ... is just a "hack" for being able to update the index in @ViewBuilder let _ = index = index + 1 } }

5

¿Podrías mostrar códigos más claros para colorForStackedBar o heightFor o escala y una captura de pantalla del resultado de la aplicación cuál sería el resultado de esta función?

- codificador ios

28/03/2021 a las 9:25

Ambas funciones están fuera de alcance, no son la causa del problema. Simplemente calculan el color y la altura del rectángulo según el índice (es parte de un gráfico de barras apiladas).

- HixField

28 de marzo de 2021 a las 9:27

¡Pero no sé qué estás intentando resolver con esta función que no puedes hacer de forma normal!

- codificador ios

28 de marzo de 2021 a las 9:29

Eche un vistazo a la pregunta original, el problema es que [Int] con duplicados no se puede usar en un ForEach con /.self porque puede contener valores duplicados.

- HixField

28/03/2021 a las 9:30

Pero eso no es un problema, déjame mostrarte un ejemplo

- codificador ios

28 de marzo de 2021 a las 9:41



------------------------------------

¡Aquí la matriz tiene duplicados pero también funciona!

func colorForStackedBar(index: Int) -> Color {
    return Color.red
}


func heightFor(value: Int, scale: CGFloat) -> CGFloat {
    
    return max(1.0, CGFloat(value)*scale)
}
1008611

1

¡Buena idea y consejo!

- HixField

28/03/2021 a las 12:06

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare