Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 988284f78c | |||
| c41c2f0d41 | |||
| 0fcbdfa575 | |||
| db1e789aa5 | |||
| 53adf155b9 | |||
| cfd8d15240 |
Executable
+30
@@ -0,0 +1,30 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file
|
||||
|
||||
## [Filled or not (1.0.4)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.4)
|
||||
|
||||
### New
|
||||
- You can set the filling percent of the last line in multiline elements (thanks @jontelang!)
|
||||
|
||||
### Bug fixes
|
||||
- Solved issue [#14](https://github.com/Juanpe/SkeletonView/issues/14). You could edit text views with skeleton active.
|
||||
|
||||
## [In all directions (1.0.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.3)
|
||||
|
||||
### New
|
||||
- Create ```SkeletonAnimationBuilder```, to facilitate the creation of layer animations.
|
||||
```GradientDirection``` enum.
|
||||
|
||||
## [Retro (1.0.2)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.2)
|
||||
|
||||
### New
|
||||
- Change some private keywords, to be Swift 3 compatible
|
||||
|
||||
## [Early bird bug (1.0.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.2)
|
||||
|
||||
### Bug fixes
|
||||
- It was not removing the skeleton layer
|
||||
|
||||
## [Starter (1.0)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0)
|
||||
|
||||
- First release
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.4</string>
|
||||
<string>1.0.5</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.4</string>
|
||||
<string>1.0.5</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
||||
@@ -13,7 +13,12 @@ let colors = [(UIColor.turquoise,"turquoise"), (UIColor.emerald,"emerald"), (UIC
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var tableview: UITableView!
|
||||
@IBOutlet weak var tableview: UITableView! {
|
||||
didSet {
|
||||
tableview.rowHeight = UITableViewAutomaticDimension
|
||||
tableview.estimatedRowHeight = 120.0
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var avatarImage: UIImageView! {
|
||||
didSet {
|
||||
|
||||
@@ -41,6 +41,7 @@ Enjoy it! 🙂
|
||||
* [Custom animations](#-custom-animations)
|
||||
* [Hierarchy](#-hierarchy)
|
||||
* [Documentation](#-documentation)
|
||||
* [Next steps](#-next-steps)
|
||||
* [Contributed](#-contributed)
|
||||
* [Author](#-author)
|
||||
* [License](#-license)
|
||||
@@ -189,6 +190,9 @@ There is only one method you need to implement to let Skeleton know the cell ide
|
||||
}
|
||||
```
|
||||
|
||||
> **IMPORTANT!**
|
||||
> If you are using resizable cells (`tableView.rowHeight = UITableViewAutomaticDimension` ), it's mandatory define the `estimatedRowHeight`.
|
||||
|
||||
### 📰 Multiline text
|
||||
|
||||
|
||||
@@ -197,7 +201,7 @@ There is only one method you need to implement to let Skeleton know the cell ide
|
||||
When using elements with text, ```SkeletonView``` draws lines to simulate text.
|
||||
Besides, you can decide how many lines you want. If ```numberOfLines``` is set to zero, it will calculate how many lines needed to populate the whole skeleton and it will be drawn. Instead, if you set it to one, two or any number greater than zero, it will only draw this number of lines.
|
||||
|
||||
**NEW** Now, you can set the filling percent of the last line. **Default: 80%**
|
||||
**NEW** Now, you can set the filling percent of the last line. **Default: 70%**
|
||||
|
||||
To modify the percent **using code**, set the property:
|
||||
```swift
|
||||
@@ -303,6 +307,17 @@ Because an image is worth a thousand words:
|
||||
### 📚 Documentation
|
||||
Coming soon...😅
|
||||
|
||||
## 📬 Next steps
|
||||
|
||||
* [x] Set the filling percent of the last line in multiline elements
|
||||
* [x] Add more gradient animations
|
||||
* [x] Supported resizable cells
|
||||
* [ ] CollectionView compatible
|
||||
* [ ] Add recovery state
|
||||
* [ ] Custom collections compatible
|
||||
* [ ] Add animations when it shows/hides the skeletons
|
||||
* [ ] MacOS and WatchOS compatible
|
||||
|
||||
## ❤️ Contributed
|
||||
This is an open source project, so feel free to contribute. How?
|
||||
- Open an [issue](https://github.com/Juanpe/SkeletonView/issues/new).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "SkeletonView"
|
||||
s.version = "1.0.4"
|
||||
s.version = "1.0.5"
|
||||
s.summary = "An elegant way to show users that something is happening and also prepare them to which contents he is waiting"
|
||||
s.description = <<-DESC
|
||||
Today almost all apps have async processes, as API requests, long runing processes, etc. And while the processes are working, usually developers place a loading view to show users that something is going on.
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
F5307E3B1FB123C100EE67C5 /* ContainsMultilineText.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E3A1FB123C100EE67C5 /* ContainsMultilineText.swift */; };
|
||||
F5307E411FB3B84500EE67C5 /* SkeletonView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* SkeletonView.framework */; };
|
||||
F5307E421FB3B84500EE67C5 /* SkeletonView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* SkeletonView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
F54CF5E42024CEB000330B0D /* UIView+CollectionSkeleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54CF5E12024CEAF00330B0D /* UIView+CollectionSkeleton.swift */; };
|
||||
F54CF5E52024CEB000330B0D /* UITableView+CollectionSkeleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54CF5E22024CEAF00330B0D /* UITableView+CollectionSkeleton.swift */; };
|
||||
F54CF5E62024CEB000330B0D /* UICollectionView+CollectionSkeleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54CF5E32024CEB000330B0D /* UICollectionView+CollectionSkeleton.swift */; };
|
||||
F56B94461FAE20AF0095662F /* PrepareForSkeletonProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F56B94451FAE20AF0095662F /* PrepareForSkeletonProtocol.swift */; };
|
||||
F5F622411FAC6E31007C062A /* UIColor+Skeleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F622401FAC6E31007C062A /* UIColor+Skeleton.swift */; };
|
||||
F5F622431FAC81FD007C062A /* CALayer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F622421FAC81FD007C062A /* CALayer+Extensions.swift */; };
|
||||
@@ -70,6 +73,9 @@
|
||||
F5307E361FB1076E00EE67C5 /* SkeletonUITableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonUITableViewDataSource.swift; sourceTree = "<group>"; };
|
||||
F5307E381FB1078E00EE67C5 /* SkeletonUICollectionViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonUICollectionViewDataSource.swift; sourceTree = "<group>"; };
|
||||
F5307E3A1FB123C100EE67C5 /* ContainsMultilineText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainsMultilineText.swift; sourceTree = "<group>"; };
|
||||
F54CF5E12024CEAF00330B0D /* UIView+CollectionSkeleton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+CollectionSkeleton.swift"; sourceTree = "<group>"; };
|
||||
F54CF5E22024CEAF00330B0D /* UITableView+CollectionSkeleton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITableView+CollectionSkeleton.swift"; sourceTree = "<group>"; };
|
||||
F54CF5E32024CEB000330B0D /* UICollectionView+CollectionSkeleton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UICollectionView+CollectionSkeleton.swift"; sourceTree = "<group>"; };
|
||||
F56B94451FAE20AF0095662F /* PrepareForSkeletonProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrepareForSkeletonProtocol.swift; sourceTree = "<group>"; };
|
||||
F5F622401FAC6E31007C062A /* UIColor+Skeleton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Skeleton.swift"; sourceTree = "<group>"; };
|
||||
F5F622421FAC81FD007C062A /* CALayer+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CALayer+Extensions.swift"; sourceTree = "<group>"; };
|
||||
@@ -166,6 +172,9 @@
|
||||
F5F899EA1FAB9DA3002E8FDA /* SkeletonCollectionDataSource.swift */,
|
||||
F5307E381FB1078E00EE67C5 /* SkeletonUICollectionViewDataSource.swift */,
|
||||
F5307E361FB1076E00EE67C5 /* SkeletonUITableViewDataSource.swift */,
|
||||
F54CF5E32024CEB000330B0D /* UICollectionView+CollectionSkeleton.swift */,
|
||||
F54CF5E22024CEAF00330B0D /* UITableView+CollectionSkeleton.swift */,
|
||||
F54CF5E12024CEAF00330B0D /* UIView+CollectionSkeleton.swift */,
|
||||
);
|
||||
path = Collections;
|
||||
sourceTree = "<group>";
|
||||
@@ -337,9 +346,11 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F5F899D01FAA6A4D002E8FDA /* UIView+IBInspectable.swift in Sources */,
|
||||
F54CF5E42024CEB000330B0D /* UIView+CollectionSkeleton.swift in Sources */,
|
||||
F5307E371FB1076E00EE67C5 /* SkeletonUITableViewDataSource.swift in Sources */,
|
||||
8933C7851EB5B820000D00A4 /* SkeletonView.swift in Sources */,
|
||||
F5307E301FB0EC9D00EE67C5 /* SkeletonDefaultConfig.swift in Sources */,
|
||||
F54CF5E52024CEB000330B0D /* UITableView+CollectionSkeleton.swift in Sources */,
|
||||
F5307E321FB0F42F00EE67C5 /* RecursiveProtocol.swift in Sources */,
|
||||
F5F622431FAC81FD007C062A /* CALayer+Extensions.swift in Sources */,
|
||||
F5F899ED1FAB9F04002E8FDA /* CollectionSkeletonProtocol.swift in Sources */,
|
||||
@@ -347,6 +358,7 @@
|
||||
F5F899EB1FAB9DA3002E8FDA /* SkeletonCollectionDataSource.swift in Sources */,
|
||||
F5F622411FAC6E31007C062A /* UIColor+Skeleton.swift in Sources */,
|
||||
F5F899D21FAB9630002E8FDA /* AssociationPolicy.swift in Sources */,
|
||||
F54CF5E62024CEB000330B0D /* UICollectionView+CollectionSkeleton.swift in Sources */,
|
||||
F56B94461FAE20AF0095662F /* PrepareForSkeletonProtocol.swift in Sources */,
|
||||
F5307E391FB1078E00EE67C5 /* SkeletonUICollectionViewDataSource.swift in Sources */,
|
||||
F5307E3B1FB123C100EE67C5 /* ContainsMultilineText.swift in Sources */,
|
||||
|
||||
@@ -8,72 +8,25 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
|
||||
func addDummyDataSourceIfNeeded() {
|
||||
guard let collection = self as? CollectionSkeleton else { return }
|
||||
collection.addDummyDataSource()
|
||||
collection.disableScrolling()
|
||||
}
|
||||
|
||||
func removeDummyDataSourceIfNeeded(reloadAfter reload: Bool = true) {
|
||||
guard let collection = self as? CollectionSkeleton else { return }
|
||||
collection.removeDummyDataSource(reloadAfter: reload)
|
||||
collection.enableScrolling()
|
||||
}
|
||||
enum DataSourceAssociatedKeys {
|
||||
static var dummyDataSource = "dummyDataSource"
|
||||
}
|
||||
|
||||
protocol CollectionSkeleton {
|
||||
var skeletonDataSource: SkeletonCollectionDataSource? { get set }
|
||||
var estimatedNumberOfRows: Int { get }
|
||||
|
||||
func addDummyDataSource()
|
||||
func removeDummyDataSource(reloadAfter: Bool)
|
||||
func disableScrolling()
|
||||
func enableScrolling()
|
||||
}
|
||||
|
||||
private enum AssociatedKeys {
|
||||
static var dummyDataSource = "dummyDataSource"
|
||||
}
|
||||
|
||||
extension CollectionSkeleton where Self: UIScrollView {
|
||||
|
||||
var estimatedNumberOfRows: Int { return 0 }
|
||||
func addDummyDataSource() {}
|
||||
func removeDummyDataSource(reloadAfter: Bool) {}
|
||||
func disableScrolling() { isScrollEnabled = false }
|
||||
func enableScrolling() { isScrollEnabled = true }
|
||||
}
|
||||
|
||||
extension UITableView: CollectionSkeleton {
|
||||
|
||||
var skeletonDataSource: SkeletonCollectionDataSource? {
|
||||
get { return objc_getAssociatedObject(self, &AssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.dummyDataSource, newValue, AssociationPolicy.retain.objc)
|
||||
self.dataSource = newValue
|
||||
}
|
||||
}
|
||||
|
||||
func addDummyDataSource() {
|
||||
guard let originalDataSource = self.dataSource as? SkeletonTableViewDataSource,
|
||||
!(originalDataSource is SkeletonCollectionDataSource)
|
||||
else { return }
|
||||
let dataSource = SkeletonCollectionDataSource(tableViewDataSource: originalDataSource)
|
||||
self.skeletonDataSource = dataSource
|
||||
reloadData()
|
||||
}
|
||||
|
||||
func removeDummyDataSource(reloadAfter: Bool) {
|
||||
guard let dataSource = self.dataSource as? SkeletonCollectionDataSource else { return }
|
||||
self.skeletonDataSource = nil
|
||||
self.dataSource = dataSource.originalTableViewDataSource
|
||||
if reloadAfter { self.reloadData() }
|
||||
}
|
||||
}
|
||||
|
||||
extension UICollectionView: CollectionSkeleton {
|
||||
|
||||
var skeletonDataSource: SkeletonCollectionDataSource? {
|
||||
get { return objc_getAssociatedObject(self, &AssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
|
||||
set { objc_setAssociatedObject(self, &AssociatedKeys.dummyDataSource, newValue, AssociationPolicy.retain.objc) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,13 @@ class SkeletonCollectionDataSource: NSObject {
|
||||
|
||||
weak var originalTableViewDataSource: SkeletonTableViewDataSource?
|
||||
weak var originalCollectionViewDataSource: UICollectionViewDataSource?
|
||||
var rowHeight: CGFloat = 0.0
|
||||
|
||||
convenience init(tableViewDataSource: SkeletonTableViewDataSource? = nil, collectionViewDataSource: UICollectionViewDataSource? = nil) {
|
||||
convenience init(tableViewDataSource: SkeletonTableViewDataSource? = nil, collectionViewDataSource: UICollectionViewDataSource? = nil, rowHeight: CGFloat = 0.0) {
|
||||
self.init()
|
||||
self.originalTableViewDataSource = tableViewDataSource
|
||||
self.originalCollectionViewDataSource = collectionViewDataSource
|
||||
self.rowHeight = rowHeight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +42,7 @@ extension SkeletonCollectionDataSource: UITableViewDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDataSource
|
||||
// MARK: - [WIP] UICollectionViewDataSource
|
||||
extension SkeletonCollectionDataSource: UICollectionViewDataSource {
|
||||
|
||||
func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||
|
||||
@@ -8,4 +8,5 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
// Work in progress
|
||||
protocol SkeletonUICollectionViewDataSource: UICollectionViewDataSource {}
|
||||
|
||||
@@ -17,7 +17,7 @@ public protocol SkeletonTableViewDataSource: UITableViewDataSource {
|
||||
public extension SkeletonTableViewDataSource {
|
||||
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return Int(ceil(skeletonView.frame.height/skeletonView.rowHeight))
|
||||
return skeletonView.estimatedNumberOfRows
|
||||
}
|
||||
|
||||
func numSections(in collectionSkeletonView: UITableView) -> Int { return 1 }
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// UICollectionView+CollectionSkeleton.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Juanpe Catalán on 02/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UICollectionView: CollectionSkeleton {
|
||||
|
||||
var skeletonDataSource: SkeletonCollectionDataSource? {
|
||||
get { return objc_getAssociatedObject(self, &DataSourceAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
|
||||
set { objc_setAssociatedObject(self, &DataSourceAssociatedKeys.dummyDataSource, newValue, AssociationPolicy.retain.objc) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// UITableView+CollectionSkeleton.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Juanpe Catalán on 02/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UITableView: CollectionSkeleton {
|
||||
|
||||
var estimatedNumberOfRows: Int {
|
||||
return Int(ceil(frame.height/rowHeight))
|
||||
}
|
||||
|
||||
var skeletonDataSource: SkeletonCollectionDataSource? {
|
||||
get { return objc_getAssociatedObject(self, &DataSourceAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
|
||||
set {
|
||||
objc_setAssociatedObject(self, &DataSourceAssociatedKeys.dummyDataSource, newValue, AssociationPolicy.retain.objc)
|
||||
self.dataSource = newValue
|
||||
}
|
||||
}
|
||||
|
||||
func addDummyDataSource() {
|
||||
guard let originalDataSource = self.dataSource as? SkeletonTableViewDataSource,
|
||||
!(originalDataSource is SkeletonCollectionDataSource)
|
||||
else { return }
|
||||
let dataSource = SkeletonCollectionDataSource(tableViewDataSource: originalDataSource, rowHeight: calculateRowHeight())
|
||||
self.skeletonDataSource = dataSource
|
||||
reloadData()
|
||||
}
|
||||
|
||||
func removeDummyDataSource(reloadAfter: Bool) {
|
||||
guard let dataSource = self.dataSource as? SkeletonCollectionDataSource else { return }
|
||||
restoreRowHeight()
|
||||
self.skeletonDataSource = nil
|
||||
self.dataSource = dataSource.originalTableViewDataSource
|
||||
if reloadAfter { self.reloadData() }
|
||||
}
|
||||
|
||||
private func restoreRowHeight() {
|
||||
guard let dataSource = self.dataSource as? SkeletonCollectionDataSource else { return }
|
||||
rowHeight = dataSource.rowHeight
|
||||
}
|
||||
|
||||
private func calculateRowHeight() -> CGFloat {
|
||||
guard rowHeight == UITableViewAutomaticDimension else { return rowHeight }
|
||||
rowHeight = estimatedRowHeight
|
||||
return estimatedRowHeight
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// UIView+CollectionSkeleton.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Juanpe Catalán on 02/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
func addDummyDataSourceIfNeeded() {
|
||||
guard let collection = self as? CollectionSkeleton else { return }
|
||||
collection.addDummyDataSource()
|
||||
collection.disableScrolling()
|
||||
}
|
||||
|
||||
func removeDummyDataSourceIfNeeded(reloadAfter reload: Bool = true) {
|
||||
guard let collection = self as? CollectionSkeleton else { return }
|
||||
collection.removeDummyDataSource(reloadAfter: reload)
|
||||
collection.enableScrolling()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user