Compare commits

..

24 Commits

Author SHA1 Message Date
Juanpe Catalán 793c79f3e2 Merge branch 'master' of https://github.com/Juanpe/SkeletonView 2018-02-14 20:35:35 +01:00
Juanpe Catalán 20c2fe7e98 fix: Problem when app enter in foreground 2018-02-14 20:35:09 +01:00
Juanpe Catalán b3a6fca8fa Update CHANGELOG.md 2018-02-14 09:41:10 +01:00
Juanpe Catalán 5bcf7f114e feat: Update CHANGELOG file 2018-02-14 09:25:42 +01:00
Juanpe Catalán 145982894a feat: Update example with UITableView with automatic dimension 2018-02-14 09:23:09 +01:00
Juanpe Catalán e89de65a2b fix: Problem setting skeletonIsAnimated property 2018-02-12 19:11:07 +01:00
Juanpe Catalán 34b9122e0a feat: Update CHANGELOG file 2018-02-09 00:56:55 +01:00
Juanpe Catalán 9613f36f19 feat: Bump version 2018-02-09 00:48:32 +01:00
Juanpe Catalán 38b42f8713 fix: Typo in CHANGELOG file 2018-02-09 00:42:30 +01:00
Juanpe Catalán 4c3c996816 feat: Update README file 2018-02-09 00:41:04 +01:00
Juanpe Catalán 3284db700c feat: Update CHANGELOG file 2018-02-09 00:40:26 +01:00
Juanpe Catalán 7958826036 feat: Update CHANGELOG file 2018-02-09 00:38:45 +01:00
Juanpe Catalán fb1a5e3b8e fix: Bug when app become active #39 2018-02-08 22:04:39 +01:00
Juanpe Catalán fcae5ac799 feat: Add UIApplication notifications observers
feat: Create SkeletonFlow
2018-02-08 21:46:24 +01:00
Juanpe Catalán 9063a5bc9f Merge pull request #10 from fanticqq/NsData_wrapping_deleted
feat: Removed wrapping structs to NSValue
2018-02-08 18:18:04 +01:00
Juanpe Catalán 605b1e368f Merge pull request #25 from Renatdz/master
feat: Add support for collection views
2018-02-08 16:45:32 +01:00
Renato Mendes 6e769ed0d4 Resolves the conflict caused by some changes to the CollectionSkeletonProtocol scope, and changes the collectionView feature to the new architecture 2018-02-06 20:22:33 -02:00
Juanpe Catalán e880c00815 feat: Change signature of “makeLayer” method 2018-02-06 10:55:17 +01:00
Juanpe Catalán 75ec8bc1f1 feat: Update CHANGELOG file 2018-02-02 18:13:27 +01:00
Renato Mendes e3e8d5b51a Remove unnecessary prints 2018-01-05 11:30:23 -02:00
Renato Mendes ad511ee64c Add support to the collectionView, the visible cells are zero when we're adding the skeleton, we fix it by replacing the visible cells with subviews. 2017-12-12 14:42:14 -02:00
Renato Mendes 86bb15bc25 Missing file 2017-11-28 16:45:43 -02:00
Renato Mendes c49e4505c8 Adjusts to add CollectionView to SkeletonView 2017-11-28 16:45:11 -02:00
Igor Zarubin 13b041b5f1 Removed wrapping to NSValue of from/to CABasicAnimation parameters because it not necessary in Swift 2017-11-19 00:21:38 +03:00
23 changed files with 282 additions and 68 deletions
+25
View File
@@ -1,6 +1,31 @@
# Change Log
All notable changes to this project will be documented in this file
## [Hotfix (1.1.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.1.1)
### Bug fixes
- Now yes, solved issue [#39](https://github.com/Juanpe/SkeletonView/issues/39)
## [Needed (1.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.1)
### New
- Now ```SkeletonView```supports **UICollectionViews**! 🎉. (thanks @Renatdz)
### Bug fixes
- Solved issue [#39](https://github.com/Juanpe/SkeletonView/issues/39). Gradient animation did not work when app becomes active.
## [Resizable (1.0.5)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.5)
### New
- Now you can use table views with resizable cells.
### Bug fixes
- Solved issues.
[#17](https://github.com/Juanpe/SkeletonView/issues/17),
[#30](https://github.com/Juanpe/SkeletonView/issues/30),
[#34](https://github.com/Juanpe/SkeletonView/issues/34).
## [Filled or not (1.0.4)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.4)
### New
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.5</string>
<string>1.1.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.5</string>
<string>1.1.1</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
+4 -4
View File
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -19,7 +19,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="120" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="UCB-SP-lQk">
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="UCB-SP-lQk">
<rect key="frame" x="0.0" y="263" width="375" height="264"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="separatorColor" red="0.1061807256" green="0.84678786989999999" blue="0.031482450150000001" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
@@ -207,7 +207,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-482" y="-6"/>
<point key="canvasLocation" x="-897" y="-376"/>
</scene>
</scenes>
<resources>
+11
View File
@@ -0,0 +1,11 @@
//
// Constants.swift
// SkeletonView-iOS
//
// Created by Renato Mendes on 28/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
let colors = [(UIColor.turquoise,"turquoise"), (UIColor.emerald,"emerald"), (UIColor.peterRiver,"peterRiver"), (UIColor.amethyst,"amethyst"),(UIColor.wetAsphalt,"wetAsphalt"), (UIColor.nephritis,"nephritis"), (UIColor.belizeHole,"belizeHole"), (UIColor.wisteria,"wisteria"), (UIColor.midnightBlue,"midnightBlue"), (UIColor.sunFlower,"sunFlower"), (UIColor.carrot,"carrot"), (UIColor.alizarin,"alizarin"),(UIColor.clouds,"clouds"), (UIColor.concrete,"concrete"), (UIColor.flatOrange,"flatOrange"), (UIColor.pumpkin,"pumpkin"), (UIColor.pomegranate,"pomegranate"), (UIColor.silver,"silver"), (UIColor.asbestos,"asbestos")]
+5 -2
View File
@@ -9,8 +9,6 @@
import UIKit
import SkeletonView
let colors = [(UIColor.turquoise,"turquoise"), (UIColor.emerald,"emerald"), (UIColor.peterRiver,"peterRiver"), (UIColor.amethyst,"amethyst"),(UIColor.wetAsphalt,"wetAsphalt"), (UIColor.nephritis,"nephritis"), (UIColor.belizeHole,"belizeHole"), (UIColor.wisteria,"wisteria"), (UIColor.midnightBlue,"midnightBlue"), (UIColor.sunFlower,"sunFlower"), (UIColor.carrot,"carrot"), (UIColor.alizarin,"alizarin"),(UIColor.clouds,"clouds"), (UIColor.concrete,"concrete"), (UIColor.flatOrange,"flatOrange"), (UIColor.pumpkin,"pumpkin"), (UIColor.pomegranate,"pomegranate"), (UIColor.silver,"silver"), (UIColor.asbestos,"asbestos")]
class ViewController: UIViewController {
@IBOutlet weak var tableview: UITableView! {
@@ -42,6 +40,11 @@ class ViewController: UIViewController {
return skeletonTypeSelector.selectedSegmentIndex == 0 ? .solid : .gradient
}
override func viewDidLoad() {
super.viewDidLoad()
tableview.isSkeletonable = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
view.showAnimatedSkeleton()
+19 -3
View File
@@ -60,7 +60,7 @@ Enjoy it! 🙂
### 📋 Supported OS & SDK Versions
* iOS 9.0+
* Swift 4 (Swift 3 compatible)
* Swift 4
### 🔮 Example
@@ -152,7 +152,9 @@ avatarImageView.isSkeletonable = true
### 🌿 Collections
Currently, ```SkeletonView``` only is compatible with ```UITableView```. We are working hard to support ```UICollectionView``` too 💪🏼
Now, ```SkeletonView``` is compatible with ```UITableView``` and ```UICollectionView```.
###### UITableView
If you want to show the skeleton in a ```UITableView```, you need to conform to ```SkeletonTableViewDataSource``` protocol.
@@ -193,6 +195,20 @@ 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`.
###### UICollectionView
For ```UICollectionView```, you need to conform to ```SkeletonCollectionViewDataSource``` protocol.
``` swift
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
}
```
The rest of the process is the same as ```UITableView```
### 📰 Multiline text
@@ -312,7 +328,7 @@ Coming soon...😅
* [x] Set the filling percent of the last line in multiline elements
* [x] Add more gradient animations
* [x] Supported resizable cells
* [ ] CollectionView compatible
* [x] CollectionView compatible
* [ ] Add recovery state
* [ ] Custom collections compatible
* [ ] Add animations when it shows/hides the skeletons
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SkeletonView"
s.version = "1.0.5"
s.version = "1.1.1"
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.
+27 -15
View File
@@ -7,14 +7,15 @@
objects = {
/* Begin PBXBuildFile section */
88DEA97F1FCDBD78006C80EF /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DEA97D1FCDBD1F006C80EF /* Constants.swift */; };
8933C7851EB5B820000D00A4 /* SkeletonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7841EB5B820000D00A4 /* SkeletonView.swift */; };
F51DE1091FBF70A70037919A /* SkeletonAnimationBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */; };
F5307E2C1FAF6BC900EE67C5 /* SkeletonGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E2B1FAF6BC900EE67C5 /* SkeletonGradient.swift */; };
F5307E2E1FB0E5E400EE67C5 /* UIView+Frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */; };
F5307E301FB0EC9D00EE67C5 /* SkeletonDefaultConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E2F1FB0EC9D00EE67C5 /* SkeletonDefaultConfig.swift */; };
F5307E321FB0F42F00EE67C5 /* RecursiveProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E311FB0F42F00EE67C5 /* RecursiveProtocol.swift */; };
F5307E371FB1076E00EE67C5 /* SkeletonUITableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E361FB1076E00EE67C5 /* SkeletonUITableViewDataSource.swift */; };
F5307E391FB1078E00EE67C5 /* SkeletonUICollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E381FB1078E00EE67C5 /* SkeletonUICollectionViewDataSource.swift */; };
F5307E371FB1076E00EE67C5 /* SkeletonTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E361FB1076E00EE67C5 /* SkeletonTableViewDataSource.swift */; };
F5307E391FB1078E00EE67C5 /* SkeletonCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E381FB1078E00EE67C5 /* SkeletonCollectionViewDataSource.swift */; };
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, ); }; };
@@ -22,6 +23,8 @@
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 */; };
F587FB84202CBFC8002DB5FE /* SkeletonFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = F587FB83202CBFC8002DB5FE /* SkeletonFlow.swift */; };
F587FB86202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.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 */; };
F5F622451FACA338007C062A /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F622441FACA338007C062A /* Cell.swift */; };
@@ -63,6 +66,7 @@
/* Begin PBXFileReference section */
52D6D97C1BEFF229002C0205 /* SkeletonView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SkeletonView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
88DEA97D1FCDBD1F006C80EF /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
8933C7841EB5B820000D00A4 /* SkeletonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SkeletonView.swift; sourceTree = "<group>"; };
AD2FAA261CD0B6D800659CF4 /* SkeletonView.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SkeletonView.plist; sourceTree = "<group>"; };
F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonAnimationBuilder.swift; sourceTree = "<group>"; };
@@ -70,13 +74,15 @@
F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Frame.swift"; sourceTree = "<group>"; };
F5307E2F1FB0EC9D00EE67C5 /* SkeletonDefaultConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonDefaultConfig.swift; sourceTree = "<group>"; };
F5307E311FB0F42F00EE67C5 /* RecursiveProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecursiveProtocol.swift; sourceTree = "<group>"; };
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>"; };
F5307E361FB1076E00EE67C5 /* SkeletonTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonTableViewDataSource.swift; sourceTree = "<group>"; };
F5307E381FB1078E00EE67C5 /* SkeletonCollectionViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonCollectionViewDataSource.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>"; };
F587FB83202CBFC8002DB5FE /* SkeletonFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonFlow.swift; sourceTree = "<group>"; };
F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+UIApplicationDelegate.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>"; };
F5F622441FACA338007C062A /* Cell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cell.swift; sourceTree = "<group>"; };
@@ -153,6 +159,7 @@
F5307E2B1FAF6BC900EE67C5 /* SkeletonGradient.swift */,
F5F899E81FAB9D2B002E8FDA /* SkeletonLayer.swift */,
8933C7841EB5B820000D00A4 /* SkeletonView.swift */,
F587FB83202CBFC8002DB5FE /* SkeletonFlow.swift */,
);
path = Sources;
sourceTree = "<group>";
@@ -170,8 +177,8 @@
children = (
F5F899EC1FAB9F04002E8FDA /* CollectionSkeletonProtocol.swift */,
F5F899EA1FAB9DA3002E8FDA /* SkeletonCollectionDataSource.swift */,
F5307E381FB1078E00EE67C5 /* SkeletonUICollectionViewDataSource.swift */,
F5307E361FB1076E00EE67C5 /* SkeletonUITableViewDataSource.swift */,
F5307E381FB1078E00EE67C5 /* SkeletonCollectionViewDataSource.swift */,
F5307E361FB1076E00EE67C5 /* SkeletonTableViewDataSource.swift */,
F54CF5E32024CEB000330B0D /* UICollectionView+CollectionSkeleton.swift */,
F54CF5E22024CEAF00330B0D /* UITableView+CollectionSkeleton.swift */,
F54CF5E12024CEAF00330B0D /* UIView+CollectionSkeleton.swift */,
@@ -186,6 +193,7 @@
F5F622401FAC6E31007C062A /* UIColor+Skeleton.swift */,
F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */,
F5F899CF1FAA6A4D002E8FDA /* UIView+IBInspectable.swift */,
F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift */,
);
path = Extensions;
sourceTree = "<group>";
@@ -205,6 +213,7 @@
isa = PBXGroup;
children = (
F5F899F41FABA607002E8FDA /* AppDelegate.swift */,
88DEA97D1FCDBD1F006C80EF /* Constants.swift */,
F5F899F61FABA607002E8FDA /* ViewController.swift */,
F5F622441FACA338007C062A /* Cell.swift */,
F5F899F81FABA607002E8FDA /* Main.storyboard */,
@@ -286,17 +295,17 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0910;
LastUpgradeCheck = 0900;
LastUpgradeCheck = 0920;
ORGANIZATIONNAME = SkeletonView;
TargetAttributes = {
52D6D97B1BEFF229002C0205 = {
CreatedOnToolsVersion = 7.1;
DevelopmentTeam = PTS5FAP7XL;
DevelopmentTeam = KWEMDK92F4;
LastSwiftMigration = 0800;
};
F5F899F11FABA607002E8FDA = {
CreatedOnToolsVersion = 9.1;
DevelopmentTeam = PTS5FAP7XL;
DevelopmentTeam = KWEMDK92F4;
ProvisioningStyle = Automatic;
};
};
@@ -347,7 +356,7 @@
files = (
F5F899D01FAA6A4D002E8FDA /* UIView+IBInspectable.swift in Sources */,
F54CF5E42024CEB000330B0D /* UIView+CollectionSkeleton.swift in Sources */,
F5307E371FB1076E00EE67C5 /* SkeletonUITableViewDataSource.swift in Sources */,
F5307E371FB1076E00EE67C5 /* SkeletonTableViewDataSource.swift in Sources */,
8933C7851EB5B820000D00A4 /* SkeletonView.swift in Sources */,
F5307E301FB0EC9D00EE67C5 /* SkeletonDefaultConfig.swift in Sources */,
F54CF5E52024CEB000330B0D /* UITableView+CollectionSkeleton.swift in Sources */,
@@ -355,12 +364,14 @@
F5F622431FAC81FD007C062A /* CALayer+Extensions.swift in Sources */,
F5F899ED1FAB9F04002E8FDA /* CollectionSkeletonProtocol.swift in Sources */,
F5307E2C1FAF6BC900EE67C5 /* SkeletonGradient.swift in Sources */,
F587FB86202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift in Sources */,
F5F899EB1FAB9DA3002E8FDA /* SkeletonCollectionDataSource.swift in Sources */,
F5F622411FAC6E31007C062A /* UIColor+Skeleton.swift in Sources */,
F587FB84202CBFC8002DB5FE /* SkeletonFlow.swift in Sources */,
F5F899D21FAB9630002E8FDA /* AssociationPolicy.swift in Sources */,
F54CF5E62024CEB000330B0D /* UICollectionView+CollectionSkeleton.swift in Sources */,
F56B94461FAE20AF0095662F /* PrepareForSkeletonProtocol.swift in Sources */,
F5307E391FB1078E00EE67C5 /* SkeletonUICollectionViewDataSource.swift in Sources */,
F5307E391FB1078E00EE67C5 /* SkeletonCollectionViewDataSource.swift in Sources */,
F5307E3B1FB123C100EE67C5 /* ContainsMultilineText.swift in Sources */,
F5F899E91FAB9D2B002E8FDA /* SkeletonLayer.swift in Sources */,
F5307E2E1FB0E5E400EE67C5 /* UIView+Frame.swift in Sources */,
@@ -375,6 +386,7 @@
F5F899F71FABA607002E8FDA /* ViewController.swift in Sources */,
F5F899F51FABA607002E8FDA /* AppDelegate.swift in Sources */,
F5F622451FACA338007C062A /* Cell.swift in Sources */,
88DEA97F1FCDBD78006C80EF /* Constants.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -523,7 +535,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = PTS5FAP7XL;
DEVELOPMENT_TEAM = KWEMDK92F4;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
@@ -548,7 +560,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = PTS5FAP7XL;
DEVELOPMENT_TEAM = KWEMDK92F4;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
@@ -576,7 +588,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = PTS5FAP7XL;
DEVELOPMENT_TEAM = KWEMDK92F4;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(SRCROOT)/Configs/SkeletonViewExampleInfo.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
@@ -601,7 +613,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = PTS5FAP7XL;
DEVELOPMENT_TEAM = KWEMDK92F4;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(SRCROOT)/Configs/SkeletonViewExampleInfo.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
LastUpgradeVersion = "0920"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -28,5 +28,5 @@ extension CollectionSkeleton where Self: UIScrollView {
func removeDummyDataSource(reloadAfter: Bool) {}
func disableScrolling() { isScrollEnabled = false }
func enableScrolling() { isScrollEnabled = true }
}
@@ -13,10 +13,10 @@ public typealias ReusableCellIdentifier = String
class SkeletonCollectionDataSource: NSObject {
weak var originalTableViewDataSource: SkeletonTableViewDataSource?
weak var originalCollectionViewDataSource: UICollectionViewDataSource?
weak var originalCollectionViewDataSource: SkeletonCollectionViewDataSource?
var rowHeight: CGFloat = 0.0
convenience init(tableViewDataSource: SkeletonTableViewDataSource? = nil, collectionViewDataSource: UICollectionViewDataSource? = nil, rowHeight: CGFloat = 0.0) {
convenience init(tableViewDataSource: SkeletonTableViewDataSource? = nil, collectionViewDataSource: SkeletonCollectionViewDataSource? = nil, rowHeight: CGFloat = 0.0) {
self.init()
self.originalTableViewDataSource = tableViewDataSource
self.originalCollectionViewDataSource = collectionViewDataSource
@@ -40,20 +40,24 @@ extension SkeletonCollectionDataSource: UITableViewDataSource {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
return cell
}
}
// MARK: - [WIP] UICollectionViewDataSource
// MARK: - UICollectionViewDataSource
extension SkeletonCollectionDataSource: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
return originalCollectionViewDataSource?.numSections(in: collectionView) ?? 0
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
return originalCollectionViewDataSource?.collectionSkeletonView(collectionView, numberOfItemsInSection: section) ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return UICollectionViewCell()
let cellIdentifier = originalCollectionViewDataSource?.collectionSkeletonView(collectionView, cellIdentifierForItemAt: indexPath) ?? ""
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath)
return cell
}
}
@@ -0,0 +1,26 @@
//
// SkeletonUICollectionViewDataSource.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 06/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
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
}
public extension SkeletonCollectionViewDataSource {
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return skeletonView.estimatedNumberOfRows
}
func numSections(in collectionSkeletonView: UICollectionView) -> Int { return 1 }
}
@@ -1,12 +0,0 @@
//
// SkeletonUICollectionViewDataSource.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 06/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
// Work in progress
protocol SkeletonUICollectionViewDataSource: UICollectionViewDataSource {}
@@ -10,8 +10,34 @@ import UIKit
extension UICollectionView: CollectionSkeleton {
var estimatedNumberOfRows: Int {
guard let flowlayout = collectionViewLayout as? UICollectionViewFlowLayout else { return 0 }
return Int(ceil(frame.height/flowlayout.itemSize.height))
}
var skeletonDataSource: SkeletonCollectionDataSource? {
get { return objc_getAssociatedObject(self, &DataSourceAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
set { objc_setAssociatedObject(self, &DataSourceAssociatedKeys.dummyDataSource, newValue, AssociationPolicy.retain.objc) }
set {
objc_setAssociatedObject(self, &DataSourceAssociatedKeys.dummyDataSource, newValue, AssociationPolicy.retain.objc)
self.dataSource = newValue
}
}
func addDummyDataSource() {
guard let originalDataSource = self.dataSource as? SkeletonCollectionViewDataSource,
!(originalDataSource is SkeletonCollectionDataSource)
else { return }
let dataSource = SkeletonCollectionDataSource(collectionViewDataSource: originalDataSource, rowHeight: 0.0)
self.skeletonDataSource = dataSource
reloadData()
}
func removeDummyDataSource(reloadAfter: Bool) {
guard let dataSource = self.dataSource as? SkeletonCollectionDataSource else { return }
self.skeletonDataSource = nil
self.dataSource = dataSource.originalCollectionViewDataSource
if reloadAfter { self.reloadData() }
}
}
+4 -4
View File
@@ -74,12 +74,12 @@ public extension CALayer {
var sliding: CAAnimation {
let startPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.startPoint))
startPointAnim.fromValue = NSValue(cgPoint:CGPoint(x: -1, y: 0.5))
startPointAnim.toValue = NSValue(cgPoint:CGPoint(x:1, y: 0.5))
startPointAnim.fromValue = CGPoint(x: -1, y: 0.5)
startPointAnim.toValue = CGPoint(x:1, y: 0.5)
let endPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.endPoint))
endPointAnim.fromValue = NSValue(cgPoint:CGPoint(x: 0, y: 0.5))
endPointAnim.toValue = NSValue(cgPoint:CGPoint(x:2, y: 0.5))
endPointAnim.fromValue = CGPoint(x: 0, y: 0.5)
endPointAnim.toValue = CGPoint(x:2, y: 0.5)
let animGroup = CAAnimationGroup()
animGroup.animations = [startPointAnim, endPointAnim]
@@ -12,6 +12,8 @@ private enum AssociatedKeys {
static var skeletonable = "skeletonable"
static var status = "status"
static var skeletonLayer = "layer"
static var flowDelegate = "flowDelegate"
static var isSkeletonAnimated = "isSkeletonAnimated"
}
public extension UIView {
@@ -34,6 +36,11 @@ extension UIView {
case off
}
var flowDelegate: SkeletonFlowDelegate? {
get { return objc_getAssociatedObject(self, &AssociatedKeys.flowDelegate) as? SkeletonFlowDelegate }
set { objc_setAssociatedObject(self, &AssociatedKeys.flowDelegate, newValue, AssociationPolicy.retain.objc) }
}
var skeletonLayer: SkeletonLayer? {
get { return objc_getAssociatedObject(self, &AssociatedKeys.skeletonLayer) as? SkeletonLayer }
set { objc_setAssociatedObject(self, &AssociatedKeys.skeletonLayer, newValue, AssociationPolicy.retain.objc) }
@@ -43,6 +50,11 @@ extension UIView {
get { return objc_getAssociatedObject(self, &AssociatedKeys.status) as? Status ?? .off }
set { objc_setAssociatedObject(self, &AssociatedKeys.status, newValue, AssociationPolicy.retain.objc) }
}
var skeletonIsAnimated: Bool! {
get { return objc_getAssociatedObject(self, &AssociatedKeys.isSkeletonAnimated) as? Bool ?? false }
set { objc_setAssociatedObject(self, &AssociatedKeys.isSkeletonAnimated, newValue, AssociationPolicy.retain.objc) }
}
fileprivate var skeletonable: Bool! {
get { return objc_getAssociatedObject(self, &AssociatedKeys.skeletonable) as? Bool ?? false }
@@ -0,0 +1,38 @@
//
// UIView+UIApplicationDelegate.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 08/02/2018.
// Copyright © 2018 SkeletonView. All rights reserved.
//
import UIKit
extension UIView {
enum Constants {
static let becomeActiveNotification = NSNotification.Name.UIApplicationDidBecomeActive
static let enterForegroundNotification = NSNotification.Name.UIApplicationDidEnterBackground
static let needAnimatedSkeletonKey = "needAnimateSkeleton"
}
func addAppNotificationsObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(appDidBecomeActive), name: Constants.becomeActiveNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterBackground), name: Constants.enterForegroundNotification, object: nil)
}
func removeAppNoticationsObserver() {
NotificationCenter.default.removeObserver(self, name: Constants.becomeActiveNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: Constants.enterForegroundNotification, object: nil)
}
@objc func appDidBecomeActive() {
if UserDefaults.standard.bool(forKey: Constants.needAnimatedSkeletonKey) {
startSkeletonAnimation()
}
}
@objc func appDidEnterBackground() {
UserDefaults.standard.set((isSkeletonActive && skeletonIsAnimated), forKey: Constants.needAnimatedSkeletonKey)
}
}
+4 -4
View File
@@ -66,12 +66,12 @@ public class SkeletonAnimationBuilder {
return { layer in
let startPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.startPoint))
startPointAnim.fromValue = NSValue(cgPoint: direction.startPoint.from)
startPointAnim.toValue = NSValue(cgPoint: direction.startPoint.to)
startPointAnim.fromValue = direction.startPoint.from
startPointAnim.toValue = direction.startPoint.to
let endPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.endPoint))
endPointAnim.fromValue = NSValue(cgPoint: direction.endPoint.from)
endPointAnim.toValue = NSValue(cgPoint: direction.endPoint.to)
endPointAnim.fromValue = direction.endPoint.from
endPointAnim.toValue = direction.endPoint.to
let animGroup = CAAnimationGroup()
animGroup.animations = [startPointAnim, endPointAnim]
+26
View File
@@ -0,0 +1,26 @@
//
// SkeletonFlow.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 08/02/2018.
// Copyright © 2018 SkeletonView. All rights reserved.
//
import UIKit
protocol SkeletonFlowDelegate {
func willBeginShowingSkeletons(withRootView rootView: UIView)
func willBeginHidingSkeletons(withRootView rootView: UIView)
}
class SkeletonFlowHandler: SkeletonFlowDelegate {
func willBeginShowingSkeletons(withRootView rootView: UIView) {
rootView.addAppNotificationsObservers()
}
func willBeginHidingSkeletons(withRootView rootView: UIView) {
rootView.removeAppNoticationsObserver()
rootView.flowDelegate = nil
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ import UIKit
class SkeletonLayerFactory {
func makeLayer(withType type: SkeletonType, usingColors colors: [UIColor], andHolder holder: UIView) -> SkeletonLayer {
func makeSkeletonLayer(withType type: SkeletonType, usingColors colors: [UIColor], andHolder holder: UIView) -> SkeletonLayer {
return SkeletonLayer(withType: type, usingColors: colors, andSkeletonHolder: holder)
}
+38 -11
View File
@@ -27,16 +27,12 @@ public extension UIView {
}
func hideSkeleton(reloadDataAfter reload: Bool = true) {
removeDummyDataSourceIfNeeded(reloadAfter: reload)
isUserInteractionEnabled = true
recursiveSearch(inArray: subviewsSkeletonables,
leafBlock: { removeSkeletonLayer() },
recursiveBlock: {
$0.hideSkeleton(reloadDataAfter: reload)
})
flowDelegate?.willBeginHidingSkeletons(withRootView: self)
recursiveHideSkeleton(reloadDataAfter: reload)
}
func startSkeletonAnimation(_ anim: SkeletonLayerAnimation? = nil) {
skeletonIsAnimated = true
recursiveSearch(inArray: subviewsSkeletonables,
leafBlock: startSkeletonLayerAnimationBlock(anim)) {
$0.startSkeletonAnimation(anim)
@@ -44,6 +40,7 @@ public extension UIView {
}
func stopSkeletonAnimation() {
skeletonIsAnimated = false
recursiveSearch(inArray: subviewsSkeletonables,
leafBlock: stopSkeletonLayerAnimationBlock) {
$0.stopSkeletonAnimation()
@@ -54,6 +51,13 @@ public extension UIView {
extension UIView {
func showSkeleton(withType type: SkeletonType = .solid, usingColors colors: [UIColor], animated: Bool = false, animation: SkeletonLayerAnimation? = nil) {
skeletonIsAnimated = animated
flowDelegate = SkeletonFlowHandler()
flowDelegate?.willBeginShowingSkeletons(withRootView: self)
recursiveShowSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation)
}
fileprivate func recursiveShowSkeleton(withType type: SkeletonType = .solid, usingColors colors: [UIColor], animated: Bool = false, animation: SkeletonLayerAnimation? = nil) {
addDummyDataSourceIfNeeded()
recursiveSearch(inArray: subviewsSkeletonables,
leafBlock: {
@@ -61,9 +65,20 @@ extension UIView {
isUserInteractionEnabled = false
(self as? PrepareForSkeleton)?.prepareViewForSkeleton()
addSkeletonLayer(withType: type, usingColors: colors, animated: animated, animation: animation)
}) {
$0.showSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation)
}
}) {
$0.recursiveShowSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation)
}
}
fileprivate func recursiveHideSkeleton(reloadDataAfter reload: Bool = true) {
removeDummyDataSourceIfNeeded()
isUserInteractionEnabled = true
recursiveSearch(inArray: subviewsSkeletonables,
leafBlock: {
removeSkeletonLayer()
}, recursiveBlock: {
$0.recursiveHideSkeleton(reloadDataAfter: reload)
})
}
fileprivate func startSkeletonLayerAnimationBlock(_ anim: SkeletonLayerAnimation? = nil) -> VoidBlock {
@@ -99,6 +114,18 @@ extension UITableViewCell {
}
}
extension UICollectionView {
override var subviewsSkeletonables: [UIView] {
return subviews.filter { $0.isSkeletonable }
}
}
extension UICollectionViewCell {
override var subviewsSkeletonables: [UIView] {
return contentView.subviews.filter { $0.isSkeletonable }
}
}
extension UIStackView {
override var subviewsSkeletonables: [UIView] {
return arrangedSubviews.filter { $0.isSkeletonable }
@@ -108,7 +135,7 @@ extension UIStackView {
extension UIView {
func addSkeletonLayer(withType type: SkeletonType, usingColors colors: [UIColor], gradientDirection direction: GradientDirection? = nil, animated: Bool, animation: SkeletonLayerAnimation? = nil) {
self.skeletonLayer = SkeletonLayerFactory().makeLayer(withType: type, usingColors: colors, andHolder: self)
self.skeletonLayer = SkeletonLayerFactory().makeSkeletonLayer(withType: type, usingColors: colors, andHolder: self)
layer.insertSublayer(skeletonLayer!.contentLayer, at: UInt32.max)
if animated { skeletonLayer!.start(animation) }
status = .on