Crear Vista Para Mostrar Porcentaje De Calificaciones Y Reseñas con switUI
¿Para que necesito un ratingView?
En mi caso le llamare RatingView, esto hace referencia a un listado de estrellas en dirección horizontal(que también puede ser cualquier figura) que muestra el porcentaje de calificación respecto al total de reseñas que tienen nuestras publicaciones(un producto, una foto, etc). Esto normal mente se añaden en las CardView(vista previa con algo de información de alguna publicación) , También necesitaremos esta vista para poder dar la opción al usuario de valorar publicaciones, pero en este caso esta vista tendría que ser interactiva y para añadirla a una CardView solo la utilizaremos para mostrar la antes mencionada información .
Crear RatingView
Existen muchas maneras de llevar acabo este tipo de vista incluso el nombre será distinto yo en mis programas le llamo así, también puede ser que otros desarrolladores lo hagan de distinta manera, pero se trata de ser creativo, de la manera en la que nosotros lo haremos será utilizando SwiftUI lo haremos de una manera muy sencilla y con pocas lineas de código y una vez que lo hagamos podremos reutilizarla en cualquier proyecto.
A continuación abrimos Xcode y creamos un nuevo proyecto y ponemos el nombre que queramos, luego de esto crearemos un nuevo fichero llamado RatingView.
Variables para Recibir los Parámetros de Nuestra vista
Necesitaremos recibir unos valores para que nuestras vista se puede personalizar al reutilizarla en cualquier proyecto, la constante “percentage” representa el valor que se mostrará de manera gráfica, mainColor es para darle el color principal y secundaryColor para dar el valor del color secundario, la ultima variable de tipo Bool es para asignar un borde a cada estrella, esto nos quedara mas claro al finalizar.
let percentage: Double
var mainColor: Color = .yellow
var secundaryColor: Color = .gray.opacity(0.5)
var addBorders: Bool = false
Implementar código para dar forma a la vista deceada
Luego dentro de las llaves de la variable body crearemos un GeometryReader y dentro del GeometryReader declararemos dos constantes con los valores que retorna la el ancho y el alto global del mismo.
GeometryReader { proxy in
let width = proxy.frame(in: .global).width
let height = proxy.frame(in: .global).height
}
El contenido del GeometryReader sera una pila de vista hacia el eje z ósea un ZStack. Le asignamos el color secundario que equivale al antes declarado, el color secundario es el que remarca todo el fondo que posteriormente al agregar el color primario dará el efecto de llenar la barra de estrellas según el porcentaje que le pasemos a nuestra constante “percentage”, que se vea que aparentemente la barra de estrellas se rellena del color principal, a mainColor le diremos que su ancho sera el ancho de su ámbito(GeometryReader) por el porcentaje recibido y este resultado lo dividimos entre 100, también tenemos que asignar un alto que será también el de su ámbito.
GeometryReader { proxy in
let width = proxy.frame(in: .global).width
let height = proxy.frame(in: .global).height
ZStack(alignment: .leading) {
secundaryColor
mainColor
.frame(width: (width)*percentage/100, height: height)
if addBorders {
HStack(spacing: 1) {
ForEach(0..<5) { _ in
Image(systemName: «star»)
.resizable()
.scaledToFit()
}
}
}
}
}
Hasta el momento tendríamos solo dos rectángulos superpuestos uno de color gris y otro de color amarillo(Puede ser cualquier color), Para poder verlo vamos agregar nuestra vista RatingView a ContentView, cuando lo agreguemos nos pedirá que le pacemos un valor a “percentage” el valor puede ser cualquier menos de 100, también le daremos un alto de 40 para que ho se redimensione al alto de toda la pantalla.
struct ContentView: View {
var body: some View {
RatingView(percentage: 30)
.frame(height:40)
}
}
Darle forma al Rectángulo
Antes de darle forma quitaremos el alto que le dimos en ContentView y le daremos un ancho o simplemente quitamos el mitificado .frame.
struct ContentView: View {
var body: some View {
RatingView(percentage: 30)
}
}
Para darle forma de cinco estrellas continuas en dirección horizontal, simplemente tendremos agregar una mascara a nuestro ZStack. Definiremos nuestra mascara con un HStack, dentro del HStack implementaremos un ForEach para que regenere 5 imágenes de estrella. En este caso utilizaremos una imagen del sistema.
GeometryReader { proxy in
let width = proxy.frame(in: .global).width
let height = proxy.frame(in: .global).height
ZStack(alignment: .leading) {
secundaryColor
mainColor
.frame(width: (width)*percentage/100, height: height)
}
.mask {
HStack(spacing: 1) {
ForEach(0..<5) { _ in
Image(systemName: «star.fill»)
.resizable()
.scaledToFit()
}
}
}
Listo ya tenemos nuestro RatingView. Una cosas de las que tenemos que tener en cuenta es que el porcentaje que le demos siempre tendrá que ser lógica mente menos de 100, este porcentaje lo calcularemos de la siguiente manera: (total de calificaciones * (total de reseñas * 5) ) / 100, En otro tutorial aprenderemos a crear una CardView utilízanos esta vista de calificaciones también incluiremos una estructura de datos para hacerlo mas parecido a un caso real, con distintas reseñas.
Agregar Opción de Personalización
Vamos agregar la opción de darle bordes a cada una de las cinco estrellas, lo haremos declarando una sentencia “if” utilizando la variable de tipo Bool que declaramos al principio var addBorders: Bool = false , luego copiaremos el HStack con todo lo que contiene dentro de sus llaves y lo pegaremos dentro de la sentencia “if” lo único que cambiaremos sera el nombre de la imagen del sistema «star.fill» por «star». Luego vamos al ContentView y añadimos el parámetro “addBorders” de nuestro RatingView y le damos el valor true desde allí también podemos cambiar los colores el principal y el secundario. Esto se vera de la siguiente manera:
GeometryReader { proxy in
let width = proxy.frame(in: .global).width
let height = proxy.frame(in: .global).height
ZStack(alignment: .leading) {
secundaryColor
mainColor
.frame(width: (width)*percentage/100, height: height)
if addBorders {
HStack(spacing: 1) {
ForEach(0..<5) { _ in
Image(systemName: «star»)
.resizable()
.scaledToFit()
}
}
}
}
.mask {
HStack(spacing: 1) {
ForEach(0..<5) { _ in
Image(systemName: «star.fill»)
.resizable()
.scaledToFit()
}
}
}
}
Listo ya tendríamos nuestra vista terminada solo una cosa mas, lo ideal y lo lógico seria que el borde tuviera el color principal para esto tendremos que escribir una ultima linea de código que seria la siguiente: .foregroundColor(mainColor), este modificador lo vamos a colocar en el ZStack antes del modificador .mask, nuestro código y nuestra vista acabada por completo se verían así.
struct RatingView: View {
let percentage: Double
var mainColor: Color = .yellow
var secundaryColor: Color = .gray.opacity(0.5)
var addBorders: Bool = false
var body: some View {
GeometryReader { proxy in
let width = proxy.frame(in: .global).width
let height = proxy.frame(in: .global).height
ZStack(alignment: .leading) {
secundaryColor
mainColor
.frame(width: (width)*percentage/100, height: height)
if addBorders {
HStack(spacing: 1) {
ForEach(0..<5) { _ in
Image(systemName: «star»)
.resizable()
.scaledToFit()
}
}
}
}
.foregroundColor(mainColor)
.mask {
HStack(spacing: 1) {
ForEach(0..<5) { _ in
Image(systemName: «star.fill»)
.resizable()
.scaledToFit()
}
}
}
}
}
}
Bien hemos terminado de crear una vista muy sencilla pero muy util, este código lo encontraras en mi perfil de GitHub, abajo te dejo el link. si te gusto el tutorial deja un comentario que para mi es de mucho valor cualquier critica me servirá a mejorar, si crees que al tutorial le falto algo házmelo saber que estaré muy agradecido nos vemos en otro tutorial.
¡Hasta luego!