Destacado • Instalación • ¿Cómo funciona? • Miscelánea • Contribuir
🌎 README está disponible en estos idiomas: 🇬🇧 . 🇨🇳 . 🇧🇷 . 🇰🇷 . 🇫🇷 . 🇩🇪
Hoy en día, La mayoría de las apps tiene procesos asíncronos, como peticiones a una API, procesos que tardan mucho tiempo, etc. Mientras estos procesos se están ejecutando, se suele mostrar un aburrido spinner indicando que algo está pasando.
SkeletonView ha sido desarrollada para cubrir esta necesidad, un elegante manera de decirle a los usarios que algo se está procesando y además prepararlos, visualmente, para el contenido que están esperando.
Enjoy it! 🙂
- 🌟 Destacado
- 🎬 Videotutoriales
- 📲 Instalación
- 🐒 ¿Cómo funciona?
- ✨ Miscelánea
- ❤️ Contributing
- 📢 Menciones
- 👨🏻💻 Autor
- 👮🏻 Licencia
- Fácil de usar
- Todas las UIViews son skeletonables
- Personalizable
- Universal (iPhone & iPad)
- Interface Builder friendly
SkeletonView Guides - Getting started | How to Create Loading View with Skeleton View in Swift 5.2 by iKh4ever Studio | Create Skeleton Loading View in App (Swift 5) - Xcode 11, 2020 by iOS Academy | Add An Elegant Loading Animation in Swift* by Gary Tokman |
pod 'SkeletonView'
github "Juanpe/SkeletonView"
dependencies: [
.package(url: "https://github.com/Juanpe/SkeletonView.git", from: "1.7.0")
]
Solo necesitas 3 pasos para usar SkeletonView
:
1️⃣ Importa SkeletonView en el archivo donde vayas a utilizarlo.
import SkeletonView
2️⃣ Ahora, debes indicar qué elementos de tu vista son skeletonables
Con código:
avatarImageView.isSkeletonable = true
Con IB/Storyboards:
3️⃣ Una vez indicado, solo tienes que mostrar el skeleton. Tienes 4 opciones:
(1) view.showSkeleton() // Sólido
(2) view.showGradientSkeleton() // Degradado
(3) view.showAnimatedSkeleton() // Sólido animado
(4) view.showAnimatedGradientSkeleton() // Degradado animado
Vista previa
Sólido | Degradado | Sólido Animado | Degradado Animado |
📣 ¡IMPORTANTE!
SkeletonView
es recursivo. Por lo que si tienes una vsita que contiene varios elementos skeletonables, solo tienes queenecu For example, withUIViewControllers
.
SkeletonView
es compatible con UITableView
and UICollectionView
.
UITableView
Si quieres mostrar el skeleton en un UITableView
, necesitas conformar el protocolo SkeletonTableViewDataSource
.
public protocol SkeletonTableViewDataSource: UITableViewDataSource {
// Por defecto: 1
func numSections(in collectionSkeletonView: UITableView) -> Int
// Por defecto:
// Calcula cuantas celdas necesita para rellenar todo el frame.
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
}
Este protocolo hereda de UITableViewDataSource
, por lo que puedes reemplazar este protocolo por el protocolo de skeleton sin perder ninguna funcionalidad. El único método que es obligatorio implementar es cellIdentifierForRowAt
, donde tienes que indicar el identificador de la celda.
Ejemplo
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier {
return "CellIdentifier"
}
Además, tu puedes mostrar el skeleton en las headers y en los footers, conformando el protocolo SkeletonTableViewDelegate
.
public protocol SkeletonTableViewDelegate: UITableViewDelegate {
func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -> ReusableHeaderFooterIdentifier? // default: nil
func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -> ReusableHeaderFooterIdentifier? // default: nil
}
📣 ¡IMPORTANTE!
1️⃣ Si estás usando celdas con altura dinámica (
tableView.rowHeight = UITableViewAutomaticDimension
), es obligatorio definir elestimatedRowHeight
.2️⃣ Cuando añades elemetos a una
UITableViewCell
, debes añadirlo alcontentView
y no a la celda directamente.cell.contentView.addSubview(titleLabel) ✅ cell.addSubview(titleLabel) ❌
UICollectionView
Para los UICollectionView
, debes conformar el protocolo SkeletonCollectionViewDataSource
.
public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
func numSections(in collectionSkeletonView: UICollectionView) -> Int // Por defecto: 1
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int
func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier
func collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -> ReusableCellIdentifier? // Por defecto: nil
}
El resto del proceso es exactamente igual que con las UITableView
.
Cuando usas elementos que contienen texto,SkeletonView
dibujo líneas para simular el texto.
Además, puedes decidir el número de líneas. Si numberOfLines
es igual a 0, se calculará automáticamente el número de líneas necesarias para ocupar todo el frame. Sin embargo, si es un número mayor que cero, solo se dibujarán esas líneas.
Puedes especificar algunos atributos para estos elementos:
Atributo | Valores | Por defecto | Vista previa |
---|---|---|---|
Porcentaje de relleno de la última línea. | 0...100 |
70% |
|
Radio de las esquinas de las líneas. | 0...10 |
0 |
Para modificar alguno de los valores lo puedes hacer con código::
descriptionTextView.lastLineFillPercent = 50
descriptionTextView.linesCornerRadius = 5
O usando IB/Storyboards:
Los skeletons tiene una apariencia por defecto. Así, cuando no especificas el color, el degradado o las propiedades para las multiíneas, SkeletonView
usa estos valores.
Valores por defecto:
- tintColor:
UIColor
- default:
.skeletonDefault
(igual que.clouds
pero se adapta al dark mode)
- default:
- gradient:
SkeletonGradient
- default:
SkeletonGradient(baseColor: .skeletonDefault)
- default:
- multilineHeight:
CGFloat
- default: 15
- multilineSpacing:
CGFloat
- default: 10
- multilineLastLineFillPercent:
Int
- default: 70
- multilineCornerRadius:
Int
- default: 0
- skeletonCornerRadius:
CGFloat
(IBInspectable)- default: 0
Para obtener o modificar estos valores tu puedes usar SkeletonAppearance.default
:
SkeletonAppearance.default.multilineHeight = 20
SkeletonAppearance.default.tintColor = .green
Puedes decidir de qué color se tinta tu skeleton. Solo tienes que indicarlo pasándolo como parámetro:
Usando colores sólidos
view.showSkeleton(usingColor: UIColor.gray)
// o
view.showSkeleton(usingColor: UIColor(red: 25.0, green: 30.0, blue: 255.0, alpha: 1.0))
Usando degradados
let gradient = SkeletonGradient(baseColor: UIColor.midnightBlue)
view.showGradientSkeleton(usingGradient: gradient)
Además, SkeletonView añade 20 colores flat 🤙🏼
UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...
Imagen extraída de la web https://flatuicolors.com
SkeletonView tiene pre-definidas dos animaciones, pulse para skeleton sólidos y sliding para degradados.
Además, usando el método showAnimatedSkeleton
, podemos incluir la animation
que es de tipo SkeletonLayerAnimation
, un bloque donde tu puedes crear tus propias animaciones:
public typealias SkeletonLayerAnimation = (CALayer) -> CAAnimation
Tu código quedaría así:
view.showAnimatedSkeleton { (layer) -> CAAnimation in
let animation = CAAnimation()
// Personaliza la animación aquí
return animation
}
SkeletonAnimationBuilder
es un builder que permite crear SkeletonLayerAnimation
.
Por ejemplo, tu puedes crear sliding animations para los degradados, decidiendo la direction y indicando la duration de la animación (default = 1.5s).
// func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation
let animation = SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: .leftToRight)
view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
GradientDirection
es un enumerado con estos cases
:
Dirección | Vista previa |
---|---|
.leftRight | |
.rightLeft | |
.topBottom | |
.bottomTop | |
.topLeftBottomRight | |
.bottomRightTopLeft |
😉 ¡Truco!
Puedes crear una animación sliding, con este shortcut:
let animation = GradientDirection.leftToRight.slidingAnimation()
SkeletonView tiene algunas transiciones listas para usarse cuando aparece o se oculta. Puedes especificarla así:
view.showSkeleton(transition: .crossDissolve(0.25))
view.hideSkeleton(transition: .crossDissolve(0.25))
La transición por defecto es crossDissolve(0.25)
Vista previa
Sin transición | Cross dissolve |
Jerarquía
SkeletonView
es recursivo, pero para que sea eficiente, tenemos que pararar la recursión tan pronto como sea posible. Por este motivo, el contenedor de las vistas debe ser skeletonable
, porque SkeletonView
parará de buscar vistas skeletonables cuando encuentre una que no lo sea, dentro de la jerarquía.
Como una imagen vale más que mil palabras:
En este ejemplo, tenemos un UIViewController
con un containerView
y una UITableView
. Cuando la vista está lista, para mostrar el skeleton ejecutamos el método:
view.showSkeleton()
isSkeletonable
= ☠️
Configuración | Resultado |
---|---|
Jerarquía en las colecciones
Esta ilustración muestra como deberías específicar qué elementos son skeletonables cuando estás usando una UITableView
:
Actualiza el skeleton
Puedes cambiar la configuración del skeleton, como el color, la animación, etc, con los siguientes métodos:
(1) view.updateSkeleton() // Sólido
(2) view.updateGradientSkeleton() // Degradado
(3) view.updateAnimatedSkeleton() // Sólido animado
(4) view.updateAnimatedGradientSkeleton() // Degradado animado
Debug
Para facilitar las tareas de debug cuando algo no está funcionando bien, SkeletonView
tiene una nueva herramienta.
Primero, UIView
tiene una nueva propiedad que contiene toda la info del skeleton:
var skeletonDescription: String
Y es representada de la siguiente manera:
Para activar el modo debug. Solo tienes que añadir una variable de entorno con esta clave SKELETON_DEBUG
y activarla.
Entonces, cuando el skeleton aparece, tu podrás ver la jerarquía de vistas en la consola de Xcode.
OS Soportado & Versiones SDK
- iOS 9.0+
- tvOS 9.0+
- Swift 5
Esto es un proyecto open source, siéntete libre de contribuir. ¿Cómo?
- Abre un issue.
- Envía feedback a través del email.
- Propone tus propies fixes, sugerencias y abre una Pull Request con los cambios.
Échale un vistazo a los que ya han contribuído
Para más información, por favor, lee la guía de contribución.
- iOS Dev Weekly #327
- Hacking with Swift Articles
- Top 10 Swift Articles November
- 30 Amazing iOS Swift Libraries (v2018)
- AppCoda Weekly #44
- iOS Cookies Newsletter #103
- Swift Developments Newsletter #113
- iOS Goodies #204
- Swift Weekly #96
- CocoaControls
- Awesome iOS Newsletter #74
- Swift News #36
- Best iOS articles, new tools & more
MIT License
Copyright (c) 2017 Juanpe Catalán
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.