diff --git a/Examples/iOS Example/Sources/ViewController.swift b/Examples/iOS Example/Sources/ViewController.swift
index 3796abc0..cb80e51c 100644
--- a/Examples/iOS Example/Sources/ViewController.swift
+++ b/Examples/iOS Example/Sources/ViewController.swift
@@ -76,8 +76,8 @@ class ViewController: UIViewController {
}
@IBAction func showOrHideSkeleton(_ sender: Any) {
- showOrHideSkeletonButton.setTitle((view.isSkeletonActive ? "Show skeleton" : "Hide skeleton"), for: .normal)
- view.isSkeletonActive ? hideSkeleton() : showSkeleton()
+ showOrHideSkeletonButton.setTitle((view.sk.isSkeletonActive ? "Show skeleton" : "Hide skeleton"), for: .normal)
+ view.sk.isSkeletonActive ? hideSkeleton() : showSkeleton()
}
@IBAction func transitionDurationStepperAction(_ sender: Any) {
diff --git a/README.md b/README.md
index 07287296..7abcf655 100755
--- a/README.md
+++ b/README.md
@@ -548,14 +548,11 @@ func showGradientSkeleton(usingGradient: SkeletonGradient,
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:
+First, `UIView` has available a property with his skeleton info:
```swift
-var skeletonDescription: String
+var sk.skeletonTreeDescription: String
```
-The skeleton representation looks like this:
-
-![](Assets/debug_description.png)
Besides, you can activate the new **debug mode**. You just add the environment variable `SKELETON_DEBUG` and activate it.
@@ -563,11 +560,21 @@ Besides, you can activate the new **debug mode**. You just add the environment v
Then, when the skeleton appears, you can see the view hierarchy in the Xcode console.
-
-Open to see an output example
-
-
-
+```
+{
+ "type" : "UIView", // UITableView, UILabel...
+ "isSkeletonable" : true,
+ "reference" : "0x000000014751ce30",
+ "children" : [
+ {
+ "type" : "UIView",
+ "isSkeletonable" : true,
+ "children" : [ ... ],
+ "reference" : "0x000000014751cfa0"
+ }
+ ]
+}
+```
**Supported OS & SDK Versions**
diff --git a/SkeletonView.xcodeproj/project.pbxproj b/SkeletonView.xcodeproj/project.pbxproj
index 3ab80ac1..6047c617 100644
--- a/SkeletonView.xcodeproj/project.pbxproj
+++ b/SkeletonView.xcodeproj/project.pbxproj
@@ -7,6 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
+ F53D731826D399E100249D46 /* SkeletonTreeNode+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F53D731726D399E100249D46 /* SkeletonTreeNode+Extensions.swift */; };
+ F53D731926D399E100249D46 /* SkeletonTreeNode+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F53D731726D399E100249D46 /* SkeletonTreeNode+Extensions.swift */; };
+ F53D731B26D3A35100249D46 /* SkeletonExtended.swift in Sources */ = {isa = PBXBuildFile; fileRef = F53D731A26D3A35100249D46 /* SkeletonExtended.swift */; };
+ F53D731C26D3A35100249D46 /* SkeletonExtended.swift in Sources */ = {isa = PBXBuildFile; fileRef = F53D731A26D3A35100249D46 /* SkeletonExtended.swift */; };
+ F53D731F26D3AC4000249D46 /* SkeletonTreeNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F70726D38F3100A80B83 /* SkeletonTreeNode.swift */; };
F556F56626CD1F3900A80B83 /* SkeletonAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* SkeletonAppearance.swift */; };
F556F56726CD1F3900A80B83 /* SkeletonLayerBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* SkeletonLayerBuilder.swift */; };
F556F56826CD1F3900A80B83 /* SkeletonMultilineLayerBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* SkeletonMultilineLayerBuilder.swift */; };
@@ -57,8 +62,8 @@
F556F69626CD509E00A80B83 /* Notification+SkeletonFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F69426CD509E00A80B83 /* Notification+SkeletonFlow.swift */; };
F556F69E26CD553B00A80B83 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F69D26CD553B00A80B83 /* UIView+Extensions.swift */; };
F556F69F26CD553B00A80B83 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F69D26CD553B00A80B83 /* UIView+Extensions.swift */; };
- F556F6A126CD566C00A80B83 /* UIView+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6A026CD566C00A80B83 /* UIView+Debug.swift */; };
- F556F6A226CD566C00A80B83 /* UIView+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6A026CD566C00A80B83 /* UIView+Debug.swift */; };
+ F556F6A126CD566C00A80B83 /* UIView+SKExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6A026CD566C00A80B83 /* UIView+SKExtensions.swift */; };
+ F556F6A226CD566C00A80B83 /* UIView+SKExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6A026CD566C00A80B83 /* UIView+SKExtensions.swift */; };
F556F6A426CD5A9000A80B83 /* CALayer+Animations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6A326CD5A9000A80B83 /* CALayer+Animations.swift */; };
F556F6A526CD5A9000A80B83 /* CALayer+Animations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6A326CD5A9000A80B83 /* CALayer+Animations.swift */; };
F556F6A726CD5B0400A80B83 /* CALayer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6A626CD5B0400A80B83 /* CALayer+Extensions.swift */; };
@@ -90,9 +95,8 @@
F556F6DD26CE33CE00A80B83 /* UIView+Swizzling.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6DC26CE33CE00A80B83 /* UIView+Swizzling.swift */; };
F556F6E026CE367600A80B83 /* UIView+SkeletonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6DF26CE367600A80B83 /* UIView+SkeletonView.swift */; };
F556F6E126CE367600A80B83 /* UIView+SkeletonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6DF26CE367600A80B83 /* UIView+SkeletonView.swift */; };
- F556F6F226CE818B00A80B83 /* UIView+Flags.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6F126CE818B00A80B83 /* UIView+Flags.swift */; };
- F556F6F326CE818B00A80B83 /* UIView+Flags.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6F126CE818B00A80B83 /* UIView+Flags.swift */; };
F556F6F626CE876300A80B83 /* UIView+Swizzling.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6DC26CE33CE00A80B83 /* UIView+Swizzling.swift */; };
+ F556F70826D38F3100A80B83 /* SkeletonTreeNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F70726D38F3100A80B83 /* SkeletonTreeNode.swift */; };
OBJ_101 /* Int+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* Int+Extensions.swift */; };
OBJ_103 /* UIColor+Skeleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* UIColor+Skeleton.swift */; };
OBJ_104 /* UITableView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_34 /* UITableView+Extensions.swift */; };
@@ -143,6 +147,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
+ F53D731726D399E100249D46 /* SkeletonTreeNode+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SkeletonTreeNode+Extensions.swift"; sourceTree = ""; };
+ F53D731A26D3A35100249D46 /* SkeletonExtended.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonExtended.swift; sourceTree = ""; };
F556F51026CD1B7900A80B83 /* SkeletonView.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = SkeletonView.podspec; sourceTree = ""; };
F556F51126CD1B8000A80B83 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
F556F51426CD1BFF00A80B83 /* README_zh.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README_zh.md; path = Translations/README_zh.md; sourceTree = ""; };
@@ -181,7 +187,7 @@
F556F69126CD506C00A80B83 /* Deprecated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deprecated.swift; sourceTree = ""; };
F556F69426CD509E00A80B83 /* Notification+SkeletonFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+SkeletonFlow.swift"; sourceTree = ""; };
F556F69D26CD553B00A80B83 /* UIView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = ""; };
- F556F6A026CD566C00A80B83 /* UIView+Debug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Debug.swift"; sourceTree = ""; };
+ F556F6A026CD566C00A80B83 /* UIView+SKExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+SKExtensions.swift"; sourceTree = ""; };
F556F6A326CD5A9000A80B83 /* CALayer+Animations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CALayer+Animations.swift"; sourceTree = ""; };
F556F6A626CD5B0400A80B83 /* CALayer+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CALayer+Extensions.swift"; sourceTree = ""; };
F556F6AA26CD5C4900A80B83 /* SkeletonMultilinesLayerConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonMultilinesLayerConfig.swift; sourceTree = ""; };
@@ -198,7 +204,7 @@
F556F6D826CE315A00A80B83 /* UICollectionView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+Extensions.swift"; sourceTree = ""; };
F556F6DC26CE33CE00A80B83 /* UIView+Swizzling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Swizzling.swift"; sourceTree = ""; };
F556F6DF26CE367600A80B83 /* UIView+SkeletonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+SkeletonView.swift"; sourceTree = ""; };
- F556F6F126CE818B00A80B83 /* UIView+Flags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Flags.swift"; sourceTree = ""; };
+ F556F70726D38F3100A80B83 /* SkeletonTreeNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonTreeNode.swift; sourceTree = ""; };
OBJ_11 /* SkeletonLayerBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonLayerBuilder.swift; sourceTree = ""; };
OBJ_12 /* SkeletonMultilineLayerBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonMultilineLayerBuilder.swift; sourceTree = ""; };
OBJ_14 /* CollectionSkeleton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionSkeleton.swift; sourceTree = ""; };
@@ -356,6 +362,7 @@
F556F68C26CD4EB400A80B83 /* FoundationExtensions */,
F556F6B726CE25B100A80B83 /* Models */,
F556F64F26CD2DFD00A80B83 /* SkeletonView.swift */,
+ F53D731A26D3A35100249D46 /* SkeletonExtended.swift */,
F556F68526CD49E900A80B83 /* UIKitExtensions */,
);
path = API;
@@ -364,6 +371,7 @@
F556F64B26CD2CD600A80B83 /* Internal */ = {
isa = PBXGroup;
children = (
+ F556F70626D38E8300A80B83 /* SkeletonTree */,
F556F6D326CE2F3700A80B83 /* Collections */,
F556F65226CD2E0A00A80B83 /* Debug */,
F556F67E26CD476300A80B83 /* FoundationExtensions */,
@@ -411,6 +419,7 @@
F556F6DF26CE367600A80B83 /* UIView+SkeletonView.swift */,
F556F6DC26CE33CE00A80B83 /* UIView+Swizzling.swift */,
OBJ_61 /* UIView+Transitions.swift */,
+ F53D731726D399E100249D46 /* SkeletonTreeNode+Extensions.swift */,
);
path = UIKitExtensions;
sourceTree = "";
@@ -431,11 +440,10 @@
children = (
F556F6A326CD5A9000A80B83 /* CALayer+Animations.swift */,
F556F68626CD49F900A80B83 /* UIView+IBInspectable.swift */,
- F556F6A026CD566C00A80B83 /* UIView+Debug.swift */,
+ F556F6A026CD566C00A80B83 /* UIView+SKExtensions.swift */,
F556F6C526CE2A2100A80B83 /* UILabel+IBInspectable.swift */,
F556F6C826CE2A4A00A80B83 /* UITextView+IBInspectable.swift */,
F556F6D826CE315A00A80B83 /* UICollectionView+Extensions.swift */,
- F556F6F126CE818B00A80B83 /* UIView+Flags.swift */,
);
path = UIKitExtensions;
sourceTree = "";
@@ -544,6 +552,14 @@
path = Appearance;
sourceTree = "";
};
+ F556F70626D38E8300A80B83 /* SkeletonTree */ = {
+ isa = PBXGroup;
+ children = (
+ F556F70726D38F3100A80B83 /* SkeletonTreeNode.swift */,
+ );
+ path = SkeletonTree;
+ sourceTree = "";
+ };
OBJ_15 /* CollectionViews */ = {
isa = PBXGroup;
children = (
@@ -771,6 +787,7 @@
F556F6D026CE2AB800A80B83 /* SkeletonTextNode.swift in Sources */,
F556F65126CD2DFD00A80B83 /* SkeletonView.swift in Sources */,
F556F56826CD1F3900A80B83 /* SkeletonMultilineLayerBuilder.swift in Sources */,
+ F53D731926D399E100249D46 /* SkeletonTreeNode+Extensions.swift in Sources */,
F556F56926CD1F3900A80B83 /* CollectionSkeleton.swift in Sources */,
F556F56A26CD1F3900A80B83 /* SkeletonCollectionViewProtocols.swift in Sources */,
F556F6C026CE277F00A80B83 /* PrepareViewForSkeleton.swift in Sources */,
@@ -794,6 +811,7 @@
F556F57E26CD1F3900A80B83 /* AssociationPolicy.swift in Sources */,
F556F6B026CE244100A80B83 /* DispatchQueue+Extensions.swift in Sources */,
F556F58026CD1F3900A80B83 /* Recursive.swift in Sources */,
+ F53D731C26D3A35100249D46 /* SkeletonExtended.swift in Sources */,
F556F6F626CE876300A80B83 /* UIView+Swizzling.swift in Sources */,
F556F58126CD1F3900A80B83 /* Swizzling.swift in Sources */,
F556F6B626CE258300A80B83 /* GradientDirection+Animations.swift in Sources */,
@@ -805,14 +823,14 @@
F556F58926CD1F3900A80B83 /* SkeletonFlowHandler.swift in Sources */,
F556F58A26CD1F3900A80B83 /* SkeletonGradient.swift in Sources */,
F556F6C326CE27FD00A80B83 /* SkeletonType.swift in Sources */,
- F556F6F326CE818B00A80B83 /* UIView+Flags.swift in Sources */,
F556F58B26CD1F3900A80B83 /* SkeletonLayer.swift in Sources */,
- F556F6A226CD566C00A80B83 /* UIView+Debug.swift in Sources */,
+ F556F6A226CD566C00A80B83 /* UIView+SKExtensions.swift in Sources */,
F556F69326CD506C00A80B83 /* Deprecated.swift in Sources */,
F556F6BA26CE262700A80B83 /* GradientDirection.swift in Sources */,
F556F58D26CD1F3900A80B83 /* SubviewsSkeletonables.swift in Sources */,
F556F58E26CD1F3900A80B83 /* SkeletonTransitionStyle.swift in Sources */,
F556F6AC26CD5C4900A80B83 /* SkeletonMultilinesLayerConfig.swift in Sources */,
+ F53D731F26D3AC4000249D46 /* SkeletonTreeNode.swift in Sources */,
F556F68126CD47CF00A80B83 /* ProcessInfo+Extensions.swift in Sources */,
F556F68826CD49F900A80B83 /* UIView+IBInspectable.swift in Sources */,
F556F6C726CE2A2100A80B83 /* UILabel+IBInspectable.swift in Sources */,
@@ -849,7 +867,7 @@
F556F6CF26CE2AB800A80B83 /* SkeletonTextNode.swift in Sources */,
F556F65026CD2DFD00A80B83 /* SkeletonView.swift in Sources */,
OBJ_88 /* SkeletonMultilineLayerBuilder.swift in Sources */,
- F556F6F226CE818B00A80B83 /* UIView+Flags.swift in Sources */,
+ F53D731B26D3A35100249D46 /* SkeletonExtended.swift in Sources */,
OBJ_89 /* CollectionSkeleton.swift in Sources */,
OBJ_90 /* SkeletonCollectionViewProtocols.swift in Sources */,
F556F6BF26CE277F00A80B83 /* PrepareViewForSkeleton.swift in Sources */,
@@ -872,7 +890,9 @@
OBJ_109 /* UIView+AppLifecycleNotifications.swift in Sources */,
OBJ_110 /* AssociationPolicy.swift in Sources */,
F556F6AF26CE244100A80B83 /* DispatchQueue+Extensions.swift in Sources */,
+ F53D731826D399E100249D46 /* SkeletonTreeNode+Extensions.swift in Sources */,
OBJ_112 /* Recursive.swift in Sources */,
+ F556F70826D38F3100A80B83 /* SkeletonTreeNode.swift in Sources */,
OBJ_113 /* Swizzling.swift in Sources */,
F556F6B526CE258300A80B83 /* GradientDirection+Animations.swift in Sources */,
F556F69E26CD553B00A80B83 /* UIView+Extensions.swift in Sources */,
@@ -885,7 +905,7 @@
F556F6C226CE27FD00A80B83 /* SkeletonType.swift in Sources */,
OBJ_123 /* SkeletonLayer.swift in Sources */,
F556F6E026CE367600A80B83 /* UIView+SkeletonView.swift in Sources */,
- F556F6A126CD566C00A80B83 /* UIView+Debug.swift in Sources */,
+ F556F6A126CD566C00A80B83 /* UIView+SKExtensions.swift in Sources */,
F556F69226CD506C00A80B83 /* Deprecated.swift in Sources */,
F556F6B926CE262700A80B83 /* GradientDirection.swift in Sources */,
OBJ_125 /* SubviewsSkeletonables.swift in Sources */,
diff --git a/SkeletonViewCore/Sources/API/Deprecated.swift b/SkeletonViewCore/Sources/API/Deprecated.swift
index 5f6ad3d0..fbacf205 100644
--- a/SkeletonViewCore/Sources/API/Deprecated.swift
+++ b/SkeletonViewCore/Sources/API/Deprecated.swift
@@ -11,7 +11,7 @@
//
// Created by Juanpe Catalán on 18/8/21.
-import Foundation
+import UIKit
public extension Notification.Name {
@@ -34,3 +34,17 @@ public extension Notification.Name {
static let didHideSkeletons = Notification.Name.skeletonDidDisappearNotification
}
+
+public extension UIView {
+
+ @available(*, deprecated, renamed: "sk.treeNodesDescription")
+ var skeletonDescription: String {
+ sk.skeletonTreeDescription
+ }
+
+ @available(*, deprecated, renamed: "sk.isSkeletonActive")
+ var isSkeletonActive: Bool {
+ sk.isSkeletonActive
+ }
+
+}
diff --git a/SkeletonViewCore/Sources/API/SkeletonExtended.swift b/SkeletonViewCore/Sources/API/SkeletonExtended.swift
new file mode 100644
index 00000000..483633bb
--- /dev/null
+++ b/SkeletonViewCore/Sources/API/SkeletonExtended.swift
@@ -0,0 +1,45 @@
+//
+// Copyright SkeletonView. All Rights Reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// SkeletonExtended.swift
+//
+// Created by Juanpe Catalán on 23/8/21.
+
+import Foundation
+
+/// Type that acts as a generic extension point for all `SkeletonViewExtended` types.
+public struct SkeletonViewExtension {
+ /// Stores the type or meta-type of any extended type.
+ public private(set) var type: ExtendedType
+
+ /// Create an instance from the provided value.
+ ///
+ /// - Parameter type: Instance being extended.
+ public init(_ type: ExtendedType) {
+ self.type = type
+ }
+}
+
+/// Protocol describing the `sk` extension points for SkeletonView extended types.
+public protocol SkeletonViewExtended {
+ /// Type being extended.
+ associatedtype ExtendedType
+
+ /// Instance SkeletonView extension point.
+ var sk: SkeletonViewExtension { get set }
+}
+
+extension SkeletonViewExtended {
+ /// Instance SkeletonView extension point.
+ public var sk: SkeletonViewExtension {
+ get { SkeletonViewExtension(self) }
+ // swiftlint:disable:next unused_setter_value
+ set {}
+ }
+}
diff --git a/SkeletonViewCore/Sources/API/UIKitExtensions/UIView+Debug.swift b/SkeletonViewCore/Sources/API/UIKitExtensions/UIView+Debug.swift
deleted file mode 100644
index dfc33bc0..00000000
--- a/SkeletonViewCore/Sources/API/UIKitExtensions/UIView+Debug.swift
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// Copyright SkeletonView. All Rights Reserved.
-//
-// Licensed under the MIT License (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://opensource.org/licenses/MIT
-//
-// UIView+Debug.swift
-//
-// Created by Juanpe Catalán on 18/8/21.
-
-import UIKit
-
-public extension UIView {
-
- /// Returns a string that describes the hierarchy of the skeleton, indicating
- /// whether the receiver is skeletonable and all skeletonable children.
- var skeletonDescription: String {
- var description = "<\(type(of: self)): \(Unmanaged.passUnretained(self).toOpaque())"
- let subSkeletons = subviewsSkeletonables
-
- if !subSkeletons.isEmpty {
- description += " | (\(subSkeletons.count)) subSkeletons"
- }
-
- if isSkeletonable {
- description += " | ☠️ "
- }
-
- return description + ">"
- }
-
-}
diff --git a/SkeletonViewCore/Sources/API/UIKitExtensions/UIView+Flags.swift b/SkeletonViewCore/Sources/API/UIKitExtensions/UIView+Flags.swift
deleted file mode 100644
index 2471dd4f..00000000
--- a/SkeletonViewCore/Sources/API/UIKitExtensions/UIView+Flags.swift
+++ /dev/null
@@ -1,22 +0,0 @@
-//
-// Copyright SkeletonView. All Rights Reserved.
-//
-// Licensed under the MIT License (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://opensource.org/licenses/MIT
-//
-// UIView+Flags.swift
-//
-// Created by Juanpe Catalán on 19/8/21.
-
-import UIKit
-
-public extension UIView {
-
- var isSkeletonActive: Bool {
- return _status == .on || subviewsSkeletonables.contains(where: { $0.isSkeletonActive })
- }
-
-}
diff --git a/SkeletonViewCore/Sources/API/UIKitExtensions/UIView+SKExtensions.swift b/SkeletonViewCore/Sources/API/UIKitExtensions/UIView+SKExtensions.swift
new file mode 100644
index 00000000..7262ce89
--- /dev/null
+++ b/SkeletonViewCore/Sources/API/UIKitExtensions/UIView+SKExtensions.swift
@@ -0,0 +1,33 @@
+//
+// Copyright SkeletonView. All Rights Reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// UIView+SKExtensions.swift
+//
+// Created by Juanpe Catalán on 18/8/21.
+
+import UIKit
+
+public extension SkeletonViewExtension where ExtendedType: UIView {
+
+ /// Returns a string that describes the hierarchy of the skeleton, indicating
+ /// whether the receiver is skeletonable and all skeletonable children.
+ var skeletonTreeDescription: String {
+ guard let theJSONData = try? JSONSerialization.data(withJSONObject: treeNode.dictionaryRepresentation, options: [.prettyPrinted]) else {
+ skeletonLog("Skeleton tree generation has failed!")
+ return ""
+ }
+
+ return String(data: theJSONData, encoding: .utf8)!
+ }
+
+ var isSkeletonActive: Bool {
+ type._status == .on || type.subviewsSkeletonables.contains(where: { $0.sk.isSkeletonActive })
+ }
+
+}
diff --git a/SkeletonViewCore/Sources/Internal/Collections/SkeletonCollectionDataSource.swift b/SkeletonViewCore/Sources/Internal/Collections/SkeletonCollectionDataSource.swift
index b18e9149..1b56a044 100644
--- a/SkeletonViewCore/Sources/Internal/Collections/SkeletonCollectionDataSource.swift
+++ b/SkeletonViewCore/Sources/Internal/Collections/SkeletonCollectionDataSource.swift
@@ -114,7 +114,7 @@ extension SkeletonCollectionDataSource: UICollectionViewDataSource {
extension SkeletonCollectionDataSource {
private func skeletonViewIfContainerSkeletonIsActive(container: UIView, view: UIView) {
- guard container.isSkeletonActive,
+ guard container.sk.isSkeletonActive,
let skeletonConfig = container._currentSkeletonConfig else {
return
}
diff --git a/SkeletonViewCore/Sources/Internal/Collections/SkeletonCollectionDelegate.swift b/SkeletonViewCore/Sources/Internal/Collections/SkeletonCollectionDelegate.swift
index 3a8fd40d..aa9ca703 100644
--- a/SkeletonViewCore/Sources/Internal/Collections/SkeletonCollectionDelegate.swift
+++ b/SkeletonViewCore/Sources/Internal/Collections/SkeletonCollectionDelegate.swift
@@ -55,7 +55,7 @@ extension SkeletonCollectionDelegate: UICollectionViewDelegate { }
extension SkeletonCollectionDelegate {
private func skeletonViewIfContainerSkeletonIsActive(container: UIView, view: UIView) {
- guard container.isSkeletonActive,
+ guard container.sk.isSkeletonActive,
let skeletonConfig = container._currentSkeletonConfig else {
return
}
diff --git a/SkeletonViewCore/Sources/Internal/Debug/SkeletonDebug.swift b/SkeletonViewCore/Sources/Internal/Debug/SkeletonDebug.swift
index 18b2dc8b..27fcb53c 100644
--- a/SkeletonViewCore/Sources/Internal/Debug/SkeletonDebug.swift
+++ b/SkeletonViewCore/Sources/Internal/Debug/SkeletonDebug.swift
@@ -25,10 +25,6 @@ extension Dictionary {
}
}
-func printSkeletonHierarchy(in view: UIView) {
- skeletonLog(view.skeletonHierarchy())
-}
-
func skeletonLog(_ message: String) {
#if DEBUG
if ProcessInfo.processInfo.environment[.debugMode] != nil {
@@ -36,17 +32,3 @@ func skeletonLog(_ message: String) {
}
#endif
}
-
-extension UIView {
-
- func skeletonHierarchy(indentationLevel level: Int = 0) -> String {
- var description = level == 0 ? "\n ⬇⬇ ☠️ Root view hierarchy with Skeletons ⬇⬇ \n" : ""
- description += "\(level == 0 ? "\n" : 3.whitespaces) \(skeletonDescription) \n"
- subviewsToSkeleton.forEach {
- description += (level + 2).whitespaces
- description += $0.skeletonHierarchy(indentationLevel: level + 1)
- }
- return description
- }
-
-}
diff --git a/SkeletonViewCore/Sources/Internal/SkeletonFlowHandler.swift b/SkeletonViewCore/Sources/Internal/SkeletonFlowHandler.swift
index ef1ef325..90dc0e36 100644
--- a/SkeletonViewCore/Sources/Internal/SkeletonFlowHandler.swift
+++ b/SkeletonViewCore/Sources/Internal/SkeletonFlowHandler.swift
@@ -20,7 +20,7 @@ class SkeletonFlowHandler: SkeletonFlowDelegate {
}
func didShowSkeletons(rootView: UIView) {
- printSkeletonHierarchy(in: rootView)
+ skeletonLog(rootView.sk.skeletonTreeDescription)
NotificationCenter.default.post(name: .skeletonWillAppearNotification, object: rootView, userInfo: nil)
}
diff --git a/SkeletonViewCore/Sources/Internal/SkeletonTree/SkeletonTreeNode.swift b/SkeletonViewCore/Sources/Internal/SkeletonTree/SkeletonTreeNode.swift
new file mode 100644
index 00000000..2cd95871
--- /dev/null
+++ b/SkeletonViewCore/Sources/Internal/SkeletonTree/SkeletonTreeNode.swift
@@ -0,0 +1,27 @@
+//
+// Copyright SkeletonView. All Rights Reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// SkeletonTreeNode.swift
+//
+// Created by Juanpe Catalán on 23/8/21.
+
+import UIKit
+
+public struct SkeletonTreeNode {
+ /// Base object to extend.
+ let base: Base
+
+ /// Creates extensions with base object.
+ ///
+ /// - parameter base: Base object.
+ init(_ base: Base) {
+ self.base = base
+ }
+
+}
diff --git a/SkeletonViewCore/Sources/Internal/UIKitExtensions/SkeletonTreeNode+Extensions.swift b/SkeletonViewCore/Sources/Internal/UIKitExtensions/SkeletonTreeNode+Extensions.swift
new file mode 100644
index 00000000..ec3ee862
--- /dev/null
+++ b/SkeletonViewCore/Sources/Internal/UIKitExtensions/SkeletonTreeNode+Extensions.swift
@@ -0,0 +1,50 @@
+//
+// Copyright SkeletonView. All Rights Reserved.
+//
+// Licensed under the MIT License (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/MIT
+//
+// SkeletonTreeNode+Extensions.swift
+//
+// Created by Juanpe Catalán on 23/8/21.
+
+import UIKit
+
+extension UIView: SkeletonViewExtended { }
+
+extension SkeletonTreeNode where Base: UIView {
+
+ var children: [SkeletonTreeNode] {
+ base.subviewsSkeletonables.map { $0.sk.treeNode }
+ }
+
+ var parent: SkeletonTreeNode? {
+ base.superview?.sk.treeNode
+ }
+
+}
+
+// MARK: Debug
+
+extension SkeletonTreeNode where Base: UIView {
+
+ var dictionaryRepresentation: [String: Any] {
+ let children = children
+
+ var nodeInfo: [String: Any] = [
+ "type": "\(type(of: base))",
+ "reference": "\(Unmanaged.passUnretained(base).toOpaque())",
+ "isSkeletonable": base.isSkeletonable
+ ]
+
+ if !children.isEmpty {
+ nodeInfo["children"] = children.map { $0.dictionaryRepresentation }
+ }
+
+ return nodeInfo
+ }
+
+}
diff --git a/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+AppLifecycleNotifications.swift b/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+AppLifecycleNotifications.swift
index e03365df..8f1a4771 100644
--- a/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+AppLifecycleNotifications.swift
+++ b/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+AppLifecycleNotifications.swift
@@ -38,7 +38,7 @@ extension UIView {
}
@objc func appDidEnterBackground() {
- UserDefaults.standard.set((isSkeletonActive && _isSkeletonAnimated), forKey: Constants.needAnimatedSkeletonKey)
+ UserDefaults.standard.set((sk.isSkeletonActive && _isSkeletonAnimated), forKey: Constants.needAnimatedSkeletonKey)
}
@objc func willTerminateNotification() {
diff --git a/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+Extensions.swift b/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+Extensions.swift
index 72b441cb..c62b1c2e 100644
--- a/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+Extensions.swift
+++ b/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+Extensions.swift
@@ -13,6 +13,14 @@
import UIKit
+extension SkeletonViewExtension where ExtendedType: UIView {
+
+ var treeNode: SkeletonTreeNode {
+ SkeletonTreeNode(self.type)
+ }
+
+}
+
extension UIView {
/// Flags
@@ -159,7 +167,7 @@ extension UIView {
}
func removeSkeletonLayer() {
- guard isSkeletonActive,
+ guard sk.isSkeletonActive,
let skeletonLayer = _skeletonLayer,
let transitionStyle = _currentSkeletonConfig?.transition else { return }
skeletonLayer.stopAnimation()
diff --git a/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+SkeletonView.swift b/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+SkeletonView.swift
index 159a43fc..df6bc33a 100644
--- a/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+SkeletonView.swift
+++ b/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+SkeletonView.swift
@@ -30,7 +30,7 @@ extension UIView {
func recursiveLayoutSkeletonIfNeeded(root: UIView? = nil) {
subviewsSkeletonables.recursiveSearch(leafBlock: {
- guard isSkeletonable, isSkeletonActive else { return }
+ guard isSkeletonable, sk.isSkeletonActive else { return }
layoutSkeletonLayerIfNeeded()
if let config = _currentSkeletonConfig, config.animated, !_isSkeletonAnimated {
startSkeletonAnimation(config.animation)
@@ -45,7 +45,7 @@ extension UIView {
}
func recursiveHideSkeleton(reloadDataAfter reload: Bool, transition: SkeletonTransitionStyle, root: UIView? = nil) {
- guard isSkeletonActive else { return }
+ guard sk.isSkeletonActive else { return }
if isHiddenWhenSkeletonIsActive {
isHidden = false
}
@@ -70,7 +70,7 @@ extension UIView {
private extension UIView {
func showSkeletonIfNotActive(skeletonConfig config: SkeletonConfig) {
- guard !isSkeletonActive else { return }
+ guard !sk.isSkeletonActive else { return }
saveViewState()
prepareViewForSkeleton()
@@ -81,7 +81,7 @@ private extension UIView {
if isHiddenWhenSkeletonIsActive {
isHidden = true
}
- guard isSkeletonable && !isSkeletonActive else { return }
+ guard isSkeletonable && !sk.isSkeletonActive else { return }
_currentSkeletonConfig = config
swizzleLayoutSubviews()
swizzleTraitCollectionDidChange()
@@ -98,7 +98,7 @@ private extension UIView {
}
func recursiveUpdateSkeleton(skeletonConfig config: SkeletonConfig, root: UIView? = nil) {
- guard isSkeletonActive else { return }
+ guard sk.isSkeletonActive else { return }
_currentSkeletonConfig = config
updateDummyDataSourceIfNeeded()
subviewsSkeletonables.recursiveSearch(leafBlock: {
diff --git a/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+Swizzling.swift b/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+Swizzling.swift
index 866c68d8..3c257161 100644
--- a/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+Swizzling.swift
+++ b/SkeletonViewCore/Sources/Internal/UIKitExtensions/UIView+Swizzling.swift
@@ -18,13 +18,13 @@ extension UIView {
@objc func skeletonLayoutSubviews() {
guard Thread.isMainThread else { return }
skeletonLayoutSubviews()
- guard isSkeletonActive else { return }
+ guard sk.isSkeletonActive else { return }
layoutSkeletonIfNeeded()
}
@objc func skeletonTraitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
skeletonTraitCollectionDidChange(previousTraitCollection)
- guard isSkeletonable, isSkeletonActive, let config = _currentSkeletonConfig else { return }
+ guard isSkeletonable, sk.isSkeletonActive, let config = _currentSkeletonConfig else { return }
updateSkeleton(skeletonConfig: config)
}