Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f5d409304 | |||
| bc3258b8a2 | |||
| fd4683f555 | |||
| 97ebbcc917 | |||
| a02922dba6 | |||
| 4ac1abe50e | |||
| 25e313850e | |||
| 88914f7816 | |||
| 14ab00d13a | |||
| 90b993a16b | |||
| 413867718e | |||
| e43b3f3750 | |||
| b9b368b7e8 | |||
| fc22d58f89 | |||
| 8988b22784 | |||
| 3cb1602e11 | |||
| 649672182e | |||
| 3c16416dbb | |||
| 0eff052314 |
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 222 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 388 KiB |
@@ -1,6 +1,20 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file
|
||||
|
||||
## [Debug (1.4)](https://github.com/Juanpe/SkeletonView/releases/tag/1.4)
|
||||
|
||||
### New
|
||||
|
||||
- Create `skeletonDescription` print a skeleton representation of the view.
|
||||
- Create `SKELETON_DEBUG` environment variable, in order to print the view hierarchy when the skeleton appears.
|
||||
|
||||
### Improvements
|
||||
- Add two new methods to `SkeletonFlowDelegate` protocol. Now you can know when the skeleton did show and when it did hide.
|
||||
- `Recursive` protocol
|
||||
|
||||
### Bug fixes
|
||||
- Solved issue [#86](https://github.com/Juanpe/SkeletonView/issues/86) (thanks @reececomo)
|
||||
|
||||
## [Custom defaults (1.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.3)
|
||||
|
||||
### New
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// SkeletonViewExampleUICollectionView
|
||||
//
|
||||
// Created by Andrei Hogea on 14/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
//
|
||||
// CollectionViewCell.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Andrei Hogea on 14/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SkeletonView
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
//
|
||||
// Constants.swift
|
||||
// SkeletonViewExampleUICollectionView
|
||||
//
|
||||
// Created by Andrei Hogea on 15/02/2018.
|
||||
// Copyright © 2018 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")]
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// SkeletonViewExampleUICollectionView
|
||||
//
|
||||
// Created by Andrei Hogea on 14/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SkeletonView
|
||||
|
||||
@@ -201,6 +201,9 @@
|
||||
<constraint firstItem="XgY-1a-UGc" firstAttribute="bottom" secondItem="6Tk-OE-BBY" secondAttribute="bottom" id="vnZ-9k-MfI"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="NO"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="BEI-dU-kr2"/>
|
||||
<connections>
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
//
|
||||
// Constants.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Renato Mendes on 28/11/2017.
|
||||
// Copyright © 2017 SkeletonView. All rights reserved.
|
||||
//
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ Enjoy it! 🙂
|
||||
* [Appearance](#-appearance)
|
||||
* [Custom animations](#-custom-animations)
|
||||
* [Hierarchy](#-hierarchy)
|
||||
* [Debug](#-debug)
|
||||
* [Documentation](#-documentation)
|
||||
* [Next steps](#-next-steps)
|
||||
* [Contributing](#-contributing)
|
||||
@@ -280,11 +281,23 @@ Besides, ```SkeletonView``` features 20 flat colors 🤙🏼
|
||||
|
||||
Default values:
|
||||
- **tintColor**: UIColor
|
||||
- *default: .clouds*
|
||||
- **gradient**: SkeletonGradient
|
||||
- *default: SkeletonGradient(baseColor: .clouds)*
|
||||
- **multilineHeight**: CGFloat
|
||||
- *default: 15*
|
||||
- **multilineSpacing**: CGFloat
|
||||
- *default: 10*
|
||||
- **multilineLastLineFillPercent**: Int
|
||||
- **multilineCornerRadius**: Int _0_
|
||||
- *default: 70*
|
||||
- **multilineCornerRadius**: Int
|
||||
- *default: 0*
|
||||
|
||||
To get these default values you can use `SkeletonAppearance.default`. Using this property you can set the values as well:
|
||||
```Swift
|
||||
SkeletonAppearance.default.multilineHeight = 20
|
||||
SkeletonAppearance.default.tintColor = .green
|
||||
```
|
||||
|
||||
|
||||
### 🤓 Custom animations
|
||||
@@ -354,6 +367,31 @@ Because an image is worth a thousand words:
|
||||
| | 
|
||||
|
||||
|
||||
### 🔬 Debug
|
||||
|
||||
**NEW** In order to facilitate the debug tasks when something is not working fine. `SkeletonView` has some new tools.
|
||||
|
||||
First, `UIView` has available a new property with his skeleton info:
|
||||
```swift
|
||||
var skeletonDescription: String
|
||||
|
||||
```
|
||||
The skeleton representation looks like this:
|
||||
|
||||

|
||||
|
||||
Besides, you can activate the new **debug mode**. You just add the environment variable `SKELETON_DEBUG` and activate it.
|
||||
|
||||

|
||||
|
||||
Then, when the skeleton appears, you can see the view hierarchy in the Xcode console.
|
||||
|
||||
<details>
|
||||
<summary>Open to see an output example </summary>
|
||||
<img src="Assets/hierarchy_output.png" />
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
### 📚 Documentation
|
||||
Coming soon...😅
|
||||
@@ -367,6 +405,7 @@ Coming soon...😅
|
||||
* [x] tvOS compatible
|
||||
* [x] Add recovery state
|
||||
* [x] Custom default appearance
|
||||
* [x] Debug mode
|
||||
* [ ] Custom collections compatible
|
||||
* [ ] Add animations when it shows/hides the skeletons
|
||||
* [ ] MacOS and WatchOS compatible
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "SkeletonView"
|
||||
s.version = "1.3"
|
||||
s.version = "1.4"
|
||||
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.
|
||||
|
||||
@@ -38,11 +38,13 @@
|
||||
42ABD07A210B54E200BEEFF4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 42ABD072210B54E100BEEFF4 /* Assets.xcassets */; };
|
||||
42ABD07B210B54E200BEEFF4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42ABD073210B54E100BEEFF4 /* ViewController.swift */; };
|
||||
42ABD07C210B54E200BEEFF4 /* Base.lproj in Resources */ = {isa = PBXBuildFile; fileRef = 42ABD074210B54E100BEEFF4 /* Base.lproj */; };
|
||||
42ABD07D210B54E200BEEFF4 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42ABD075210B54E100BEEFF4 /* Constants.swift */; };
|
||||
42ABD07E210B54E200BEEFF4 /* SkeletonViewExampleCollectionview-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 42ABD076210B54E200BEEFF4 /* SkeletonViewExampleCollectionview-Info.plist */; };
|
||||
42ABD07F210B54E200BEEFF4 /* CollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42ABD077210B54E200BEEFF4 /* CollectionViewCell.swift */; };
|
||||
8748240D20C6A88A00E92179 /* UIView+IBInspectable.swift in Headers */ = {isa = PBXBuildFile; fileRef = F5F899CF1FAA6A4D002E8FDA /* UIView+IBInspectable.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8748240E20C6A88E00E92179 /* ContainsMultilineText.swift in Headers */ = {isa = PBXBuildFile; fileRef = F5307E3A1FB123C100EE67C5 /* ContainsMultilineText.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8785E3A1211C9C9800CC9DFD /* SkeletonDebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8785E3A0211C9C9800CC9DFD /* SkeletonDebug.swift */; };
|
||||
8785E3A2211C9CA500CC9DFD /* SkeletonDebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8785E3A0211C9C9800CC9DFD /* SkeletonDebug.swift */; };
|
||||
8785E3A3211C9CE800CC9DFD /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DEA97D1FCDBD1F006C80EF /* Constants.swift */; };
|
||||
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 */; };
|
||||
@@ -71,6 +73,8 @@
|
||||
F58A6E6C20A8C54100612494 /* RecoverableViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F58A6E6A20A8C54100612494 /* RecoverableViewState.swift */; };
|
||||
F58A6E6E20A8C66300612494 /* Recoverable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F58A6E6D20A8C66300612494 /* Recoverable.swift */; };
|
||||
F58A6E6F20A8C66300612494 /* Recoverable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F58A6E6D20A8C66300612494 /* Recoverable.swift */; };
|
||||
F5A5E8B4211DCE7000FD20D0 /* Int+Whitespaces.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A5E8B3211DCE7000FD20D0 /* Int+Whitespaces.swift */; };
|
||||
F5A5E8B5211DCE7000FD20D0 /* Int+Whitespaces.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A5E8B3211DCE7000FD20D0 /* Int+Whitespaces.swift */; };
|
||||
F5D3FB0B209DCAA300003FCF /* SubviewsSkeletonables.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D3FB0A209DCAA300003FCF /* SubviewsSkeletonables.swift */; };
|
||||
F5D3FB0C209DCAA300003FCF /* SubviewsSkeletonables.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D3FB0A209DCAA300003FCF /* SubviewsSkeletonables.swift */; };
|
||||
F5F622411FAC6E31007C062A /* UIColor+Skeleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F622401FAC6E31007C062A /* UIColor+Skeleton.swift */; };
|
||||
@@ -142,10 +146,10 @@
|
||||
42ABD072210B54E100BEEFF4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
42ABD073210B54E100BEEFF4 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
42ABD074210B54E100BEEFF4 /* Base.lproj */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Base.lproj; sourceTree = "<group>"; };
|
||||
42ABD075210B54E100BEEFF4 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
42ABD076210B54E200BEEFF4 /* SkeletonViewExampleCollectionview-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SkeletonViewExampleCollectionview-Info.plist"; sourceTree = "<group>"; };
|
||||
42ABD077210B54E200BEEFF4 /* CollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
52D6D97C1BEFF229002C0205 /* SkeletonView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SkeletonView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8785E3A0211C9C9800CC9DFD /* SkeletonDebug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonDebug.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonAnimationBuilder.swift; sourceTree = "<group>"; };
|
||||
@@ -167,6 +171,7 @@
|
||||
F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+UIApplicationDelegate.swift"; sourceTree = "<group>"; };
|
||||
F58A6E6A20A8C54100612494 /* RecoverableViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoverableViewState.swift; sourceTree = "<group>"; };
|
||||
F58A6E6D20A8C66300612494 /* Recoverable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Recoverable.swift; sourceTree = "<group>"; };
|
||||
F5A5E8B3211DCE7000FD20D0 /* Int+Whitespaces.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Int+Whitespaces.swift"; sourceTree = "<group>"; };
|
||||
F5D3FB0A209DCAA300003FCF /* SubviewsSkeletonables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubviewsSkeletonables.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>"; };
|
||||
@@ -226,7 +231,6 @@
|
||||
42ABD072210B54E100BEEFF4 /* Assets.xcassets */,
|
||||
42ABD074210B54E100BEEFF4 /* Base.lproj */,
|
||||
42ABD077210B54E200BEEFF4 /* CollectionViewCell.swift */,
|
||||
42ABD075210B54E100BEEFF4 /* Constants.swift */,
|
||||
42ABD071210B54E100BEEFF4 /* Main.storyboard */,
|
||||
42ABD073210B54E100BEEFF4 /* ViewController.swift */,
|
||||
);
|
||||
@@ -267,15 +271,32 @@
|
||||
path = Configs;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8785E39E211C9C6D00CC9DFD /* Appearance */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F5307E2F1FB0EC9D00EE67C5 /* SkeletonAppearance.swift */,
|
||||
);
|
||||
path = Appearance;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8785E39F211C9C7C00CC9DFD /* Debug */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8785E3A0211C9C9800CC9DFD /* SkeletonDebug.swift */,
|
||||
);
|
||||
path = Debug;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8933C7811EB5B7E0000D00A4 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8785E39F211C9C7C00CC9DFD /* Debug */,
|
||||
8785E39E211C9C6D00CC9DFD /* Appearance */,
|
||||
F58A6E7020A8C87100612494 /* Recoverable */,
|
||||
F5307E331FB1068500EE67C5 /* Collections */,
|
||||
F5307E341FB106A500EE67C5 /* Extensions */,
|
||||
F5307E351FB106BF00EE67C5 /* Helpers */,
|
||||
F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */,
|
||||
F5307E2F1FB0EC9D00EE67C5 /* SkeletonAppearance.swift */,
|
||||
F587FB83202CBFC8002DB5FE /* SkeletonFlow.swift */,
|
||||
F5307E2B1FAF6BC900EE67C5 /* SkeletonGradient.swift */,
|
||||
F5F899E81FAB9D2B002E8FDA /* SkeletonLayer.swift */,
|
||||
@@ -343,6 +364,7 @@
|
||||
F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */,
|
||||
F5F899CF1FAA6A4D002E8FDA /* UIView+IBInspectable.swift */,
|
||||
F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift */,
|
||||
F5A5E8B3211DCE7000FD20D0 /* Int+Whitespaces.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@@ -593,6 +615,7 @@
|
||||
17DD0E1E207FB32100C56334 /* PrepareForSkeletonProtocol.swift in Sources */,
|
||||
F51ED28520973CC9008B2434 /* SkeletonReusableCell.swift in Sources */,
|
||||
17DD0E17207FB28F00C56334 /* SkeletonLayer.swift in Sources */,
|
||||
8785E3A2211C9CA500CC9DFD /* SkeletonDebug.swift in Sources */,
|
||||
17DD0E08207FB28900C56334 /* CollectionSkeletonProtocol.swift in Sources */,
|
||||
F58A6E6C20A8C54100612494 /* RecoverableViewState.swift in Sources */,
|
||||
17DD0E0B207FB28900C56334 /* SkeletonTableViewProtocols.swift in Sources */,
|
||||
@@ -614,6 +637,7 @@
|
||||
F51ED28420973CC6008B2434 /* GenericCollectionView.swift in Sources */,
|
||||
17DD0E0A207FB28900C56334 /* SkeletonCollectionViewProtocols.swift in Sources */,
|
||||
17DD0E1C207FB32100C56334 /* AssociationPolicy.swift in Sources */,
|
||||
F5A5E8B5211DCE7000FD20D0 /* Int+Whitespaces.swift in Sources */,
|
||||
17DD0E1D207FB32100C56334 /* ContainsMultilineText.swift in Sources */,
|
||||
17DD0E0F207FB28C00C56334 /* CALayer+Extensions.swift in Sources */,
|
||||
17DD0E16207FB28F00C56334 /* SkeletonGradient.swift in Sources */,
|
||||
@@ -627,7 +651,7 @@
|
||||
42ABD07B210B54E200BEEFF4 /* ViewController.swift in Sources */,
|
||||
42ABD078210B54E200BEEFF4 /* AppDelegate.swift in Sources */,
|
||||
42ABD07F210B54E200BEEFF4 /* CollectionViewCell.swift in Sources */,
|
||||
42ABD07D210B54E200BEEFF4 /* Constants.swift in Sources */,
|
||||
8785E3A3211C9CE800CC9DFD /* Constants.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -639,6 +663,7 @@
|
||||
F54CF5E42024CEB000330B0D /* UIView+CollectionSkeleton.swift in Sources */,
|
||||
F5307E371FB1076E00EE67C5 /* SkeletonTableViewProtocols.swift in Sources */,
|
||||
8933C7851EB5B820000D00A4 /* SkeletonView.swift in Sources */,
|
||||
8785E3A1211C9C9800CC9DFD /* SkeletonDebug.swift in Sources */,
|
||||
F5307E301FB0EC9D00EE67C5 /* SkeletonAppearance.swift in Sources */,
|
||||
F58A6E6B20A8C54100612494 /* RecoverableViewState.swift in Sources */,
|
||||
F54CF5E52024CEB000330B0D /* UITableView+CollectionSkeleton.swift in Sources */,
|
||||
@@ -660,6 +685,7 @@
|
||||
F5307E3B1FB123C100EE67C5 /* ContainsMultilineText.swift in Sources */,
|
||||
F5F899E91FAB9D2B002E8FDA /* SkeletonLayer.swift in Sources */,
|
||||
F5307E2E1FB0E5E400EE67C5 /* UIView+Frame.swift in Sources */,
|
||||
F5A5E8B4211DCE7000FD20D0 /* Int+Whitespaces.swift in Sources */,
|
||||
F51DF871206E91B300D23301 /* SkeletonReusableCell.swift in Sources */,
|
||||
F51DF879206E9F5500D23301 /* SkeletonCollectionDelegate.swift in Sources */,
|
||||
F51DE1091FBF70A70037919A /* SkeletonAnimationBuilder.swift in Sources */,
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -28,6 +28,6 @@ extension CollectionSkeleton where Self: UIScrollView {
|
||||
var estimatedNumberOfRows: Int { return 0 }
|
||||
func addDummyDataSource() {}
|
||||
func removeDummyDataSource(reloadAfter: Bool) {}
|
||||
func disableUserInteraction() { isUserInteractionEnabled = false }
|
||||
func enableUserInteraction() { isUserInteractionEnabled = true }
|
||||
func disableUserInteraction() { isScrollEnabled = false }
|
||||
func enableUserInteraction() { isScrollEnabled = true }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
enum SkeletonEnvironmentKey: String {
|
||||
case debugMode = "SKELETON_DEBUG"
|
||||
}
|
||||
|
||||
extension Dictionary {
|
||||
subscript (_ key: SkeletonEnvironmentKey) -> Value? {
|
||||
return self[key.rawValue as! Key]
|
||||
}
|
||||
}
|
||||
|
||||
func printSkeletonHierarchy(in view: UIView) {
|
||||
skeletonLog(view.skeletonHierarchy())
|
||||
}
|
||||
|
||||
func skeletonLog(_ message: String) {
|
||||
if let _ = ProcessInfo.processInfo.environment[.debugMode] {
|
||||
print(message)
|
||||
}
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
|
||||
public var skeletonDescription: String {
|
||||
var description = "<\(type(of: self)): \(Unmanaged.passUnretained(self).toOpaque())"
|
||||
let subSkeletons = subviewsSkeletonables
|
||||
if subSkeletons.count != 0 {
|
||||
description += " | (\(subSkeletons.count)) subSkeletons"
|
||||
}
|
||||
if isSkeletonable {
|
||||
description += " | ☠️ "
|
||||
}
|
||||
return description + ">"
|
||||
}
|
||||
|
||||
public func skeletonHierarchy(index: Int = 0) -> String {
|
||||
var description = index == 0 ? "\n ⬇⬇ ☠️ Root view hierarchy with Skeletons ⬇⬇ \n" : ""
|
||||
description += "\(index == 0 ? "\n" : 3.whitespaces) \(skeletonDescription) \n"
|
||||
subviewsToSkeleton.forEach {
|
||||
description += (index + 2).whitespaces
|
||||
description += $0.skeletonHierarchy(index: index + 1)
|
||||
}
|
||||
return description
|
||||
}
|
||||
}
|
||||
@@ -10,18 +10,20 @@ import UIKit
|
||||
|
||||
extension CALayer {
|
||||
@objc func tint(withColors colors: [UIColor]) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { backgroundColor = colors.first?.cgColor }) {
|
||||
$0.tint(withColors: colors)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
backgroundColor = colors.first?.cgColor
|
||||
}) {
|
||||
$0.tint(withColors: colors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CAGradientLayer {
|
||||
override func tint(withColors colors: [UIColor]) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { self.colors = colors.map { $0.cgColor } }) {
|
||||
$0.tint(withColors: colors)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
self.colors = colors.map { $0.cgColor }
|
||||
}) {
|
||||
$0.tint(withColors: colors)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,16 +93,18 @@ public extension CALayer {
|
||||
}
|
||||
|
||||
func playAnimation(_ anim: SkeletonLayerAnimation, key: String) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { add(anim(self), forKey: key) }) {
|
||||
$0.playAnimation(anim, key: key)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
add(anim(self), forKey: key)
|
||||
}) {
|
||||
$0.playAnimation(anim, key: key)
|
||||
}
|
||||
}
|
||||
|
||||
func stopAnimation(forKey key: String) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { removeAnimation(forKey: key) }) {
|
||||
$0.stopAnimation(forKey: key)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
removeAnimation(forKey: key)
|
||||
}) {
|
||||
$0.stopAnimation(forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Int {
|
||||
|
||||
var whitespace: String {
|
||||
return whitespaces
|
||||
}
|
||||
|
||||
var whitespaces: String {
|
||||
return String(repeating: " ", count: self)
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,28 @@
|
||||
//
|
||||
// HelperProtocols.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Juanpe Catalán on 06/11/2017.
|
||||
// Copyright © 2017 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
typealias VoidBlock = () -> Void
|
||||
typealias RecursiveBlock<T> = (T) -> Void
|
||||
|
||||
protocol IterableElement {}
|
||||
extension UIView: IterableElement {}
|
||||
extension CALayer: IterableElement {}
|
||||
|
||||
//MARK: Recursive
|
||||
protocol Recursive {
|
||||
associatedtype Element
|
||||
func recursiveSearch(inArray array:[Element], leafBlock: VoidBlock, recursiveBlock: RecursiveBlock<Element>)
|
||||
associatedtype Element: IterableElement
|
||||
func recursiveSearch(leafBlock: VoidBlock, recursiveBlock: RecursiveBlock<Element>)
|
||||
}
|
||||
|
||||
extension Recursive {
|
||||
func recursiveSearch(inArray array:[Element], leafBlock: VoidBlock, recursiveBlock: RecursiveBlock<Element>) {
|
||||
guard array.count > 0 else {
|
||||
extension Array: Recursive where Element: IterableElement {
|
||||
func recursiveSearch(leafBlock: VoidBlock, recursiveBlock: RecursiveBlock<Element>) {
|
||||
guard count > 0 else {
|
||||
leafBlock()
|
||||
return
|
||||
}
|
||||
array.forEach { recursiveBlock($0) }
|
||||
forEach { recursiveBlock($0) }
|
||||
}
|
||||
}
|
||||
|
||||
extension UIView: Recursive {
|
||||
typealias Element = UIView
|
||||
}
|
||||
extension CALayer: Recursive {
|
||||
typealias Element = CALayer
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
//
|
||||
// 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 didShowSkeletons(withRootView rootView: UIView)
|
||||
func willBeginHidingSkeletons(withRootView rootView: UIView)
|
||||
func didHideSkeletons(withRootView rootView: UIView)
|
||||
|
||||
}
|
||||
|
||||
class SkeletonFlowHandler: SkeletonFlowDelegate {
|
||||
|
||||
|
||||
func willBeginShowingSkeletons(withRootView rootView: UIView) {
|
||||
rootView.addAppNotificationsObservers()
|
||||
}
|
||||
|
||||
func didShowSkeletons(withRootView rootView: UIView) {
|
||||
printSkeletonHierarchy(in: rootView)
|
||||
}
|
||||
|
||||
func willBeginHidingSkeletons(withRootView rootView: UIView) {
|
||||
rootView.removeAppNoticationsObserver()
|
||||
}
|
||||
|
||||
func didHideSkeletons(withRootView rootView: UIView) {
|
||||
rootView.flowDelegate = nil
|
||||
}
|
||||
}
|
||||
|
||||
+31
-27
@@ -22,22 +22,20 @@ public extension UIView {
|
||||
|
||||
func hideSkeleton(reloadDataAfter reload: Bool = true) {
|
||||
flowDelegate?.willBeginHidingSkeletons(withRootView: self)
|
||||
recursiveHideSkeleton(reloadDataAfter: reload)
|
||||
recursiveHideSkeleton(reloadDataAfter: reload, root: self)
|
||||
}
|
||||
|
||||
func startSkeletonAnimation(_ anim: SkeletonLayerAnimation? = nil) {
|
||||
skeletonIsAnimated = true
|
||||
recursiveSearch(inArray: subviewsSkeletonables,
|
||||
leafBlock: startSkeletonLayerAnimationBlock(anim)) {
|
||||
$0.startSkeletonAnimation(anim)
|
||||
}
|
||||
subviewsSkeletonables.recursiveSearch(leafBlock: startSkeletonLayerAnimationBlock(anim)) { subview in
|
||||
subview.startSkeletonAnimation(anim)
|
||||
}
|
||||
}
|
||||
|
||||
func stopSkeletonAnimation() {
|
||||
skeletonIsAnimated = false
|
||||
recursiveSearch(inArray: subviewsSkeletonables,
|
||||
leafBlock: stopSkeletonLayerAnimationBlock) {
|
||||
$0.stopSkeletonAnimation()
|
||||
subviewsSkeletonables.recursiveSearch(leafBlock: stopSkeletonLayerAnimationBlock) { subview in
|
||||
subview.stopSkeletonAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,33 +46,39 @@ extension UIView {
|
||||
skeletonIsAnimated = animated
|
||||
flowDelegate = SkeletonFlowHandler()
|
||||
flowDelegate?.willBeginShowingSkeletons(withRootView: self)
|
||||
recursiveShowSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation)
|
||||
recursiveShowSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation, root: self)
|
||||
}
|
||||
|
||||
fileprivate func recursiveShowSkeleton(withType type: SkeletonType, usingColors colors: [UIColor], animated: Bool, animation: SkeletonLayerAnimation?) {
|
||||
fileprivate func recursiveShowSkeleton(withType type: SkeletonType, usingColors colors: [UIColor], animated: Bool, animation: SkeletonLayerAnimation?, root: UIView? = nil) {
|
||||
addDummyDataSourceIfNeeded()
|
||||
recursiveSearch(inArray: subviewsSkeletonables,
|
||||
leafBlock: {
|
||||
guard !isSkeletonActive else { return }
|
||||
isUserInteractionEnabled = false
|
||||
saveViewState()
|
||||
(self as? PrepareForSkeleton)?.prepareViewForSkeleton()
|
||||
addSkeletonLayer(withType: type, usingColors: colors, animated: animated, animation: animation)
|
||||
}) {
|
||||
$0.recursiveShowSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation)
|
||||
|
||||
subviewsSkeletonables.recursiveSearch(leafBlock: {
|
||||
guard !isSkeletonActive else { return }
|
||||
isUserInteractionEnabled = false
|
||||
saveViewState()
|
||||
(self as? PrepareForSkeleton)?.prepareViewForSkeleton()
|
||||
addSkeletonLayer(withType: type, usingColors: colors, animated: animated, animation: animation)
|
||||
}) { subview in
|
||||
subview.recursiveShowSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation)
|
||||
}
|
||||
|
||||
if let root = root {
|
||||
flowDelegate?.didShowSkeletons(withRootView: root)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func recursiveHideSkeleton(reloadDataAfter reload: Bool) {
|
||||
fileprivate func recursiveHideSkeleton(reloadDataAfter reload: Bool, root: UIView? = nil) {
|
||||
removeDummyDataSourceIfNeeded()
|
||||
isUserInteractionEnabled = true
|
||||
recursiveSearch(inArray: subviewsSkeletonables,
|
||||
leafBlock: {
|
||||
recoverViewState(forced: false)
|
||||
removeSkeletonLayer()
|
||||
}, recursiveBlock: {
|
||||
$0.recursiveHideSkeleton(reloadDataAfter: reload)
|
||||
})
|
||||
subviewsSkeletonables.recursiveSearch(leafBlock: {
|
||||
recoverViewState(forced: false)
|
||||
removeSkeletonLayer()
|
||||
}) { subview in
|
||||
subview.recursiveHideSkeleton(reloadDataAfter: reload)
|
||||
}
|
||||
if let root = root {
|
||||
flowDelegate?.didHideSkeletons(withRootView: root)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func startSkeletonLayerAnimationBlock(_ anim: SkeletonLayerAnimation? = nil) -> VoidBlock {
|
||||
|
||||
@@ -1,45 +1,48 @@
|
||||
//
|
||||
// SubviewsSkeletonables.swift
|
||||
// SkeletonView
|
||||
//
|
||||
// Created by Juanpe Catalán on 05/05/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
@objc var subviewsSkeletonables: [UIView] {
|
||||
return subviews.filter { $0.isSkeletonable }
|
||||
return subviewsToSkeleton.filter { $0.isSkeletonable }
|
||||
}
|
||||
|
||||
@objc var subviewsToSkeleton: [UIView] {
|
||||
return subviews
|
||||
}
|
||||
}
|
||||
|
||||
extension UITableView {
|
||||
override var subviewsSkeletonables: [UIView] {
|
||||
return visibleCells.filter { $0.isSkeletonable }
|
||||
|
||||
override var subviewsToSkeleton: [UIView] {
|
||||
return visibleCells
|
||||
}
|
||||
}
|
||||
|
||||
extension UITableViewCell {
|
||||
override var subviewsSkeletonables: [UIView] {
|
||||
return contentView.subviews.filter { $0.isSkeletonable }
|
||||
|
||||
override var subviewsToSkeleton: [UIView] {
|
||||
return contentView.subviews
|
||||
}
|
||||
}
|
||||
|
||||
extension UICollectionView {
|
||||
override var subviewsSkeletonables: [UIView] {
|
||||
return subviews.filter { $0.isSkeletonable }
|
||||
|
||||
override var subviewsToSkeleton: [UIView] {
|
||||
return subviews
|
||||
}
|
||||
}
|
||||
|
||||
extension UICollectionViewCell {
|
||||
override var subviewsSkeletonables: [UIView] {
|
||||
return contentView.subviews.filter { $0.isSkeletonable }
|
||||
|
||||
override var subviewsToSkeleton: [UIView] {
|
||||
return contentView.subviews
|
||||
}
|
||||
}
|
||||
|
||||
extension UIStackView {
|
||||
override var subviewsSkeletonables: [UIView] {
|
||||
return arrangedSubviews.filter { $0.isSkeletonable }
|
||||
|
||||
override var subviewsToSkeleton: [UIView] {
|
||||
return arrangedSubviews
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user