Compare commits

..

43 Commits

Author SHA1 Message Date
Juanpe Catalán fdd17dd4e9 fix: missing UIView+IBInspectable 2019-08-22 15:16:37 +02:00
Juanpe Catalán 14ef5012f3 feat: refactor Swift format 2019-08-22 15:11:01 +02:00
Juanpe Catalán e62c7d8c0e Merge branch 'develop'
# Conflicts:
#	.codebeatsettings
2019-08-22 12:07:41 +02:00
Juanpe Catalán e7aa9da5ae feat: BUMP cocoapods version 2019-08-22 12:04:29 +02:00
Juanpe Catalán 09a30d36b8 feat: remove whitespaces 2019-08-22 09:34:56 +02:00
Juanpe Catalán d5656b9715 feat: change some methods about animate transition 2019-08-22 03:00:09 +02:00
Juanpe Catalán 66dc7e89c5 fix: SPM install instructions 2019-08-21 13:03:56 +02:00
Juanpe Catalán 5c815d7647 feat: add new rule for codebeat 2019-08-21 13:01:47 +02:00
Juanpe Catalán aa60f82c81 feat: create codebeat settings 2019-08-21 12:12:03 +02:00
Juanpe Catalán 6676760860 feat: config number of functions allowed. Codebeat file 2019-08-21 12:08:52 +02:00
Juanpe Catalán b571988fad update README 2019-08-21 10:04:14 +02:00
Juanpe Catalán abd9130ff6 Merge branch 'master' into develop 2019-08-21 10:02:41 +02:00
Juanpe Catalán fc9dca1730 revert README.md 2019-08-21 10:01:56 +02:00
Juanpe Catalán 46a95eecb4 Merge pull request #170 from pontusjacobsson/master
Fade in and fade out animations of the skeletonViews
2019-08-21 09:57:47 +02:00
Pontus Jacobsson e08e563ec0 Fixed typo 2019-08-21 09:23:54 +02:00
Pontus Jacobsson 1c24785ed6 Merge branch 'master' of https://github.com/pontusjacobsson/SkeletonView
# Conflicts:
#	README.md
2019-08-20 17:17:29 +02:00
Pontus Jacobsson bbcaeedd19 Added hide transition to readme 2019-08-20 17:16:13 +02:00
Pontus Jacobsson 6fc8f5caea Added hide transition to readme 2019-08-20 17:15:06 +02:00
Pontus Jacobsson ab6efd1504 Updated readme 2019-08-20 17:08:18 +02:00
Pontus Jacobsson 6632f5d91e Cleaned up code 2019-08-05 15:52:03 +02:00
Pontus Jacobsson c1a47f098b Cleaned up code 2019-08-02 13:35:41 +02:00
Pontus Jacobsson 02be363c95 Updated tableView tutorial and also added custom transitions on "hideSkeleton()" 2019-08-02 13:11:11 +02:00
Pontus Jacobsson cb0e4c63cf Added fading testing for the collection view example 2019-08-01 22:42:27 +02:00
Pontus Jacobsson 26d839387d Fixed background color bug when showing skeleton without transition 2019-07-31 10:41:20 +02:00
Pontus Jacobsson e05d013af8 Cleaned up some code and aded extra viewState keys 2019-07-31 09:50:13 +02:00
Pontus Jacobsson d8a5df75ee Cleaned up code and changed recoverableStates to structs 2019-07-30 21:51:40 +02:00
Pontus Jacobsson f7eb048317 Changed code to Eduard Bosch's tips with minor adjustments 2019-07-30 19:55:27 +02:00
Pontus Jacobsson 4497e5cdb9 Cleaned up some code 2019-07-30 10:35:54 +02:00
Pontus Jacobsson e83ab2e033 Cleaned up code 2019-07-29 13:44:50 +02:00
Pontus Jacobsson d40a877c42 Handled access level on transitions 2019-07-29 12:56:43 +02:00
Pontus Jacobsson 3b6c61cfcb Cleaned up some code 2019-07-29 11:53:09 +02:00
Pontus Jacobsson f42b77fd4d Removed lost file 2019-07-29 11:48:39 +02:00
Pontus Jacobsson c75df015d8 Added missing compilation file 2019-07-29 11:43:01 +02:00
Pontus Jacobsson 0393c04aa8 Moved some functions 2019-07-29 11:41:02 +02:00
Pontus Jacobsson c3df0bc5df Fixed a file bug in xcode prov 2019-07-29 11:35:57 +02:00
Pontus Jacobsson 0f0bb220f2 Cleaned up some code 2019-07-29 11:33:35 +02:00
Pontus Jacobsson a299c8c0c8 Added support for multiple transitions instead of just one 2019-07-29 11:32:31 +02:00
Pontus Jacobsson aea2ae6793 Added missing fade in call 2019-07-29 09:36:17 +02:00
Pontus Jacobsson a3ed33f53b Added fade in/out duration to config and text color to recoveryState 2019-07-26 17:04:52 +02:00
Pontus Jacobsson 6cf19ca50d Added support to start fade from all "showSkeleton" functions 2019-07-26 16:36:13 +02:00
Pontus Jacobsson ca0b295a80 Added support for fade in and fade out animations of the skeleton load 2019-07-26 16:28:30 +02:00
Juanpe Catalán 60c387b250 feat: update gemfile 2019-07-23 10:54:52 +02:00
Juanpe Catalán 1eece8e013 feat: update gemfile 2019-07-06 11:42:03 +02:00
48 changed files with 596 additions and 236 deletions
+6
View File
@@ -0,0 +1,6 @@
{
"SWIFT": {
"TOO_MANY_FUNCTIONS": [50, 100, 150, 200],
"TOTAL_LOC": [200, 400, 500, 600]
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB

+1 -1
View File
@@ -8,7 +8,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "avatar.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "picture.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

@@ -6,12 +6,14 @@ import SkeletonView
class CollectionViewCell: UICollectionViewCell {
var label: UILabel!
var imageView: UIImageView!
override init(frame: CGRect) {
super.init(frame: frame)
isSkeletonable = true
createLabel()
createImageView()
}
@@ -19,16 +21,34 @@ class CollectionViewCell: UICollectionViewCell {
fatalError("init(coder:) has not been implemented")
}
private func createImageView() {
imageView = UIImageView(image: UIImage(named: "picture"))
imageView.isSkeletonable = true
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
addSubview(imageView)
NSLayoutConstraint.activate([
imageView.centerXAnchor.constraint(equalTo: centerXAnchor),
imageView.topAnchor.constraint(equalTo: topAnchor),
imageView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.75),
imageView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.75)
])
}
private func createLabel() {
label = UILabel()
label.isSkeletonable = true
label.text = "Lorem ipsum"
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: centerXAnchor),
label.centerYAnchor.constraint(equalTo: centerYAnchor),
label.heightAnchor.constraint(equalToConstant: frame.height / 2),
label.widthAnchor.constraint(equalToConstant: frame.width / 2)
label.bottomAnchor.constraint(equalTo: bottomAnchor),
label.heightAnchor.constraint(equalToConstant: 40),
label.widthAnchor.constraint(equalToConstant: frame.width)
])
}
+69 -26
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="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="irH-dz-xqL">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="irH-dz-xqL">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -13,7 +13,7 @@
<!--View Controller-->
<scene sceneID="qda-qV-vJk">
<objects>
<viewController id="irH-dz-xqL" customClass="ViewController" customModule="SkeletonViewExampleUICollectionView" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="irH-dz-xqL" customClass="ViewController" customModule="SkeletonViewExampleUICollectionView" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Fso-nq-n6t">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -37,7 +37,7 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar" translatesAutoresizingMaskIntoConstraints="NO" id="Ql9-Jy-aWM">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar" translatesAutoresizingMaskIntoConstraints="NO" id="Ql9-Jy-aWM">
<rect key="frame" x="141" y="20" width="93" height="93"/>
<color key="backgroundColor" red="0.56078431370000004" green="0.59607843140000005" blue="0.7843137255" alpha="0.90709546230000004" colorSpace="calibratedRGB"/>
<constraints>
@@ -66,7 +66,7 @@
</userDefinedRuntimeAttributes>
</view>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="HKL-L0-T2w">
<rect key="frame" x="0.0" y="263" width="375" height="264"/>
<rect key="frame" x="0.0" y="263" width="375" height="244"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="mGU-kn-rfE">
<size key="itemSize" width="50" height="50"/>
@@ -80,11 +80,10 @@
</connections>
</collectionView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JjA-MK-YzZ">
<rect key="frame" x="0.0" y="527" width="375" height="140"/>
<rect key="frame" x="0.0" y="507" width="375" height="160"/>
<subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="fMR-vj-7de">
<rect key="frame" x="20" y="23" width="140" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="fMR-vj-7de">
<rect key="frame" x="20" y="22.5" width="135" height="29"/>
<segments>
<segment title="Solid"/>
<segment title="Gradient"/>
@@ -93,44 +92,85 @@
<action selector="changeSkeletonType:" destination="irH-dz-xqL" eventType="valueChanged" id="lfR-JV-DU4"/>
</connections>
</segmentedControl>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KBe-RM-BG8">
<rect key="frame" x="310" y="21" width="49" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KBe-RM-BG8">
<rect key="frame" x="308" y="21" width="51" height="31"/>
<connections>
<action selector="changeAnimated:" destination="irH-dz-xqL" eventType="valueChanged" id="dlH-KK-iee"/>
</connections>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Animated" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GSj-Ze-UIK">
<rect key="frame" x="211" y="28" width="91" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Animated" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GSj-Ze-UIK">
<rect key="frame" x="229" y="26" width="73" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Color" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4Hm-fj-45V">
<rect key="frame" x="32" y="89" width="52" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Color" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4Hm-fj-45V">
<rect key="frame" x="20" y="61" width="41.5" height="52"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HBJ-nh-56V">
<rect key="frame" x="92" y="84" width="30" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HBJ-nh-56V">
<rect key="frame" x="69.5" y="72" width="30" height="30"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="DVW-Tc-XEQ"/>
<constraint firstAttribute="height" constant="30" id="JfP-3b-yqX"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aUR-Qo-gHK">
<rect key="frame" x="20" y="74" width="140" height="52"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aUR-Qo-gHK">
<rect key="frame" x="20" y="61" width="100" height="52"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="GvX-hq-2Qn"/>
<constraint firstAttribute="height" constant="52" id="UQe-Cf-riE"/>
</constraints>
<connections>
<action selector="btnChangeColorTouchUpInside:" destination="irH-dz-xqL" eventType="touchUpInside" id="Xca-QC-htl"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nPs-17-vfs">
<rect key="frame" x="263" y="72" width="94" height="30"/>
<state key="normal" title="Hide skeleton"/>
<connections>
<action selector="showOrHideSkeleton:" destination="irH-dz-xqL" eventType="touchUpInside" id="lHc-k2-OgV"/>
</connections>
</button>
<stepper opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="5" stepValue="0.25" translatesAutoresizingMaskIntoConstraints="NO" id="3mz-9M-e7Q">
<rect key="frame" x="263" y="126" width="94" height="29"/>
<connections>
<action selector="transitionDurationStepperAction:" destination="irH-dz-xqL" eventType="valueChanged" id="Ll0-Pr-d0V"/>
</connections>
</stepper>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Fade Duration: 0 sec" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5gN-Jz-44y">
<rect key="frame" x="113.5" y="131.5" width="141.5" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="140" id="QDV-wu-e3I"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="140" id="qR5-cz-YAm"/>
<constraint firstItem="3mz-9M-e7Q" firstAttribute="leading" secondItem="5gN-Jz-44y" secondAttribute="trailing" constant="8" id="65e-Nj-bKG"/>
<constraint firstItem="HBJ-nh-56V" firstAttribute="centerY" secondItem="aUR-Qo-gHK" secondAttribute="centerY" id="81M-Wq-Avl"/>
<constraint firstItem="fMR-vj-7de" firstAttribute="leading" secondItem="JjA-MK-YzZ" secondAttribute="leading" constant="20" id="AyG-hI-tte"/>
<constraint firstItem="aUR-Qo-gHK" firstAttribute="leading" secondItem="fMR-vj-7de" secondAttribute="leading" id="C1b-Hl-jEg"/>
<constraint firstItem="3mz-9M-e7Q" firstAttribute="trailing" secondItem="nPs-17-vfs" secondAttribute="trailing" id="KuK-fc-jOQ"/>
<constraint firstItem="nPs-17-vfs" firstAttribute="centerY" secondItem="aUR-Qo-gHK" secondAttribute="centerY" id="MQX-E5-IDE"/>
<constraint firstItem="HBJ-nh-56V" firstAttribute="leading" secondItem="4Hm-fj-45V" secondAttribute="trailing" constant="8" id="MhM-jY-LIA"/>
<constraint firstItem="4Hm-fj-45V" firstAttribute="height" secondItem="aUR-Qo-gHK" secondAttribute="height" id="OSn-RA-wQL"/>
<constraint firstItem="4Hm-fj-45V" firstAttribute="leading" secondItem="aUR-Qo-gHK" secondAttribute="leading" id="PwQ-UR-iMq"/>
<constraint firstAttribute="height" constant="160" id="QDV-wu-e3I"/>
<constraint firstItem="5gN-Jz-44y" firstAttribute="centerY" secondItem="3mz-9M-e7Q" secondAttribute="centerY" id="TGP-Ep-0ob"/>
<constraint firstItem="nPs-17-vfs" firstAttribute="top" secondItem="KBe-RM-BG8" secondAttribute="bottom" constant="20" id="TPg-wY-9bc"/>
<constraint firstItem="4Hm-fj-45V" firstAttribute="centerY" secondItem="aUR-Qo-gHK" secondAttribute="centerY" id="V4i-bF-Jed"/>
<constraint firstItem="KBe-RM-BG8" firstAttribute="leading" secondItem="GSj-Ze-UIK" secondAttribute="trailing" constant="6" id="ehg-tW-7kq"/>
<constraint firstItem="GSj-Ze-UIK" firstAttribute="centerY" secondItem="KBe-RM-BG8" secondAttribute="centerY" id="esk-GV-DBS"/>
<constraint firstAttribute="trailing" secondItem="KBe-RM-BG8" secondAttribute="trailing" constant="18" id="hhE-rV-dV7"/>
<constraint firstItem="KBe-RM-BG8" firstAttribute="top" secondItem="JjA-MK-YzZ" secondAttribute="top" constant="21" id="pBQ-H8-xTK"/>
<constraint firstAttribute="bottom" secondItem="3mz-9M-e7Q" secondAttribute="bottom" constant="5" id="pQ9-a6-hM4"/>
<constraint firstItem="fMR-vj-7de" firstAttribute="centerY" secondItem="GSj-Ze-UIK" secondAttribute="centerY" id="q2v-t1-Zu0"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="160" id="qR5-cz-YAm"/>
<constraint firstItem="nPs-17-vfs" firstAttribute="trailing" secondItem="KBe-RM-BG8" secondAttribute="trailing" id="yls-k6-ZfC"/>
</constraints>
</view>
</subviews>
@@ -153,8 +193,11 @@
<outlet property="avatarImage" destination="Ql9-Jy-aWM" id="VoL-by-ygR"/>
<outlet property="collectionView" destination="HKL-L0-T2w" id="HSe-j0-S5d"/>
<outlet property="colorSelectedView" destination="HBJ-nh-56V" id="Iiq-iY-Glj"/>
<outlet property="showOrHideSkeletonButton" destination="nPs-17-vfs" id="vw4-fW-QoD"/>
<outlet property="skeletonTypeSelector" destination="fMR-vj-7de" id="CgX-3A-weo"/>
<outlet property="switchAnimated" destination="KBe-RM-BG8" id="emU-g9-NHT"/>
<outlet property="transitionDurationLabel" destination="5gN-Jz-44y" id="69y-iR-mbi"/>
<outlet property="transitionDurationStepper" destination="3mz-9M-e7Q" id="tzK-W7-A4D"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="PkM-Y0-M5i" userLabel="First Responder" sceneMemberID="firstResponder"/>
+25 -9
View File
@@ -4,7 +4,6 @@ import UIKit
import SkeletonView
class ViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView! {
didSet {
collectionView.isSkeletonable = true
@@ -36,6 +35,9 @@ class ViewController: UIViewController {
@IBOutlet weak var switchAnimated: UISwitch!
@IBOutlet weak var skeletonTypeSelector: UISegmentedControl!
@IBOutlet weak var showOrHideSkeletonButton: UIButton!
@IBOutlet weak var transitionDurationLabel: UILabel!
@IBOutlet weak var transitionDurationStepper: UIStepper!
var type: SkeletonType {
return skeletonTypeSelector.selectedSegmentIndex == 0 ? .solid : .gradient
@@ -65,6 +67,23 @@ class ViewController: UIViewController {
showAlertPicker()
}
@IBAction func showOrHideSkeleton(_ sender: Any) {
showOrHideSkeletonButton.setTitle((view.isSkeletonActive ? "Show skeleton" : "Hide skeleton"), for: .normal)
view.isSkeletonActive ? hideSkeleton() : showSkeleton()
}
@IBAction func transitionDurationStepperAction(_ sender: Any) {
transitionDurationLabel.text = "transition duration: \(transitionDurationStepper.value) sec"
}
func showSkeleton() {
refreshSkeleton()
}
func hideSkeleton() {
view.hideSkeleton(transition: .crossDisolve(transitionDurationStepper.value))
}
func refreshSkeleton() {
self.view.hideSkeleton()
if type == .gradient { showGradientSkeleton() }
@@ -73,23 +92,22 @@ class ViewController: UIViewController {
func showSolidSkeleton() {
if switchAnimated.isOn {
view.showAnimatedSkeleton(usingColor: colorSelectedView.backgroundColor!)
view.showAnimatedSkeleton(usingColor: colorSelectedView.backgroundColor!, transition: .crossDissolve(transitionDurationStepper.value))
} else {
view.showSkeleton(usingColor: colorSelectedView.backgroundColor!)
view.showSkeleton(usingColor: colorSelectedView.backgroundColor!, transition: .crossDissolve(transitionDurationStepper.value))
}
}
func showGradientSkeleton() {
let gradient = SkeletonGradient(baseColor: colorSelectedView.backgroundColor!)
if switchAnimated.isOn {
view.showAnimatedGradientSkeleton(usingGradient: gradient)
view.showAnimatedGradientSkeleton(usingGradient: gradient, transition: .crossDissolve(transitionDurationStepper.value))
} else {
view.showGradientSkeleton(usingGradient: gradient)
view.showGradientSkeleton(usingGradient: gradient, transition: .crossDissolve(transitionDurationStepper.value))
}
}
func showAlertPicker() {
let alertView = UIAlertController(title: "Select color", message: "\n\n\n\n\n\n", preferredStyle: .alert)
let pickerView = UIPickerView(frame: CGRect(x: 0, y: 50, width: 260, height: 115))
@@ -117,7 +135,6 @@ class ViewController: UIViewController {
// MARK: - UIPickerViewDelegate, UIPickerViewDataSource
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
@@ -134,7 +151,6 @@ class ViewController: UIViewController {
// MARK: - UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width/3 - 10, height: view.frame.width/3 - 10)
}
@@ -162,7 +178,7 @@ extension ViewController: SkeletonCollectionViewDataSource {
// MARK: - UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 0
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+67 -25
View File
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" 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="14490.70" 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="14088"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -20,7 +19,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<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"/>
<rect key="frame" x="0.0" y="263" width="375" height="244"/>
<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"/>
<prototypes>
@@ -107,7 +106,7 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar" translatesAutoresizingMaskIntoConstraints="NO" id="nMj-pU-5wJ">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar" translatesAutoresizingMaskIntoConstraints="NO" id="nMj-pU-5wJ">
<rect key="frame" x="141" y="20" width="93" height="93"/>
<color key="backgroundColor" red="0.56078431370000004" green="0.59607843140000005" blue="0.7843137255" alpha="0.90709546230000004" colorSpace="calibratedRGB"/>
<constraints>
@@ -134,11 +133,10 @@
</userDefinedRuntimeAttributes>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XgY-1a-UGc">
<rect key="frame" x="0.0" y="527" width="375" height="140"/>
<rect key="frame" x="0.0" y="507" width="375" height="160"/>
<subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="xOL-Sq-r4i">
<rect key="frame" x="20" y="23" width="140" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="xOL-Sq-r4i">
<rect key="frame" x="20" y="23" width="135" height="29"/>
<segments>
<segment title="Solid"/>
<segment title="Gradient"/>
@@ -147,43 +145,84 @@
<action selector="changeSkeletonType:" destination="BYZ-38-t0r" eventType="valueChanged" id="iAS-ab-0jP"/>
</connections>
</segmentedControl>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vz0-qg-GcZ">
<rect key="frame" x="310" y="21" width="49" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vz0-qg-GcZ">
<rect key="frame" x="308" y="21" width="51" height="31"/>
<connections>
<action selector="changeAnimated:" destination="BYZ-38-t0r" eventType="valueChanged" id="w1G-gZ-RE0"/>
</connections>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Animated" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WHN-wR-TKt">
<rect key="frame" x="211" y="28" width="91" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Animated" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WHN-wR-TKt">
<rect key="frame" x="229" y="26" width="73" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Color" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7CF-rV-pK2">
<rect key="frame" x="32" y="89" width="52" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Color" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7CF-rV-pK2">
<rect key="frame" x="20" y="73.5" width="90" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iGp-rp-t1d">
<rect key="frame" x="92" y="84" width="30" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iGp-rp-t1d">
<rect key="frame" x="130" y="69" width="30" height="30"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="Q3k-B1-E88"/>
<constraint firstAttribute="height" constant="30" id="xOD-RY-U4u"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Mde-Cm-CoS">
<rect key="frame" x="20" y="74" width="140" height="52"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Mde-Cm-CoS">
<rect key="frame" x="20" y="58" width="140" height="52"/>
<constraints>
<constraint firstAttribute="height" constant="52" id="3GX-2y-eQj"/>
<constraint firstAttribute="width" constant="140" id="6cC-Y1-RKs"/>
</constraints>
<connections>
<action selector="btnChangeColorTouchUpInside:" destination="BYZ-38-t0r" eventType="touchUpInside" id="cB8-Ik-LIJ"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Tdu-YQ-saq">
<rect key="frame" x="263" y="69" width="94" height="30"/>
<state key="normal" title="Hide skeleton"/>
<connections>
<action selector="showOrHideSkeleton:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Ma1-WX-Dzy"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Fade Duration: 0 sec" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mrw-PM-jJJ">
<rect key="frame" x="113.5" y="128.5" width="141.5" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stepper opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="5" stepValue="0.25" translatesAutoresizingMaskIntoConstraints="NO" id="l4N-LL-ZrJ">
<rect key="frame" x="263" y="123" width="94" height="29"/>
<connections>
<action selector="transitionDurationStepperAction:" destination="BYZ-38-t0r" eventType="valueChanged" id="jPN-df-fNs"/>
</connections>
</stepper>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="140" id="OH5-ja-ZlB"/>
<constraint firstItem="l4N-LL-ZrJ" firstAttribute="leading" secondItem="mrw-PM-jJJ" secondAttribute="trailing" constant="8" id="5iU-dO-qVc"/>
<constraint firstItem="mrw-PM-jJJ" firstAttribute="centerY" secondItem="l4N-LL-ZrJ" secondAttribute="centerY" id="9OM-mx-4Jo"/>
<constraint firstAttribute="trailing" secondItem="Tdu-YQ-saq" secondAttribute="trailing" constant="18" id="BQ0-S0-YMp"/>
<constraint firstItem="iGp-rp-t1d" firstAttribute="trailing" secondItem="Mde-Cm-CoS" secondAttribute="trailing" id="IJ3-CC-5M7"/>
<constraint firstAttribute="height" constant="160" id="OH5-ja-ZlB"/>
<constraint firstItem="Mde-Cm-CoS" firstAttribute="leading" secondItem="XgY-1a-UGc" secondAttribute="leading" constant="20" id="Rek-hz-pDw"/>
<constraint firstItem="xOL-Sq-r4i" firstAttribute="top" secondItem="XgY-1a-UGc" secondAttribute="top" constant="23" id="Udf-0g-bZm"/>
<constraint firstItem="Tdu-YQ-saq" firstAttribute="top" secondItem="vz0-qg-GcZ" secondAttribute="bottom" constant="17" id="WiR-yP-dyv"/>
<constraint firstItem="Mde-Cm-CoS" firstAttribute="centerY" secondItem="7CF-rV-pK2" secondAttribute="centerY" id="eaN-FA-4mF"/>
<constraint firstItem="iGp-rp-t1d" firstAttribute="centerY" secondItem="7CF-rV-pK2" secondAttribute="centerY" id="hBb-mp-AjF"/>
<constraint firstItem="l4N-LL-ZrJ" firstAttribute="top" secondItem="Tdu-YQ-saq" secondAttribute="bottom" constant="24" id="iA5-RB-pW2"/>
<constraint firstItem="vz0-qg-GcZ" firstAttribute="top" secondItem="XgY-1a-UGc" secondAttribute="top" constant="21" id="iad-6N-wNf"/>
<constraint firstItem="vz0-qg-GcZ" firstAttribute="leading" secondItem="WHN-wR-TKt" secondAttribute="trailing" constant="6" id="jgu-tV-gqO"/>
<constraint firstItem="WHN-wR-TKt" firstAttribute="centerY" secondItem="vz0-qg-GcZ" secondAttribute="centerY" id="kTu-fb-Bc8"/>
<constraint firstAttribute="trailing" secondItem="vz0-qg-GcZ" secondAttribute="trailing" constant="18" id="ktq-JT-uoR"/>
<constraint firstItem="xOL-Sq-r4i" firstAttribute="leading" secondItem="XgY-1a-UGc" secondAttribute="leading" constant="20" id="pY0-qd-xmK"/>
<constraint firstItem="l4N-LL-ZrJ" firstAttribute="trailing" secondItem="Tdu-YQ-saq" secondAttribute="trailing" id="ql2-Z9-dnv"/>
<constraint firstItem="iGp-rp-t1d" firstAttribute="leading" secondItem="7CF-rV-pK2" secondAttribute="trailing" constant="20" id="vWD-0m-dMp"/>
<constraint firstItem="7CF-rV-pK2" firstAttribute="centerY" secondItem="Tdu-YQ-saq" secondAttribute="centerY" id="x0d-LB-A4q"/>
<constraint firstItem="7CF-rV-pK2" firstAttribute="leading" secondItem="xOL-Sq-r4i" secondAttribute="leading" id="yEL-Nv-z76"/>
</constraints>
</view>
</subviews>
@@ -209,9 +248,12 @@
<connections>
<outlet property="avatarImage" destination="nMj-pU-5wJ" id="9fa-Z7-vYi"/>
<outlet property="colorSelectedView" destination="iGp-rp-t1d" id="0Zm-9d-jRU"/>
<outlet property="showOrHideSkeletonButton" destination="Tdu-YQ-saq" id="gkm-mB-zYD"/>
<outlet property="skeletonTypeSelector" destination="xOL-Sq-r4i" id="yTr-8L-I4Y"/>
<outlet property="switchAnimated" destination="vz0-qg-GcZ" id="d2R-8x-lRb"/>
<outlet property="tableview" destination="UCB-SP-lQk" id="XV0-KX-lAN"/>
<outlet property="transitionDurationLabel" destination="mrw-PM-jJJ" id="BVK-Kl-5Q3"/>
<outlet property="transitionDurationStepper" destination="l4N-LL-ZrJ" id="OJr-Ul-7XR"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+37 -5
View File
@@ -10,7 +10,6 @@ import UIKit
import SkeletonView
class ViewController: UIViewController {
@IBOutlet weak var tableview: UITableView! {
didSet {
tableview.rowHeight = UITableView.automaticDimension
@@ -35,6 +34,9 @@ class ViewController: UIViewController {
@IBOutlet weak var switchAnimated: UISwitch!
@IBOutlet weak var skeletonTypeSelector: UISegmentedControl!
@IBOutlet weak var showOrHideSkeletonButton: UIButton!
@IBOutlet weak var transitionDurationLabel: UILabel!
@IBOutlet weak var transitionDurationStepper: UIStepper!
var type: SkeletonType {
return skeletonTypeSelector.selectedSegmentIndex == 0 ? .solid : .gradient
@@ -70,6 +72,39 @@ class ViewController: UIViewController {
showAlertPicker()
}
@IBAction func showOrHideSkeleton(_ sender: Any) {
showOrHideSkeletonButton.setTitle((view.isSkeletonActive ? "Show skeleton" : "Hide skeleton"), for: .normal)
view.isSkeletonActive ? hideSkeleton() : showSkeleton()
}
@IBAction func transitionDurationStepperAction(_ sender: Any) {
transitionDurationLabel.text = "Transition duration: \(transitionDurationStepper.value) sec"
}
func showSkeleton() {
if type == .gradient {
let gradient = SkeletonGradient(baseColor: colorSelectedView.backgroundColor!)
if switchAnimated.isOn {
view.showAnimatedGradientSkeleton(usingGradient: gradient, transition: .crossDissolve(transitionDurationStepper.value))
}
else {
view.showGradientSkeleton(usingGradient: gradient, transition: .crossDissolve(transitionDurationStepper.value))
}
}
else {
if switchAnimated.isOn {
view.showAnimatedSkeleton(transition: .crossDissolve(transitionDurationStepper.value))
}
else {
view.showSkeleton(transition: .crossDissolve(transitionDurationStepper.value))
}
}
}
func hideSkeleton() {
view.hideSkeleton(transition: .crossDissolve(transitionDurationStepper.value))
}
func refreshSkeleton() {
if type == .gradient { showOrUpdateGradientSkeleton() }
else { showOrUpdatepdateSolidSkeleton() }
@@ -93,7 +128,6 @@ class ViewController: UIViewController {
}
func showAlertPicker() {
let alertView = UIAlertController(title: "Select color", message: "\n\n\n\n\n\n", preferredStyle: .alert)
let pickerView = UIPickerView(frame: CGRect(x: 0, y: 50, width: 260, height: 115))
@@ -119,7 +153,6 @@ class ViewController: UIViewController {
}
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
@@ -134,9 +167,8 @@ extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
}
extension ViewController: SkeletonTableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
return 10
}
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier {
+23 -23
View File
@@ -12,10 +12,10 @@ GEM
atomos (0.1.3)
babosa (1.0.2)
claide (1.0.2)
cocoapods (1.7.0.beta.3)
cocoapods (1.7.5)
activesupport (>= 4.0.2, < 5)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.7.0.beta.3)
cocoapods-core (= 1.7.5)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.2.2, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
@@ -25,13 +25,13 @@ GEM
cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1)
escape (~> 0.0.4)
fourflusher (>= 2.2.0, < 3.0)
fourflusher (>= 2.3.0, < 3.0)
gh_inspector (~> 1.0)
molinillo (~> 0.6.6)
nap (~> 1.0)
ruby-macho (~> 1.4)
xcodeproj (>= 1.8.2, < 2.0)
cocoapods-core (1.7.0.beta.3)
xcodeproj (>= 1.10.0, < 2.0)
cocoapods-core (1.7.5)
activesupport (>= 4.0.2, < 6)
fuzzy_match (~> 2.0.4)
nap (~> 1.0)
@@ -53,12 +53,12 @@ GEM
declarative (0.0.10)
declarative-option (0.1.0)
digest-crc (0.4.1)
domain_name (0.5.20180417)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.2)
dotenv (2.7.4)
emoji_regex (1.0.1)
escape (0.0.4)
excon (0.64.0)
excon (0.65.0)
faraday (0.15.4)
multipart-post (>= 1.2, < 3)
faraday-cookie_jar (0.0.6)
@@ -67,7 +67,7 @@ GEM
faraday_middleware (0.13.1)
faraday (>= 0.7.4, < 1.0)
fastimage (2.1.5)
fastlane (2.121.0)
fastlane (2.128.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
babosa (>= 1.0.2, < 2.0.0)
@@ -86,8 +86,8 @@ GEM
google-cloud-storage (>= 1.15.0, < 2.0.0)
highline (>= 1.7.2, < 2.0.0)
json (< 3.0.0)
mini_magick (~> 4.5.1)
multi_json
jwt (~> 2.1.0)
mini_magick (>= 4.9.4, < 5.0.0)
multi_xml (~> 0.5)
multipart-post (~> 2.0.0)
plist (>= 3.1.0, < 4.0.0)
@@ -104,7 +104,7 @@ GEM
xcodeproj (>= 1.8.1, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
fourflusher (2.2.0)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
google-api-client (0.23.9)
@@ -117,7 +117,7 @@ GEM
signet (~> 0.9)
google-cloud-core (1.3.0)
google-cloud-env (~> 1.0)
google-cloud-env (1.0.5)
google-cloud-env (1.2.0)
faraday (~> 0.11)
google-cloud-storage (1.16.0)
digest-crc (~> 0.4)
@@ -143,7 +143,7 @@ GEM
mime-types (3.2.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2019.0331)
mini_magick (4.5.1)
mini_magick (4.9.5)
minitest (5.11.3)
molinillo (0.6.6)
multi_json (1.13.1)
@@ -153,7 +153,7 @@ GEM
nap (1.1.0)
naturally (2.2.0)
netrc (0.11.0)
os (1.0.0)
os (1.0.1)
plist (3.5.0)
public_suffix (2.0.5)
representable (3.0.4)
@@ -163,7 +163,7 @@ GEM
retriable (3.1.2)
rouge (2.0.7)
ruby-macho (1.4.0)
rubyzip (1.2.2)
rubyzip (1.2.3)
security (0.1.3)
signet (0.11.0)
addressable (~> 2.3)
@@ -178,19 +178,19 @@ GEM
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thread_safe (0.3.6)
tty-cursor (0.6.1)
tty-screen (0.6.5)
tty-spinner (0.9.0)
tty-cursor (~> 0.6.0)
tty-cursor (0.7.0)
tty-screen (0.7.0)
tty-spinner (0.9.1)
tty-cursor (~> 0.7)
tzinfo (1.2.5)
thread_safe (~> 0.1)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.6)
unicode-display_width (1.5.0)
unicode-display_width (1.6.0)
word_wrap (1.0.0)
xcodeproj (1.8.2)
xcodeproj (1.11.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
@@ -209,4 +209,4 @@ DEPENDENCIES
fastlane
BUNDLED WITH
1.16.6
2.0.1
+40 -3
View File
@@ -50,6 +50,7 @@ Enjoy it! 🙂
* [Custom colors](#-custom-colors)
* [Appearance](#-appearance)
* [Custom animations](#-custom-animations)
* [Transitions](#-transitions)
* [Hierarchy](#-hierarchy)
* [Debug](#-debug)
* [Documentation](#-documentation)
@@ -99,7 +100,7 @@ Once you have your Swift package set up, adding `SkeletonView` as a dependency i
```swift
dependencies: [
.package(url: "https://github.com/Juanpe/SkeletonView.git", from: "1.7")
.package(url: "https://github.com/Juanpe/SkeletonView.git", from: "1.7.0")
]
```
@@ -390,6 +391,42 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
Exist another way to create sliding animations, just using this shortcut:
>>```let animation = GradientDirection.leftToRight.slidingAnimation()```
### 🏄 Transitions
```SkeletonView``` has build-in transitions to **show** or **hide** the skeletons in a *smoother* way 🤙
To use the transition, simply add the ```transition``` parameter to your ```showSkeleton()``` or ```hideSkeleton()``` function with the transition time, like this:
```swift
view.showSkeleton(transition: .crossDissolve(0.25)) //Show skeleton cross dissolve transition with 0.25 seconds fade time
view.hideSkeleton(transition: .crossDissolve(0.25)) //Hide skeleton cross dissolve transition with 0.25 seconds fade time
```
**Preview**
<table>
<tr>
<td width="50%">
<center>None</center>
</td>
<td width="50%">
<center>Cross dissolve</center>
</td>
</tr>
<tr>
<td width="50%">
<img src="Assets/skeleton_transition_nofade.gif"></img>
</td>
<td width="50%">
<img src="Assets/skeleton_transition_fade.gif"></img>
</td>
</tr>
</table>
### 👨‍👧‍👦 Hierarchy
Since ```SkeletonView``` is recursive, and we want skeleton to be very efficient, we want to stop recursion as soon as possible. For this reason, you must set the container view as `Skeletonable`, because Skeleton will stop looking for `skeletonable` subviews as soon as a view is not Skeletonable, breaking then the recursion.
@@ -439,7 +476,7 @@ Coming soon...😅
* iOS 9.0+
* tvOS 9.0+
* Swift 4.2
* Swift 5
## 📬 Next steps
@@ -451,8 +488,8 @@ Coming soon...😅
* [x] Add recovery state
* [x] Custom default appearance
* [x] Debug mode
* [x] Add animations when it shows/hides the skeletons
* [ ] Custom collections compatible
* [ ] Add animations when it shows/hides the skeletons
* [ ] MacOS and WatchOS compatible
## ❤️ Contributing
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SkeletonView"
s.version = "1.7"
s.version = "1.8"
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.
+30 -16
View File
@@ -17,7 +17,6 @@
17DD0E0F207FB28C00C56334 /* CALayer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F622421FAC81FD007C062A /* CALayer+Extensions.swift */; };
17DD0E10207FB28C00C56334 /* UIColor+Skeleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F622401FAC6E31007C062A /* UIColor+Skeleton.swift */; };
17DD0E11207FB28C00C56334 /* UIView+Frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */; };
17DD0E12207FB28C00C56334 /* UIView+IBInspectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F899CF1FAA6A4D002E8FDA /* UIView+IBInspectable.swift */; };
17DD0E13207FB28C00C56334 /* UIView+UIApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift */; };
17DD0E14207FB28F00C56334 /* SkeletonAnimationBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */; };
17DD0E15207FB28F00C56334 /* SkeletonAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E2F1FB0EC9D00EE67C5 /* SkeletonAppearance.swift */; };
@@ -29,7 +28,8 @@
17DD0E1D207FB32100C56334 /* ContainsMultilineText.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E3A1FB123C100EE67C5 /* ContainsMultilineText.swift */; };
17DD0E1E207FB32100C56334 /* PrepareForSkeletonProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F56B94451FAE20AF0095662F /* PrepareForSkeletonProtocol.swift */; };
17DD0E1F207FB32100C56334 /* RecursiveProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E311FB0F42F00EE67C5 /* RecursiveProtocol.swift */; };
3B83EE4820C41488005178A4 /* UIView+IBInspectable.swift in Headers */ = {isa = PBXBuildFile; fileRef = 3B83EE4620C41488005178A4 /* UIView+IBInspectable.swift */; settings = {ATTRIBUTES = (Public, ); }; };
1E6C67A2230E76CC0019D87B /* SkeletonTransitionStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4CE587C22EEE65200333067 /* SkeletonTransitionStyle.swift */; };
1E6C67A3230E76CE0019D87B /* UIView+Transitions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4CE587B22EEE63100333067 /* UIView+Transitions.swift */; };
42ABD063210B548200BEEFF4 /* SkeletonView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* SkeletonView.framework */; };
42ABD069210B548200BEEFF4 /* SkeletonView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* SkeletonView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
42ABD078210B54E200BEEFF4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42ABD070210B54E100BEEFF4 /* AppDelegate.swift */; };
@@ -46,7 +46,6 @@
872D5A5D21C24EDD0037D763 /* UILabel+Multiline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872D5A5B21C24EDD0037D763 /* UILabel+Multiline.swift */; };
872D5A5F21C24F8E0037D763 /* UITextView+Multiline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872D5A5E21C24F8E0037D763 /* UITextView+Multiline.swift */; };
872D5A6021C24F8E0037D763 /* UITextView+Multiline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872D5A5E21C24F8E0037D763 /* UITextView+Multiline.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, ); }; };
877EFA4521BEE9D80031FC00 /* SkeletonLayerBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877EFA4421BEE9D80031FC00 /* SkeletonLayerBuilder.swift */; };
877EFA4621BEE9D80031FC00 /* SkeletonLayerBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877EFA4421BEE9D80031FC00 /* SkeletonLayerBuilder.swift */; };
@@ -57,6 +56,8 @@
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 */; };
E4CE587D22EEE65200333067 /* SkeletonTransitionStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4CE587C22EEE65200333067 /* SkeletonTransitionStyle.swift */; };
E4CE588B22EEF70D00333067 /* UIView+Transitions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4CE587B22EEE63100333067 /* UIView+Transitions.swift */; };
F51DE1091FBF70A70037919A /* SkeletonAnimationBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */; };
F51DF871206E91B300D23301 /* SkeletonReusableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F51DF870206E91B300D23301 /* SkeletonReusableCell.swift */; };
F51DF873206E91FB00D23301 /* GenericCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F51DF872206E91FB00D23301 /* GenericCollectionView.swift */; };
@@ -77,6 +78,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 */; };
F5804772230ECD0000066D02 /* UIView+IBInspectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5804771230ECD0000066D02 /* UIView+IBInspectable.swift */; };
F5804773230ECD0000066D02 /* UIView+IBInspectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5804771230ECD0000066D02 /* UIView+IBInspectable.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 */; };
F58A6E6B20A8C54100612494 /* RecoverableViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F58A6E6A20A8C54100612494 /* RecoverableViewState.swift */; };
@@ -90,7 +93,6 @@
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 */; };
F5F899D01FAA6A4D002E8FDA /* UIView+IBInspectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F899CF1FAA6A4D002E8FDA /* UIView+IBInspectable.swift */; };
F5F899D21FAB9630002E8FDA /* AssociationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F899D11FAB9630002E8FDA /* AssociationPolicy.swift */; };
F5F899E91FAB9D2B002E8FDA /* SkeletonLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F899E81FAB9D2B002E8FDA /* SkeletonLayer.swift */; };
F5F899EB1FAB9DA3002E8FDA /* SkeletonCollectionDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F899EA1FAB9DA3002E8FDA /* SkeletonCollectionDataSource.swift */; };
@@ -148,7 +150,6 @@
17DD0E00207FB27400C56334 /* SkeletonView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SkeletonView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
17DD0E1A207FB2C200C56334 /* SkeletonView-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SkeletonView-tvOS.plist"; sourceTree = "<group>"; };
17DD0E1B207FB2C200C56334 /* SkeletonView-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SkeletonView-iOS.plist"; sourceTree = "<group>"; };
3B83EE4620C41488005178A4 /* UIView+IBInspectable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "UIView+IBInspectable.swift"; path = "Sources/Extensions/UIView+IBInspectable.swift"; sourceTree = "<group>"; };
42ABD06D210B548200BEEFF4 /* SkeletonViewExampleUICollectionView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SkeletonViewExampleUICollectionView.app; sourceTree = BUILT_PRODUCTS_DIR; };
42ABD070210B54E100BEEFF4 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
42ABD071210B54E100BEEFF4 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
@@ -167,6 +168,8 @@
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>"; };
E4CE587B22EEE63100333067 /* UIView+Transitions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Transitions.swift"; sourceTree = "<group>"; };
E4CE587C22EEE65200333067 /* SkeletonTransitionStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonTransitionStyle.swift; sourceTree = "<group>"; };
F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonAnimationBuilder.swift; sourceTree = "<group>"; };
F51DF870206E91B300D23301 /* SkeletonReusableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonReusableCell.swift; sourceTree = "<group>"; };
F51DF872206E91FB00D23301 /* GenericCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericCollectionView.swift; sourceTree = "<group>"; };
@@ -182,6 +185,7 @@
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>"; };
F5804771230ECD0000066D02 /* UIView+IBInspectable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+IBInspectable.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>"; };
F58A6E6A20A8C54100612494 /* RecoverableViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoverableViewState.swift; sourceTree = "<group>"; };
@@ -191,7 +195,6 @@
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>"; };
F5F899CF1FAA6A4D002E8FDA /* UIView+IBInspectable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+IBInspectable.swift"; sourceTree = "<group>"; };
F5F899D11FAB9630002E8FDA /* AssociationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssociationPolicy.swift; sourceTree = "<group>"; };
F5F899E81FAB9D2B002E8FDA /* SkeletonLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonLayer.swift; sourceTree = "<group>"; };
F5F899EA1FAB9DA3002E8FDA /* SkeletonCollectionDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonCollectionDataSource.swift; sourceTree = "<group>"; };
@@ -242,7 +245,6 @@
52D6D9721BEFF229002C0205 = {
isa = PBXGroup;
children = (
3B83EE4620C41488005178A4 /* UIView+IBInspectable.swift */,
F5F899F31FABA607002E8FDA /* Example */,
8933C7811EB5B7E0000D00A4 /* Sources */,
52D6D99C1BEFF38C002C0205 /* Configs */,
@@ -336,6 +338,7 @@
8933C7811EB5B7E0000D00A4 /* Sources */ = {
isa = PBXGroup;
children = (
E4CE587A22EEE62300333067 /* Transitions */,
872D5A5A21C24E7C0037D763 /* Multilines */,
877EFA4321BEE9C40031FC00 /* Builders */,
8785E39F211C9C7C00CC9DFD /* Debug */,
@@ -364,6 +367,15 @@
name = Frameworks;
sourceTree = "<group>";
};
E4CE587A22EEE62300333067 /* Transitions */ = {
isa = PBXGroup;
children = (
E4CE587B22EEE63100333067 /* UIView+Transitions.swift */,
E4CE587C22EEE65200333067 /* SkeletonTransitionStyle.swift */,
);
path = Transitions;
sourceTree = "<group>";
};
F51DF874206E94D300D23301 /* CollectionViews */ = {
isa = PBXGroup;
children = (
@@ -409,12 +421,12 @@
isa = PBXGroup;
children = (
F5F622421FAC81FD007C062A /* CALayer+Extensions.swift */,
F5F622401FAC6E31007C062A /* UIColor+Skeleton.swift */,
F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */,
F5F899CF1FAA6A4D002E8FDA /* UIView+IBInspectable.swift */,
872D5A5521C177E20037D763 /* UIView+Extension.swift */,
F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift */,
F5A5E8B3211DCE7000FD20D0 /* Int+Whitespaces.swift */,
F5F622401FAC6E31007C062A /* UIColor+Skeleton.swift */,
872D5A5521C177E20037D763 /* UIView+Extension.swift */,
F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */,
F5804771230ECD0000066D02 /* UIView+IBInspectable.swift */,
F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift */,
);
path = Extensions;
sourceTree = "<group>";
@@ -470,7 +482,6 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
8748240D20C6A88A00E92179 /* UIView+IBInspectable.swift in Headers */,
8748240E20C6A88E00E92179 /* ContainsMultilineText.swift in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -479,7 +490,6 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
3B83EE4820C41488005178A4 /* UIView+IBInspectable.swift in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -662,6 +672,7 @@
17DD0E08207FB28900C56334 /* CollectionSkeletonProtocol.swift in Sources */,
F58A6E6C20A8C54100612494 /* RecoverableViewState.swift in Sources */,
17DD0E0B207FB28900C56334 /* SkeletonTableViewProtocols.swift in Sources */,
1E6C67A2230E76CC0019D87B /* SkeletonTransitionStyle.swift in Sources */,
17DD0E0D207FB28900C56334 /* UITableView+CollectionSkeleton.swift in Sources */,
17DD0E0E207FB28900C56334 /* UIView+CollectionSkeleton.swift in Sources */,
877EFA4921BEED760031FC00 /* SkeletonMultilineLayerBuilder.swift in Sources */,
@@ -671,9 +682,9 @@
17DD0E19207FB28F00C56334 /* SkeletonFlow.swift in Sources */,
17DD0E09207FB28900C56334 /* SkeletonCollectionDataSource.swift in Sources */,
17DD0E0C207FB28900C56334 /* UICollectionView+CollectionSkeleton.swift in Sources */,
F5804773230ECD0000066D02 /* UIView+IBInspectable.swift in Sources */,
17DD0E13207FB28C00C56334 /* UIView+UIApplicationDelegate.swift in Sources */,
F5D3FB0C209DCAA300003FCF /* SubviewsSkeletonables.swift in Sources */,
17DD0E12207FB28C00C56334 /* UIView+IBInspectable.swift in Sources */,
17DD0E14207FB28F00C56334 /* SkeletonAnimationBuilder.swift in Sources */,
17DD0E11207FB28C00C56334 /* UIView+Frame.swift in Sources */,
17DD0E15207FB28F00C56334 /* SkeletonAppearance.swift in Sources */,
@@ -688,6 +699,7 @@
17DD0E1D207FB32100C56334 /* ContainsMultilineText.swift in Sources */,
17DD0E0F207FB28C00C56334 /* CALayer+Extensions.swift in Sources */,
17DD0E16207FB28F00C56334 /* SkeletonGradient.swift in Sources */,
1E6C67A3230E76CE0019D87B /* UIView+Transitions.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -706,8 +718,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E4CE588B22EEF70D00333067 /* UIView+Transitions.swift in Sources */,
872D5A5621C177E20037D763 /* UIView+Extension.swift in Sources */,
F5F899D01FAA6A4D002E8FDA /* UIView+IBInspectable.swift in Sources */,
872D5A5C21C24EDD0037D763 /* UILabel+Multiline.swift in Sources */,
F54CF5E42024CEB000330B0D /* UIView+CollectionSkeleton.swift in Sources */,
F5307E371FB1076E00EE67C5 /* SkeletonTableViewProtocols.swift in Sources */,
@@ -719,12 +731,14 @@
F5307E321FB0F42F00EE67C5 /* RecursiveProtocol.swift in Sources */,
F5F622431FAC81FD007C062A /* CALayer+Extensions.swift in Sources */,
877EFA4821BEED760031FC00 /* SkeletonMultilineLayerBuilder.swift in Sources */,
E4CE587D22EEE65200333067 /* SkeletonTransitionStyle.swift in Sources */,
F5F899ED1FAB9F04002E8FDA /* CollectionSkeletonProtocol.swift in Sources */,
F58A6E6E20A8C66300612494 /* Recoverable.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 */,
F5804772230ECD0000066D02 /* UIView+IBInspectable.swift in Sources */,
F587FB84202CBFC8002DB5FE /* SkeletonFlow.swift in Sources */,
F5D3FB0B209DCAA300003FCF /* SubviewsSkeletonables.swift in Sources */,
F5F899D21FAB9630002E8FDA /* AssociationPolicy.swift in Sources */,
@@ -17,7 +17,6 @@ public enum SkeletonAppearance {
// codebeat:disable[TOO_MANY_IVARS]
class SkeletonViewAppearance: Appearance {
static var shared = SkeletonViewAppearance()
var tintColor: UIColor = .clouds
+11 -12
View File
@@ -5,7 +5,6 @@ import UIKit
/// Object that facilitates the creation of skeleton layers,
/// based on the builder pattern
class SkeletonLayerBuilder {
var skeletonType: SkeletonType?
var colors: [UIColor] = []
var holder: UIView?
@@ -27,15 +26,15 @@ class SkeletonLayerBuilder {
func setHolder(_ holder: UIView) -> SkeletonLayerBuilder {
self.holder = holder
return self
}
func build() -> SkeletonLayer? {
guard let type = skeletonType,
let holder = holder
else { return nil }
return SkeletonLayer(withType: type,
usingColors: colors,
andSkeletonHolder: holder)
}
}
func build() -> SkeletonLayer? {
guard let type = skeletonType,
let holder = holder
else { return nil }
return SkeletonLayer(type: type,
colors: colors,
skeletonHolder: holder)
}
}
@@ -5,7 +5,6 @@ import UIKit
/// Object that facilitates the creation of skeleton layers for multiline
/// elements, based on the builder pattern
class SkeletonMultilineLayerBuilder {
var skeletonType: SkeletonType?
var index: Int?
var width: CGFloat?
@@ -17,7 +17,6 @@ public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
}
public extension SkeletonCollectionViewDataSource {
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return skeletonView.estimatedNumberOfRows
}
@@ -9,7 +9,6 @@
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))
@@ -11,7 +11,6 @@ import UIKit
public typealias ReusableCellIdentifier = String
class SkeletonCollectionDataSource: NSObject {
weak var originalTableViewDataSource: SkeletonTableViewDataSource?
weak var originalCollectionViewDataSource: SkeletonCollectionViewDataSource?
var rowHeight: CGFloat = 0.0
@@ -26,13 +25,12 @@ class SkeletonCollectionDataSource: NSObject {
// MARK: - UITableViewDataSource
extension SkeletonCollectionDataSource: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return originalTableViewDataSource?.numSections(in:tableView) ?? 0
return originalTableViewDataSource?.numSections(in: tableView) ?? 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return originalTableViewDataSource?.collectionSkeletonView(tableView, numberOfRowsInSection:section) ?? 0
return originalTableViewDataSource?.collectionSkeletonView(tableView, numberOfRowsInSection: section) ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
@@ -45,7 +43,6 @@ extension SkeletonCollectionDataSource: UITableViewDataSource {
// MARK: - UICollectionViewDataSource
extension SkeletonCollectionDataSource: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return originalCollectionViewDataSource?.numSections(in: collectionView) ?? 0
}
@@ -9,7 +9,6 @@
import UIKit
class SkeletonCollectionDelegate: NSObject {
weak var originalTableViewDelegate: SkeletonTableViewDelegate?
weak var originalCollectionViewDelegate: SkeletonCollectionViewDelegate?
@@ -15,7 +15,6 @@ public protocol SkeletonTableViewDataSource: UITableViewDataSource {
}
public extension SkeletonTableViewDataSource {
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int {
return skeletonView.estimatedNumberOfRows
}
@@ -30,5 +29,4 @@ public extension SkeletonTableViewDataSource {
}
}
public protocol SkeletonTableViewDelegate: UITableViewDelegate {
}
public protocol SkeletonTableViewDelegate: UITableViewDelegate { }
@@ -9,7 +9,6 @@
import UIKit
extension UITableView: CollectionSkeleton {
var estimatedNumberOfRows: Int {
return Int(ceil(frame.height/rowHeight))
}
-1
View File
@@ -25,7 +25,6 @@ func skeletonLog(_ message: String) {
}
extension UIView {
public var skeletonDescription: String {
var description = "<\(type(of: self)): \(Unmanaged.passUnretained(self).toOpaque())"
let subSkeletons = subviewsSkeletonables
+15 -2
View File
@@ -31,7 +31,6 @@ extension CAGradientLayer {
// MARK: Skeleton sublayers
extension CALayer {
static let skeletonSubLayersName = "SkeletonSubLayersName"
var skeletonSublayers: [CALayer] {
@@ -93,7 +92,6 @@ extension CALayer {
// MARK: Animations
public extension CALayer {
var pulse: CAAnimation {
let pulseAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.backgroundColor))
pulseAnimation.fromValue = backgroundColor
@@ -139,3 +137,18 @@ public extension CALayer {
}
}
}
extension CALayer {
func setOpacity(from: Int, to: Int, duration: TimeInterval, completion: (() -> Void)?) {
CATransaction.begin()
let animation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))
animation.fromValue = from
animation.toValue = to
animation.duration = duration
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
// layer.contentLayer.opacity = 1
CATransaction.setCompletionBlock(completion)
add(animation, forKey: "setOpacityAnimation")
CATransaction.commit()
}
}
-1
View File
@@ -3,7 +3,6 @@
import Foundation
extension Int {
var whitespace: String {
return whitespaces
}
@@ -4,7 +4,6 @@ import UIKit
// codebeat:disable[TOO_MANY_IVARS]
extension UIColor {
convenience init(_ hex: UInt) {
self.init(
red: CGFloat((hex & 0xFF0000) >> 16) / 255.0,
+2 -1
View File
@@ -10,12 +10,13 @@ enum ViewAssociatedKeys {
static var flowDelegate = "flowDelegate"
static var isSkeletonAnimated = "isSkeletonAnimated"
static var viewState = "viewState"
static var labelViewState = "labelViewState"
static var imageViewState = "imageViewState"
static var currentSkeletonConfig = "currentSkeletonConfig"
}
// codebeat:enable[TOO_MANY_IVARS]
extension UIView {
enum Status {
case on
case off
-1
View File
@@ -10,7 +10,6 @@ import UIKit
// MARK: Frame
extension UIView {
var maxBoundsEstimated: CGRect {
if let parentStackView = (superview as? UIStackView) {
var origin: CGPoint = .zero
@@ -3,7 +3,6 @@
import UIKit
public extension UIView {
@IBInspectable
var isSkeletonable: Bool {
get { return skeletonable }
@@ -9,7 +9,6 @@
import UIKit
extension UIView {
enum Constants {
static let becomeActiveNotification = UIApplication.didBecomeActiveNotification
static let enterForegroundNotification = UIApplication.didEnterBackgroundNotification
-1
View File
@@ -20,7 +20,6 @@ protocol AssociatedObjects: class { }
// transparent wrappers
extension AssociatedObjects {
/// wrapper around `objc_getAssociatedObject`
func ao_get(pkey: UnsafeRawPointer) -> Any? {
return objc_getAssociatedObject(self, pkey)
+24 -11
View File
@@ -8,26 +8,39 @@
import UIKit
protocol PrepareForSkeleton {
func prepareViewForSkeleton()
extension UIView {
@objc func prepareViewForSkeleton() {
startTransition { [weak self] in
self?.backgroundColor = .clear
}
}
}
extension UILabel: PrepareForSkeleton {
func prepareViewForSkeleton() {
text = " "
extension UILabel {
override func prepareViewForSkeleton() {
backgroundColor = .clear
resignFirstResponder()
startTransition { [weak self] in
self?.textColor = .clear
}
}
}
extension UITextView: PrepareForSkeleton {
func prepareViewForSkeleton() {
text = " "
extension UITextView {
override func prepareViewForSkeleton() {
backgroundColor = .clear
resignFirstResponder()
startTransition { [weak self] in
self?.textColor = .clear
}
}
}
extension UIImageView: PrepareForSkeleton {
func prepareViewForSkeleton() {
image = nil
extension UIImageView {
override func prepareViewForSkeleton() {
backgroundColor = .clear
startTransition { [weak self] in
self?.image = nil
}
}
}
@@ -3,7 +3,6 @@
import UIKit
public extension UITextView {
@IBInspectable
var lastLineFillPercent: Int {
get { return lastLineFillingPercent }
+38 -15
View File
@@ -9,13 +9,11 @@
import UIKit
protocol Recoverable {
var viewState: RecoverableViewState? { get set }
func saveViewState()
func recoverViewState(forced: Bool)
}
extension UIView: Recoverable {
var viewState: RecoverableViewState? {
get { return ao_get(pkey: &ViewAssociatedKeys.viewState) as? RecoverableViewState }
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.viewState) }
@@ -28,47 +26,72 @@ extension UIView: Recoverable {
@objc func recoverViewState(forced: Bool) {
guard let safeViewState = viewState else { return }
layer.cornerRadius = safeViewState.cornerRadius
layer.masksToBounds = safeViewState.clipToBounds
if safeViewState.backgroundColor != backgroundColor || forced {
backgroundColor = safeViewState.backgroundColor
startTransition { [weak self] in
self?.layer.cornerRadius = safeViewState.cornerRadius
self?.layer.masksToBounds = safeViewState.clipToBounds
if safeViewState.backgroundColor != self?.backgroundColor || forced {
self?.backgroundColor = safeViewState.backgroundColor
}
}
}
}
extension UILabel {
extension UILabel{
var labelState: RecoverableTextViewState? {
get { return ao_get(pkey: &ViewAssociatedKeys.labelViewState) as? RecoverableTextViewState }
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.labelViewState) }
}
override func saveViewState() {
super.saveViewState()
viewState?.text = text
labelState = RecoverableTextViewState(view: self)
}
override func recoverViewState(forced: Bool) {
super.recoverViewState(forced: forced)
text = text == " " || forced ? viewState?.text : text
startTransition { [weak self] in
self?.textColor = self?.labelState?.textColor
self?.text = self?.labelState?.text
}
}
}
extension UITextView {
extension UITextView{
var textState: RecoverableTextViewState? {
get { return ao_get(pkey: &ViewAssociatedKeys.labelViewState) as? RecoverableTextViewState }
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.labelViewState) }
}
override func saveViewState() {
super.saveViewState()
viewState?.text = text
textState = RecoverableTextViewState(view: self)
}
override func recoverViewState(forced: Bool) {
super.recoverViewState(forced: forced)
text = text == " " || forced ? viewState?.text : text
startTransition { [weak self] in
self?.textColor = self?.textState?.textColor
self?.text = self?.textState?.text
}
}
}
extension UIImageView {
var imageState: RecoverableImageViewState? {
get { return ao_get(pkey: &ViewAssociatedKeys.imageViewState) as? RecoverableImageViewState }
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.imageViewState) }
}
override func saveViewState() {
super.saveViewState()
viewState?.image = image
imageState = RecoverableImageViewState(view: self)
}
override func recoverViewState(forced: Bool) {
super.recoverViewState(forced: forced)
image = image == nil || forced ? viewState?.image : image
startTransition { [weak self] in
self?.image = self?.image == nil || forced ? self?.imageState?.image : self?.image
}
}
}
+23 -8
View File
@@ -13,17 +13,32 @@ struct RecoverableViewState {
var cornerRadius: CGFloat
var clipToBounds: Bool
// UI text
var text: String?
// UI image
var image: UIImage?
}
extension RecoverableViewState {
init(view: UIView) {
self.backgroundColor = view.backgroundColor
self.clipToBounds = view.layer.masksToBounds
self.cornerRadius = view.layer.cornerRadius
}
}
struct RecoverableTextViewState {
var text: String?
var textColor: UIColor?
init(view: UILabel) {
self.textColor = view.textColor
self.text = view.text
}
init(view: UITextView) {
self.textColor = view.textColor
self.text = view.text
}
}
struct RecoverableImageViewState {
var image: UIImage?
init(view: UIImageView) {
self.image = view.image
}
}
+1 -3
View File
@@ -60,9 +60,7 @@ public enum GradientDirection {
}
public class SkeletonAnimationBuilder {
public init() {
}
public init() { }
public func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation {
return { layer in
+16 -7
View File
@@ -6,26 +6,35 @@ import UIKit
struct SkeletonConfig {
/// Type of skeleton layer
let type: SkeletonType
/// Colors used in skeleton layer
let colors: [UIColor]
/// If type is gradient, which gradient direction
let gradientDirection: GradientDirection?
/// Specify if skeleton is animated or not
let animated: Bool
/// Used to execute a custom animation
let animation: SkeletonLayerAnimation?
/// Transition style
var transition: SkeletonTransitionStyle
init(
type: SkeletonType,
colors: [UIColor],
gradientDirection: GradientDirection? = nil,
animated: Bool = false,
animation: SkeletonLayerAnimation? = nil
) {
type: SkeletonType,
colors: [UIColor],
gradientDirection: GradientDirection? = nil,
animated: Bool = false,
animation: SkeletonLayerAnimation? = nil,
transition: SkeletonTransitionStyle = .none
) {
self.type = type
self.colors = colors
self.gradientDirection = gradientDirection
self.animated = animated
self.animation = animation
self.transition = transition
}
}
+1 -2
View File
@@ -9,8 +9,7 @@
import UIKit
public struct SkeletonGradient {
private var gradientColors: [UIColor]
private let gradientColors: [UIColor]
public var colors: [UIColor] {
return gradientColors
Regular → Executable
+14 -8
View File
@@ -34,7 +34,6 @@ public enum SkeletonType {
}
struct SkeletonLayer {
private var maskLayer: CALayer
private weak var holder: UIView?
@@ -46,7 +45,7 @@ struct SkeletonLayer {
return maskLayer
}
init(withType type: SkeletonType, usingColors colors: [UIColor], andSkeletonHolder holder: UIView) {
init(type: SkeletonType, colors: [UIColor], skeletonHolder holder: UIView) {
self.holder = holder
self.maskLayer = type.layer
self.maskLayer.anchorPoint = .zero
@@ -57,18 +56,26 @@ struct SkeletonLayer {
func update(usingColors colors: [UIColor]) {
layoutIfNeeded()
self.maskLayer.tint(withColors: colors)
maskLayer.tint(withColors: colors)
}
func layoutIfNeeded() {
if let bounds = self.holder?.maxBoundsEstimated {
self.maskLayer.bounds = bounds
if let bounds = holder?.maxBoundsEstimated {
maskLayer.bounds = bounds
}
updateMultilinesIfNeeded()
}
func removeLayer() {
maskLayer.removeFromSuperlayer()
func removeLayer(transition: SkeletonTransitionStyle, completion: (() -> Void)? = nil) {
switch transition {
case .none:
maskLayer.removeFromSuperlayer()
case .crossDissolve(let duration):
maskLayer.setOpacity(from: 1, to: 0, duration: duration) {
self.maskLayer.removeFromSuperlayer()
completion?()
}
}
}
func addMultilinesIfNeeded() {
@@ -83,7 +90,6 @@ struct SkeletonLayer {
}
extension SkeletonLayer {
func start(_ anim: SkeletonLayerAnimation? = nil) {
let animation = anim ?? type.layerAnimation
contentLayer.playAnimation(animation, key: "skeletonAnimation")
Regular → Executable
+36 -28
View File
@@ -3,44 +3,43 @@
import UIKit
public extension UIView {
func showSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor) {
let config: SkeletonConfig = SkeletonConfig(type: .solid, colors: [color])
func showSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor, transition: SkeletonTransitionStyle = .none) {
let config = SkeletonConfig(type: .solid, colors: [color], transition: transition)
showSkeleton(skeletonConfig: config)
}
func showGradientSkeleton(usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient) {
let config: SkeletonConfig = SkeletonConfig(type: .gradient, colors: gradient.colors)
func showGradientSkeleton(usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient, transition: SkeletonTransitionStyle = .none) {
let config = SkeletonConfig(type: .gradient, colors: gradient.colors, transition: transition)
showSkeleton(skeletonConfig: config)
}
func showAnimatedSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor, animation: SkeletonLayerAnimation? = nil) {
let config: SkeletonConfig = SkeletonConfig(type: .solid, colors: [color], animated: true, animation: animation)
func showAnimatedSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor, animation: SkeletonLayerAnimation? = nil, transition: SkeletonTransitionStyle = .none) {
let config = SkeletonConfig(type: .solid, colors: [color], animated: true, animation: animation, transition: transition)
showSkeleton(skeletonConfig: config)
}
func showAnimatedGradientSkeleton(usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient, animation: SkeletonLayerAnimation? = nil) {
let config: SkeletonConfig = SkeletonConfig(type: .gradient, colors: gradient.colors, animated: true, animation: animation)
func showAnimatedGradientSkeleton(usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient, animation: SkeletonLayerAnimation? = nil, transition: SkeletonTransitionStyle = .none) {
let config = SkeletonConfig(type: .gradient, colors: gradient.colors, animated: true, animation: animation, transition: transition)
showSkeleton(skeletonConfig: config)
}
func updateSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor) {
let config: SkeletonConfig = SkeletonConfig(type: .solid, colors: [color])
let config = SkeletonConfig(type: .solid, colors: [color])
updateSkeleton(skeletonConfig: config)
}
func updateGradientSkeleton(usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient) {
let config: SkeletonConfig = SkeletonConfig(type: .gradient, colors: gradient.colors)
let config = SkeletonConfig(type: .gradient, colors: gradient.colors)
updateSkeleton(skeletonConfig: config)
}
func updateAnimatedSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor, animation: SkeletonLayerAnimation? = nil) {
let config: SkeletonConfig = SkeletonConfig(type: .solid, colors: [color], animated: true, animation: animation)
let config = SkeletonConfig(type: .solid, colors: [color], animated: true, animation: animation)
updateSkeleton(skeletonConfig: config)
}
func updateAnimatedGradientSkeleton(usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient, animation: SkeletonLayerAnimation? = nil) {
let config: SkeletonConfig = SkeletonConfig(type: .gradient, colors: gradient.colors, animated: true, animation: animation)
let config = SkeletonConfig(type: .gradient, colors: gradient.colors, animated: true, animation: animation)
updateSkeleton(skeletonConfig: config)
}
@@ -50,7 +49,11 @@ public extension UIView {
recursiveLayoutSkeletonIfNeeded(root: self)
}
func hideSkeleton(reloadDataAfter reload: Bool = true) {
func hideSkeleton(reloadDataAfter reload: Bool = true, transition: SkeletonTransitionStyle = .none) {
if var config = currentSkeletonConfig {
config.transition = transition
updateSkeleton(skeletonConfig: config)
}
flowDelegate?.willBeginHidingSkeletons(withRootView: self)
recursiveHideSkeleton(reloadDataAfter: reload, root: self)
}
@@ -97,11 +100,11 @@ extension UIView {
}
fileprivate func showSkeletonIfNotActive(skeletonConfig config: SkeletonConfig) {
guard !self.isSkeletonActive else { return }
self.isUserInteractionEnabled = false
self.saveViewState()
(self as? PrepareForSkeleton)?.prepareViewForSkeleton()
self.addSkeletonLayer(skeletonConfig: config)
guard !isSkeletonActive else { return }
isUserInteractionEnabled = false
saveViewState()
prepareViewForSkeleton()
addSkeletonLayer(skeletonConfig: config)
}
func updateSkeleton(skeletonConfig config: SkeletonConfig) {
@@ -183,7 +186,6 @@ extension UIView {
}
extension UIView {
func addSkeletonLayer(skeletonConfig config: SkeletonConfig) {
guard let skeletonLayer = SkeletonLayerBuilder()
.setSkeletonType(config.type)
@@ -193,8 +195,13 @@ extension UIView {
else { return }
self.skeletonLayer = skeletonLayer
layer.insertSublayer(skeletonLayer.contentLayer, at: UInt32.max)
if config.animated { skeletonLayer.start(config.animation) }
layer.insertSublayer(skeletonLayer,
at: UInt32.max,
transition: config.transition) {
if config.animated {
skeletonLayer.start(config.animation)
}
}
status = .on
}
@@ -212,12 +219,13 @@ extension UIView {
func removeSkeletonLayer() {
guard isSkeletonActive,
let skeletonLayer = skeletonLayer else { return }
let skeletonLayer = skeletonLayer,
let transitionStyle = currentSkeletonConfig?.transition else { return }
skeletonLayer.stopAnimation()
skeletonLayer.removeLayer()
self.skeletonLayer = nil
status = .off
currentSkeletonConfig = nil
skeletonLayer.removeLayer(transition: transitionStyle) {
self.skeletonLayer = nil
self.status = .off
self.currentSkeletonConfig = nil
}
}
}
-5
View File
@@ -13,35 +13,30 @@ extension UIView {
}
extension UITableView {
override var subviewsToSkeleton: [UIView] {
return visibleCells
}
}
extension UITableViewCell {
override var subviewsToSkeleton: [UIView] {
return contentView.subviews
}
}
extension UICollectionView {
override var subviewsToSkeleton: [UIView] {
return subviews
}
}
extension UICollectionViewCell {
override var subviewsToSkeleton: [UIView] {
return contentView.subviews
}
}
extension UIStackView {
override var subviewsToSkeleton: [UIView] {
return arrangedSubviews
}
@@ -0,0 +1,8 @@
// Copyright © 2019 SkeletonView. All rights reserved.
import UIKit
public enum SkeletonTransitionStyle: Equatable {
case none
case crossDissolve(TimeInterval)
}
@@ -0,0 +1,34 @@
// Copyright © 2019 SkeletonView. All rights reserved.
import UIKit
extension CALayer {
func insertSublayer(_ layer: SkeletonLayer, at idx: UInt32, transition: SkeletonTransitionStyle, completion: (() -> Void)? = nil) {
insertSublayer(layer.contentLayer, at: idx)
switch transition {
case .none:
break
case .crossDissolve(let duration):
layer.contentLayer.setOpacity(from: 0, to: 1, duration: duration, completion: completion)
}
}
}
extension UIView {
func startTransition(transitionBlock: @escaping () -> Void) {
guard let transitionStyle = currentSkeletonConfig?.transition,
transitionStyle != .none
else {
transitionBlock()
return
}
if case let .crossDissolve(duration) = transitionStyle {
UIView.transition(with: self,
duration: duration,
options: .transitionCrossDissolve,
animations: transitionBlock,
completion: nil)
}
}
}