如今,几乎所有应用都包含异步进程,例如 API 请求、长时间运行的过程等。在进程运行期间,通常开发人员会放置一个加载视图来向用户展示正在发生的事情。
SkeletonView
正是为了解决这一需求而设计的,以优雅的方式向用户展示正在进行的事情,同时也让他们准备好等待的内容。
享受它吧!
🌟 特性
- 易于使用
- 所有 UIView 都可以骨架化
- 完全可定制
- 通用(iPhone & iPad)
- 与 Interface Builder 友好
- 简单的 Swift 语法
- 轻量级、易于阅读的代码库
🎬 指南
📲 安装
CocoaPods
使用编辑您的 Podfile
并指定依赖项
pod "SkeletonView"
Carthage
使用编辑您的 Cartfile
并指定依赖项
github "Juanpe/SkeletonView"
使用 Swift 包管理器
一旦你设置了 Swift 包,将 SkeletonView
作为依赖项添加就像将它添加到你的 Package.swift
中的 dependencies
值一样简单。
dependencies: [
.package(url: "https://github.com/Juanpe/SkeletonView.git", from: "1.7.0")
]
🐒 如何使用
使用 SkeletonView
需要 3 个步骤
1. 在适当的位置导入 SkeletonView。
import SkeletonView
2. 现在设置哪些视图将是 skeletonables
。你可以通过以下两种方式实现
使用代码
avatarImageView.isSkeletonable = true
使用 IB/Storyboards
3. 一旦设置了视图,你可以显示 骨架。为此,你有 4 种选择
(1) view.showSkeleton() // Solid
(2) view.showGradientSkeleton() // Gradient
(3) view.showAnimatedSkeleton() // Solid animated
(4) view.showAnimatedGradientSkeleton() // Gradient animated
预览
纯色 | 渐变 | 纯色动画 | 渐变动画 |
![]() |
![]() |
![]() |
![]() |
重要!
SkeletonView
是递归的,所以如果你想在一开始的容器视图中显示骨架,你可以只调用 show 方法。例如,在使用 UIViewControllers 时
额外
骨架视图布局
有时,由于父视图的边界发生变化,骨架布局可能不适合你的布局。例如,旋转设备。
你可以如下重新布局骨架视图
override func viewDidLayoutSubviews() {
view.layoutSkeletonIfNeeded()
}
更新骨架配置
你可以通过以下方法在任何时候更改骨架配置,例如其颜色、动画等:
(1) view.updateSkeleton() // Solid
(2) view.updateGradientSkeleton() // Gradient
(3) view.updateAnimatedSkeleton() // Solid animated
(4) view.updateAnimatedGradientSkeleton() // Gradient animated
🌿 集合
现在,SkeletonView
与 UITableView
和 UICollectionView
兼容。
UITableView
如果您想在UITableView
中显示骨架,需要遵守SkeletonTableViewDataSource
协议。
public protocol SkeletonTableViewDataSource: UITableViewDataSource {
func numSections(in collectionSkeletonView: UITableView) -> Int
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -> ReusableHeaderFooterIdentifier?
func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -> ReusableHeaderFooterIdentifier?
}
如您所见,此协议继承自UITableViewDataSource
,所以您可以替换此协议为骨架协议。
此协议有一个默认实现
func numSections(in collectionSkeletonView: UITableView) -> Int
// Default: 1
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int
// Default:
// It calculates how many cells need to populate whole tableview
func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -> ReusableHeaderFooterIdentifier?
// Default: nil
func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -> ReusableHeaderFooterIdentifier?
// Default: nil
您只需要实现一个方法,让Skeleton知道cell标识符。此方法没有默认实现
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
示例
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier {
return "CellIdentifier"
}
重要!如果使用可调整大小的cell(
tableView.rowHeight = UITableViewAutomaticDimension
),则必须定义estimatedRowHeight
。
👩🏫 如何指定哪些元素是可骨架化的?
以下是 illustration,展示了使用UITableView
时应如何指定哪些元素可骨架化
如您所见,我们必须将tableview、cell和UI元素标记为可骨架化,但我们不需要将contentView
设为可骨架化
UICollectionView
对于UICollectionView
,需要遵守SkeletonCollectionViewDataSource
协议。
public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
func numSections(in collectionSkeletonView: UICollectionView) -> Int
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int
func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier
}
其余过程与UITableView
相同
📰 多行文本
当使用带文本的元素时,SkeletonView
会绘制线条以模拟文本。此外,您可以决定要绘制多少行。如果将numberOfLines
设置为0,则它会计算填充完整骨架所需的行数并进行绘制。相反,如果将其设置为1,2或任何大于0的数字,则只会绘制这个数量的线条。
🎛 自定义
可以为多行元素设置一些属性。
属性 | 值 | 默认 | 预览 |
---|---|---|---|
最后一行填充百分比。 | 0...100 |
70% |
![]() |
线条圆角。(新品) | 0...10 |
0 |
![]() |
要使用代码修改百分比或半径,请设置属性
descriptionTextView.lastLineFillPercent = 50
descriptionTextView.linesCornerRadius = 5
或,如果您更喜欢使用IB/Storyboard
🎨 自定义颜色
您可以决定骨架要使用的颜色。您只需传递您想要的颜色或渐变即可。
使用纯色
view.showSkeleton(usingColor: UIColor.gray) // Solid
// or
view.showSkeleton(usingColor: UIColor(red: 25.0, green: 30.0, blue: 255.0, alpha: 1.0))
使用渐变
let gradient = SkeletonGradient(baseColor: UIColor.midnightBlue)
view.showGradientSkeleton(usingGradient: gradient) // Gradient
此外,SkeletonView
具有20种扁平颜色🤙🏼
UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...
https://flatuicolors.com
Image captured from website🦋 外观
新增 骨干默认具有默认外观。因此,当你没有指定颜色、渐变或多行属性时,SkeletonView
将使用默认值。
默认值
- legiColor:UIColor
- 默认:
.skeletonDefault
(与.clouds
相同,但适用于暗色模式)
- 默认:
- 梯度:
SkeletonGradient
- 默认:
SkeletonGradient(baseColor: .skeletonDefault)
- 默认:
- 多行高度:
CGFloat
- 默认:15
- 多行间距:
CGFloat
- 默认:10
- 多行最后一行填充百分比:Int
- 默认:70
- 多行圆角:Int
- 默认:0
- 骨骼圆角:
CGFloat
(IBInspectable)(使用圆角制作骨骼视图)- 默认:0
要获取这些默认值,您可以使用 SkeletonAppearance.default
。使用此属性,您还可以设置值
SkeletonAppearance.default.multilineHeight = 20
SkeletonAppearance.default.tintColor = .green
您还可以为每个标签指定这些行外观属性
- 最后一行填充百分比:Int
- 线条圆角:Int
- 骨骼行间距:
CGFloat
- 骨骼填充内边距:
UIEdgeInsets
🤓 自定义动画
SkeletonView
有两个内置动画, pulse 用于实心骨骼和 sliding 用于渐变。
除此之外,如果您想自己创建骨骼动画,这真的非常简单。
Skeleton 提供了 showAnimatedSkeleton
函数,其中有一个 SkeletonLayerAnimation
闭包,您可以在其中定义自定义动画。
public typealias SkeletonLayerAnimation = (CALayer) -> CAAnimation
您可以这样调用该函数
view.showAnimatedSkeleton { (layer) -> CAAnimation in
let animation = CAAnimation()
// Customize here your animation
return animation
}
它提供了 SkeletonAnimationBuilder
。它是一个用于创建 SkeletonLayerAnimation
的构建器。
今天,您可以创建 滑动动画 以显示渐变,决定动画的 方向 并设置动画的 持续时间(默认 = 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
是一个枚举,包含以下情况
方向 | 预览 |
---|---|
.leftRight | ![]() |
.rightLeft | ![]() |
.topBottom | ![]() |
.bottomTop | ![]() |
.topLeftBottomRight | ![]() |
.bottomRightTopLeft | ![]() |
😉 吧法! 存在另一种创建滑动动画的方式,只需使用此快捷方式即可
let animation = GradientDirection.leftToRight.slidingAnimation()
🏄 过渡
SkeletonView
内置了用于以更 平滑 方式显示或隐藏骨骼的过渡
要使用过渡,请将过渡时间作为 transition
参数添加到您的 showSkeleton()
或 hideSkeleton()
函数中,如下所示
view.showSkeleton(transition: .crossDissolve(0.25)) //Show skeleton cross dissolve transition with 0.25 seconds fade time
view.hideSkeleton(transition: .crossDissolve(0.25)) //Hide skeleton cross dissolve transition with 0.25 seconds fade time
默认值是 crossDissolve(0.25)
预览
无 | 交叉溶解 |
![]() |
![]() |
👨👧👦 层级
由于 SkeletonView
是递归的,并且我们希望骨骼非常高效,我们希望在可能的情况下尽快停止递归。为此,您必须将容器视图设置为 Skeletonable
,因为一旦视图不再是 Skeletonable
,Skeleton 将停止寻找 skeletonable
子视图,从而中断递归。
因为一张图胜过千言万语
在这个例子中,我们有一个 UIViewController
,它有一个 ContainerView
和一个 UITableView
。当视图就绪时,我们使用此方法显示骨骼
view.showSkeleton()
ìsSkeletonable
=☠️
配置 | 结果 |
---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
🔬 调试
新增 为了便于调试任务,当某些事情工作不正常时。 SkeletonView
有一些新工具。
首先, UIView
可用的新属性包含其骨架信息
var skeletonDescription: String
骨架表示如下所示
除此之外,您还可以激活新的 调试模式。您只需添加环境变量 SKELETON_DEBUG
并激活它。
然后,当骨架出现时,您可以在 Xcode 控制台中看到视图层次结构。
📚 文档
即将推出...
📋 支持的 OS & SDK 版本
- iOS 9.0+
- tvOS 9.0+
- Swift 5
📬 下一步
- 设置多行元素中最后一行的填充百分比
- 增加更多渐变动画
- 支持可调整大小的单元格
- CollectionView 兼容
- tvOS 兼容
- 增加恢复状态
- 自定义默认外观
- 调试模式
- 显示/隐藏骨架时添加动画
- 自定义集合兼容
- MacOS 和 WatchOS 兼容
❤️ 贡献
这是一个开源项目,请随时贡献。如何进行?
查看所有贡献者
SwiftPlate生成的项目
使用📢 提及
- iOS Dev Weekly #327
- Hacking with Swift 文章
- 11月最受欢迎的 Swift 文章 Top 10
- 30个令人惊异的 iOS Swift 库 (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
- 最佳 iOS 文章,新工具及更多
👨💻 作者
👮🏻 许可证
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.