Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 36a863b557 | |||
| 3b83b85249 | |||
| afbb10d785 | |||
| 99ccd1e640 | |||
| e6834d1296 | |||
| 89cb6f4116 | |||
| b74592e6be | |||
| 5f79708f03 | |||
| a83e1a00bf | |||
| 61e98b26ad | |||
| 0ec754dfc5 | |||
| 78b4b7b31c | |||
| e3ddc4fe98 | |||
| 13485e61f7 | |||
| 8f5d409304 | |||
| bc3258b8a2 | |||
| fd4683f555 | |||
| 97ebbcc917 | |||
| a02922dba6 | |||
| 4ac1abe50e | |||
| 25e313850e | |||
| 88914f7816 | |||
| 14ab00d13a | |||
| 90b993a16b | |||
| 413867718e | |||
| e43b3f3750 | |||
| b9b368b7e8 | |||
| fc22d58f89 | |||
| 8988b22784 | |||
| 3cb1602e11 | |||
| 649672182e | |||
| 3c16416dbb | |||
| 0eff052314 |
+1
-1
@@ -1 +1 @@
|
||||
4.1
|
||||
4.2
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
language: objective-c
|
||||
osx_image: xcode9.3
|
||||
osx_image: xcode10
|
||||
script:
|
||||
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonView-iOS -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=11'
|
||||
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonView-tvOS -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV,OS=11'
|
||||
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonViewExample -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=11'
|
||||
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonView-iOS -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=12'
|
||||
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonView-tvOS -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV,OS=12'
|
||||
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonViewExample -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=12'
|
||||
after_success:
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 222 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 388 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -1,6 +1,20 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file
|
||||
|
||||
## [Debug (1.4)](https://github.com/Juanpe/SkeletonView/releases/tag/1.4)
|
||||
|
||||
### New
|
||||
|
||||
- Create `skeletonDescription` print a skeleton representation of the view.
|
||||
- Create `SKELETON_DEBUG` environment variable, in order to print the view hierarchy when the skeleton appears.
|
||||
|
||||
### Improvements
|
||||
- Add two new methods to `SkeletonFlowDelegate` protocol. Now you can know when the skeleton did show and when it did hide.
|
||||
- `Recursive` protocol
|
||||
|
||||
### Bug fixes
|
||||
- Solved issue [#86](https://github.com/Juanpe/SkeletonView/issues/86) (thanks @reececomo)
|
||||
|
||||
## [Custom defaults (1.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.3)
|
||||
|
||||
### New
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// SkeletonViewExampleUICollectionView
|
||||
//
|
||||
// Created by Andrei Hogea on 14/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
//
|
||||
// CollectionViewCell.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Andrei Hogea on 14/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SkeletonView
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
//
|
||||
// Constants.swift
|
||||
// SkeletonViewExampleUICollectionView
|
||||
//
|
||||
// Created by Andrei Hogea on 15/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
let colors = [(UIColor.turquoise,"turquoise"), (UIColor.emerald,"emerald"), (UIColor.peterRiver,"peterRiver"), (UIColor.amethyst,"amethyst"),(UIColor.wetAsphalt,"wetAsphalt"), (UIColor.nephritis,"nephritis"), (UIColor.belizeHole,"belizeHole"), (UIColor.wisteria,"wisteria"), (UIColor.midnightBlue,"midnightBlue"), (UIColor.sunFlower,"sunFlower"), (UIColor.carrot,"carrot"), (UIColor.alizarin,"alizarin"),(UIColor.clouds,"clouds"), (UIColor.concrete,"concrete"), (UIColor.flatOrange,"flatOrange"), (UIColor.pumpkin,"pumpkin"), (UIColor.pomegranate,"pomegranate"), (UIColor.silver,"silver"), (UIColor.asbestos,"asbestos")]
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="irH-dz-xqL">
|
||||
<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">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@@ -13,13 +13,60 @@
|
||||
<!--View Controller-->
|
||||
<scene sceneID="qda-qV-vJk">
|
||||
<objects>
|
||||
<viewController id="irH-dz-xqL" customClass="ViewController" customModule="SkeletonView" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController id="irH-dz-xqL" customClass="ViewController" customModule="SkeletonViewExampleUICollectionView" customModuleProvider="target" 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"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eHI-ka-8vS">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="243"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="obr-b6-dib">
|
||||
<rect key="frame" x="45" y="142" width="287" height="78"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="78" id="jx6-c1-U0j"/>
|
||||
</constraints>
|
||||
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </string>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="lastLineFillPercent">
|
||||
<integer key="value" value="40"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</textView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" 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>
|
||||
<constraint firstAttribute="height" constant="93" id="jlG-7K-wMd"/>
|
||||
<constraint firstAttribute="width" constant="93" id="xHX-Y1-dvi"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="243" id="0g6-3g-uII"/>
|
||||
<constraint firstAttribute="trailing" secondItem="obr-b6-dib" secondAttribute="trailing" constant="43" id="3ms-Wk-qcn"/>
|
||||
<constraint firstItem="obr-b6-dib" firstAttribute="centerX" secondItem="eHI-ka-8vS" secondAttribute="centerX" constant="1" id="B5s-DM-eR8"/>
|
||||
<constraint firstAttribute="height" constant="243" id="GX5-3W-tUt"/>
|
||||
<constraint firstItem="Ql9-Jy-aWM" firstAttribute="centerX" secondItem="eHI-ka-8vS" secondAttribute="centerX" id="HsA-ID-oSK"/>
|
||||
<constraint firstItem="Ql9-Jy-aWM" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="top" constant="20" id="Hxu-ae-hXQ"/>
|
||||
<constraint firstItem="obr-b6-dib" firstAttribute="leading" secondItem="eHI-ka-8vS" secondAttribute="leading" constant="45" id="eop-Gq-7mO"/>
|
||||
<constraint firstItem="obr-b6-dib" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="top" constant="142" id="inJ-75-hGX"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="36i-gK-pIa"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="HKL-L0-T2w">
|
||||
<rect key="frame" x="0.0" y="243" width="375" height="284"/>
|
||||
<rect key="frame" x="0.0" y="263" width="375" height="264"/>
|
||||
<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"/>
|
||||
@@ -86,52 +133,6 @@
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="140" id="qR5-cz-YAm"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eHI-ka-8vS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="243"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="obr-b6-dib">
|
||||
<rect key="frame" x="45" y="142" width="287" height="78"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="78" id="jx6-c1-U0j"/>
|
||||
</constraints>
|
||||
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </string>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="lastLineFillPercent">
|
||||
<integer key="value" value="40"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</textView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" 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>
|
||||
<constraint firstAttribute="height" constant="93" id="jlG-7K-wMd"/>
|
||||
<constraint firstAttribute="width" constant="93" id="xHX-Y1-dvi"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="243" id="0g6-3g-uII"/>
|
||||
<constraint firstAttribute="trailing" secondItem="obr-b6-dib" secondAttribute="trailing" constant="43" id="3ms-Wk-qcn"/>
|
||||
<constraint firstItem="obr-b6-dib" firstAttribute="centerX" secondItem="eHI-ka-8vS" secondAttribute="centerX" constant="1" id="B5s-DM-eR8"/>
|
||||
<constraint firstAttribute="height" constant="243" id="GX5-3W-tUt"/>
|
||||
<constraint firstItem="Ql9-Jy-aWM" firstAttribute="centerX" secondItem="eHI-ka-8vS" secondAttribute="centerX" id="HsA-ID-oSK"/>
|
||||
<constraint firstItem="Ql9-Jy-aWM" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="top" constant="20" id="Hxu-ae-hXQ"/>
|
||||
<constraint firstItem="obr-b6-dib" firstAttribute="leading" secondItem="eHI-ka-8vS" secondAttribute="leading" constant="45" id="eop-Gq-7mO"/>
|
||||
<constraint firstItem="obr-b6-dib" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="top" constant="142" id="inJ-75-hGX"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
@@ -141,10 +142,10 @@
|
||||
<constraint firstItem="JjA-MK-YzZ" firstAttribute="bottom" secondItem="2Gq-Y8-1TU" secondAttribute="bottom" id="AAr-ke-R7M"/>
|
||||
<constraint firstItem="JjA-MK-YzZ" firstAttribute="trailing" secondItem="2Gq-Y8-1TU" secondAttribute="trailing" id="DtS-9c-zBC"/>
|
||||
<constraint firstItem="HKL-L0-T2w" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="bottom" id="Jgf-jS-PLT"/>
|
||||
<constraint firstItem="eHI-ka-8vS" firstAttribute="top" secondItem="2Gq-Y8-1TU" secondAttribute="top" id="Ux2-GF-HLK"/>
|
||||
<constraint firstItem="JjA-MK-YzZ" firstAttribute="top" secondItem="HKL-L0-T2w" secondAttribute="bottom" id="XEd-Gf-KFI"/>
|
||||
<constraint firstItem="2Gq-Y8-1TU" firstAttribute="trailing" secondItem="HKL-L0-T2w" secondAttribute="trailing" id="bNo-98-pE4"/>
|
||||
<constraint firstItem="HKL-L0-T2w" firstAttribute="leading" secondItem="2Gq-Y8-1TU" secondAttribute="leading" id="iIq-cx-paX"/>
|
||||
<constraint firstItem="eHI-ka-8vS" firstAttribute="top" secondItem="Fso-nq-n6t" secondAttribute="top" id="tlZ-Wl-lvE"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="2Gq-Y8-1TU"/>
|
||||
</view>
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// SkeletonViewExampleUICollectionView
|
||||
//
|
||||
// Created by Andrei Hogea on 14/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SkeletonView
|
||||
|
||||
@@ -14,7 +14,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
|
||||
}
|
||||
|
||||
@@ -201,6 +201,9 @@
|
||||
<constraint firstItem="XgY-1a-UGc" firstAttribute="bottom" secondItem="6Tk-OE-BBY" secondAttribute="bottom" id="vnZ-9k-MfI"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="NO"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="BEI-dU-kr2"/>
|
||||
<connections>
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
//
|
||||
// Constants.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Renato Mendes on 28/11/2017.
|
||||
// Copyright © 2017 SkeletonView. All rights reserved.
|
||||
//
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class ViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var tableview: UITableView! {
|
||||
didSet {
|
||||
tableview.rowHeight = UITableViewAutomaticDimension
|
||||
tableview.rowHeight = UITableView.automaticDimension
|
||||
tableview.estimatedRowHeight = 120.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
🌎 Translations: [ [🇨🇳](https://github.com/Juanpe/SkeletonView/blob/master/README_zh.md) by [@WhatsXie](https://twitter.com/WhatsXie) ]
|
||||
🌎 Translations: </br>
|
||||
[🇨🇳](https://github.com/Juanpe/SkeletonView/blob/master/README_zh.md) by [@WhatsXie](https://twitter.com/WhatsXie) </br>
|
||||
[🇧🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_pt-br.md) by [@brunomunizaf](https://twitter.com/brunomuniz_af)
|
||||
|
||||
Today almost all apps have async processes, such as Api requests, long running processes, etc. And while the processes are working, usually developers place a loading view to show users that something is going on.
|
||||
|
||||
@@ -41,6 +43,7 @@ Enjoy it! 🙂
|
||||
|
||||
* [Features](#-features)
|
||||
* [Requirements](#-supported-os--sdk-versions)
|
||||
* [Guides](#-guides)
|
||||
* [Example Project](#-example)
|
||||
* [Installation](#-installation)
|
||||
* [Cocoapods](#using-cocoapods)
|
||||
@@ -52,6 +55,7 @@ Enjoy it! 🙂
|
||||
* [Appearance](#-appearance)
|
||||
* [Custom animations](#-custom-animations)
|
||||
* [Hierarchy](#-hierarchy)
|
||||
* [Debug](#-debug)
|
||||
* [Documentation](#-documentation)
|
||||
* [Next steps](#-next-steps)
|
||||
* [Contributing](#-contributing)
|
||||
@@ -76,6 +80,10 @@ Enjoy it! 🙂
|
||||
* tvOS 9.0+
|
||||
* Swift 4
|
||||
|
||||
### 🎬 Guides
|
||||
|
||||
[<img src="Assets/thumb_getting_started.png">](https://youtu.be/75kgOhWsPNA)
|
||||
|
||||
### 🔮 Example
|
||||
|
||||
To run the example project, clone the repo and run `SkeletonViewExample` target.
|
||||
@@ -280,11 +288,23 @@ Besides, ```SkeletonView``` features 20 flat colors 🤙🏼
|
||||
|
||||
Default values:
|
||||
- **tintColor**: UIColor
|
||||
- *default: .clouds*
|
||||
- **gradient**: SkeletonGradient
|
||||
- *default: SkeletonGradient(baseColor: .clouds)*
|
||||
- **multilineHeight**: CGFloat
|
||||
- *default: 15*
|
||||
- **multilineSpacing**: CGFloat
|
||||
- *default: 10*
|
||||
- **multilineLastLineFillPercent**: Int
|
||||
- **multilineCornerRadius**: Int _0_
|
||||
- *default: 70*
|
||||
- **multilineCornerRadius**: Int
|
||||
- *default: 0*
|
||||
|
||||
To get these default values you can use `SkeletonAppearance.default`. Using this property you can set the values as well:
|
||||
```Swift
|
||||
SkeletonAppearance.default.multilineHeight = 20
|
||||
SkeletonAppearance.default.tintColor = .green
|
||||
```
|
||||
|
||||
|
||||
### 🤓 Custom animations
|
||||
@@ -354,6 +374,31 @@ Because an image is worth a thousand words:
|
||||
| | 
|
||||
|
||||
|
||||
### 🔬 Debug
|
||||
|
||||
**NEW** In order to facilitate the debug tasks when something is not working fine. `SkeletonView` has some new tools.
|
||||
|
||||
First, `UIView` has available a new property with his skeleton info:
|
||||
```swift
|
||||
var skeletonDescription: String
|
||||
|
||||
```
|
||||
The skeleton representation looks like this:
|
||||
|
||||

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

|
||||
|
||||
Then, when the skeleton appears, you can see the view hierarchy in the Xcode console.
|
||||
|
||||
<details>
|
||||
<summary>Open to see an output example </summary>
|
||||
<img src="Assets/hierarchy_output.png" />
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
### 📚 Documentation
|
||||
Coming soon...😅
|
||||
@@ -367,6 +412,7 @@ Coming soon...😅
|
||||
* [x] tvOS compatible
|
||||
* [x] Add recovery state
|
||||
* [x] Custom default appearance
|
||||
* [x] Debug mode
|
||||
* [ ] Custom collections compatible
|
||||
* [ ] Add animations when it shows/hides the skeletons
|
||||
* [ ] MacOS and WatchOS compatible
|
||||
|
||||
Executable
+446
@@ -0,0 +1,446 @@
|
||||

|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/Juanpe/SkeletonView">
|
||||
<img src="https://img.shields.io/travis/Juanpe/SkeletonView.svg">
|
||||
</a>
|
||||
<a href="https://instagram.github.io/IGListKit/">
|
||||
<img src="https://img.shields.io/cocoapods/p/SkeletonView.svg" alt="Platforms">
|
||||
</a>
|
||||
<img src="https://img.shields.io/badge/Swift-4.1-orange.svg" />
|
||||
<a href="https://cocoapods.org/pods/SkeletonView">
|
||||
<img src="https://img.shields.io/cocoapods/v/SkeletonView.svg" alt="CocoaPods" />
|
||||
</a>
|
||||
<a href="https://github.com/Carthage/Carthage">
|
||||
<img src="https://img.shields.io/badge/carthage-compatible-4BC51D.svg?style=flat" alt="Carthage" />
|
||||
</a>
|
||||
<a href="https://cocoapods.org/pods/SkeletonView">
|
||||
<img src="https://img.shields.io/cocoapods/dt/SkeletonView.svg?style=flat" alt="CocoaPods downloads" />
|
||||
</a>
|
||||
<a href="https://twitter.com/JuanpeCatalan">
|
||||
<img src="https://img.shields.io/badge/contact-@JuanpeCatalan-blue.svg?style=flat" alt="Twitter: @JuanpeCatalan" />
|
||||
</a>
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=MJ4Y2D9DEX6FL&lc=ES&item_name=SkeletonView¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted">
|
||||
<img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Paypal" />
|
||||
</a>
|
||||
<a href="https://twitter.com/intent/tweet?text=Wow%20This%20library%20is%20awesome:&url=https%3A%2F%2Fgithub.com%2FJuanpe%2FSkeletonView">
|
||||
<img src="https://img.shields.io/twitter/url/https/github.com/Juanpe/SkeletonView.svg?style=social" alt="License" />
|
||||
</a>
|
||||
<a href="https://twitter.com/JuanpeCatalan">
|
||||
<img src="https://img.shields.io/twitter/follow/JuanpeCatalan.svg?style=social&label=Follow" alt="Twitter" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
🌎 Traduções: </br>
|
||||
[Original](https://github.com/Juanpe/SkeletonView) </br>
|
||||
[🇨🇳](https://github.com/Juanpe/SkeletonView/blob/master/README_zh.md) por [@WhatsXie](https://twitter.com/WhatsXie) </br>
|
||||
|
||||
Hoje, quase todos os apps têm processos assíncronos, como requisições de API, processos longos, etc. E enquanto os processos estão ocorrendo, normalmente os desenvolvedores usam uma view que mostra os usuarios que algo está ocorrendo.
|
||||
|
||||
```SkeletonView``` foi criado para essa necessidade, um jeito elegante de mostrar aos usuários que algo está acontecendo e já prepará-los para qual conteúdo será carregado.
|
||||
|
||||
Aproveite! 🙂
|
||||
|
||||
* [Features](#-features)
|
||||
* [Requerimentos](#-supported-os--sdk-versions)
|
||||
* [Projeto de exemplo](#-example)
|
||||
* [Instalação](#-installation)
|
||||
* [Cocoapods](#using-cocoapods)
|
||||
* [Carthage](#using-carthage)
|
||||
* [Como usar](#-how-to-use)
|
||||
* [Coleções](#-collections)
|
||||
* [Texto em várias linhas](#-multiline-text)
|
||||
* [Cores customizadas](#-custom-colors)
|
||||
* [Aparência](#-appearance)
|
||||
* [Animaçōes customizadas](#-custom-animations)
|
||||
* [Hierarquia](#-hierarchy)
|
||||
* [Documentação](#-documentation)
|
||||
* [Próximos passos](#-next-steps)
|
||||
* [Contribuindo](#-contributing)
|
||||
* [Menções](#-mentions)
|
||||
* [Autor](#-author)
|
||||
* [Licença](#-license)
|
||||
|
||||
|
||||
## 🌟 Features
|
||||
|
||||
- [x] Fácil de usar
|
||||
- [x] Todas as UIViews são skeletonables
|
||||
- [x] Completamente customizável
|
||||
- [x] Universal (iPhone & iPad)
|
||||
- [x] Interface Builder friendly
|
||||
- [x] Sintaxe simples em Swift
|
||||
- [x] Código leve e legível
|
||||
|
||||
### 📋 Versões do SDK e OS suportados
|
||||
|
||||
* iOS 9.0+
|
||||
* tvOS 9.0+
|
||||
* Swift 4
|
||||
|
||||
### 🔮 Exemplo
|
||||
|
||||
Para rodar o projeto de exemplo, clone o repositório e use o target `SkeletonViewExample`.
|
||||
|
||||
## 📲 Instalação
|
||||
|
||||
#### Usando [CocoaPods](https://cocoapods.org)
|
||||
|
||||
Edite seu `Podfile` e especifíque a dependência:
|
||||
|
||||
```ruby
|
||||
pod "SkeletonView"
|
||||
```
|
||||
|
||||
#### Usando [Carthage](https://github.com/carthage)
|
||||
|
||||
Edite seu `Cartfile` e especifíque a dependência:
|
||||
|
||||
```bash
|
||||
github "Juanpe/SkeletonView"
|
||||
```
|
||||
|
||||
## 🐒 Como usar
|
||||
|
||||
Apenas **3** passos necessários para usar `SkeletonView`:
|
||||
|
||||
**1.** Importe SkeletonView no lugar desejado.
|
||||
```swift
|
||||
import SkeletonView
|
||||
```
|
||||
|
||||
**2.** Agora, especifíque quais views serão `skeletonables`. Você consegue fazer isso de duas formas:
|
||||
|
||||
**Usando código:**
|
||||
```swift
|
||||
avatarImageView.isSkeletonable = true
|
||||
```
|
||||
**Usando IB/Storyboards:**
|
||||
|
||||

|
||||
|
||||
**3.** Uma vez que você setou as views, você pode mostrar o **skeleton**. Para fazê-lo, você tem **4** escolhas:
|
||||
|
||||
```swift
|
||||
(1) view.showSkeleton() // Solid
|
||||
(2) view.showGradientSkeleton() // Gradient
|
||||
(3) view.showAnimatedSkeleton() // Solid animated
|
||||
(4) view.showAnimatedGradientSkeleton() // Gradient animated
|
||||
```
|
||||
|
||||
**Pré-visualização**
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="25%">
|
||||
<center>Solid</center>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<center>Gradient</center>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<center>Solid Animated</center>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<center>Gradient Animated</center>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="25%">
|
||||
<img src="Assets/solid.png"></img>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<img src="Assets/gradient.png"></img>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<img src="Assets/solid_animated.gif"></img>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<img src="Assets/gradient_animated.gif"></img>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
> **IMPORTANTE!**
|
||||
>>```SkeletonView``` é recursivo, então se você quer mostrar o esqueleto em todas as views skeletonables, você só precisa chamar o método na main container view. Por exemplo, com UIViewControllers
|
||||
|
||||
### 🌿 Coleções
|
||||
|
||||
```SkeletonView``` é compatível com ```UITableView``` e ```UICollectionView```.
|
||||
|
||||
###### UITableView
|
||||
|
||||
Se você quer mostrar o skeleton em uma ```UITableView```, você precisa conformar com o protocolo ```SkeletonTableViewDataSource```.
|
||||
|
||||
``` swift
|
||||
public protocol SkeletonTableViewDataSource: UITableViewDataSource {
|
||||
func numSections(in collectionSkeletonView: UITableView) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
|
||||
}
|
||||
```
|
||||
Como você pode ver, esse protocolo herda de ```UITableViewDataSource```, então você pode substituir esse protocolo com o protocolo do skeleton.
|
||||
|
||||
Esse protocolo tem uma implementação padrão:
|
||||
|
||||
``` swift
|
||||
func numSections(in collectionSkeletonView: UITableView) -> Int
|
||||
// Default: 1
|
||||
```
|
||||
|
||||
``` swift
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int
|
||||
// Default:
|
||||
// It calculates how many cells need to populate whole tableview
|
||||
```
|
||||
|
||||
Esse é o único método que você precisa implementar para informar o skeleton sobre o cell identifier. Esse método não possui uma implementação padrão:
|
||||
``` swift
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
|
||||
```
|
||||
|
||||
**Exemplo**
|
||||
``` swift
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier {
|
||||
return "CellIdentifier"
|
||||
}
|
||||
```
|
||||
|
||||
> **IMPORTANTE!**
|
||||
> Se você está usando resizable cells (`tableView.rowHeight = UITableViewAutomaticDimension` ), é obrigatório definir a `estimatedRowHeight`.
|
||||
|
||||
###### UICollectionView
|
||||
|
||||
Para ```UICollectionView```, você precisa conformar com o protocolo ```SkeletonCollectionViewDataSource```.
|
||||
|
||||
``` swift
|
||||
public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
|
||||
func numSections(in collectionSkeletonView: UICollectionView) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier
|
||||
}
|
||||
```
|
||||
|
||||
O resto do processo é o mesmo da ```UITableView```
|
||||
|
||||
### 📰 Texto de várias linhas
|
||||
|
||||
|
||||

|
||||
|
||||
Quando você usar elementos com texto, ```SkeletonView``` desenha linhas para simular o texto.
|
||||
Além disso, você pode decidir quantas linhas você quer. Se ```numberOfLines``` está setado para zero (0), haverá um cálculo para saber quantas linhas são necessárias para preencher o skeleton inteiro e será desenhado. Caso contrário, se você setar para um (1) ou qualquer outro número maior que zero, só serão desenhadas aquele número de linhas.
|
||||
|
||||
##### 🎛 Customização
|
||||
|
||||
Você pode setar algumas propriedades para elementos de várias linhas.
|
||||
|
||||
|
||||
| Property | Values | Default | Preview
|
||||
| ------- | ------- |------- | -------
|
||||
| **Filling percent** of the last line. | `0...100` | `70%` | 
|
||||
| **Corner radius** of lines. (**NEW**) | `0...10` | `0` | 
|
||||
|
||||
|
||||
|
||||
Para modificar a percentagem ou o raio **usando código**, especifique as propriedades:
|
||||
```swift
|
||||
descriptionTextView.lastLineFillPercent = 50
|
||||
descriptionTextView.linesCornerRadius = 5
|
||||
```
|
||||
|
||||
Ou, se você preferir use **IB/Storyboard**:
|
||||
|
||||

|
||||
|
||||
### 🎨 Cores customizadas
|
||||
|
||||
Você pode decidir que cor o skeleton esta pintado. Você só precisa parametrizar a cor e o gradiente que deseja.
|
||||
|
||||
**Usando cores sólidas**
|
||||
``` swift
|
||||
view.showSkeleton(usingColor: UIColor.gray) // Solid
|
||||
// or
|
||||
view.showSkeleton(usingColor: UIColor(red: 25.0, green: 30.0, blue: 255.0, alpha: 1.0))
|
||||
```
|
||||
**Usando gradientes**
|
||||
``` swift
|
||||
let gradient = SkeletonGradient(baseColor: UIColor.midnightBlue)
|
||||
view.showGradientSkeleton(usingGradient: gradient) // Gradient
|
||||
```
|
||||
|
||||
Além do mais, ```SkeletonView``` tem 20 cores flat 🤙🏼
|
||||
|
||||
```UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...```
|
||||
|
||||

|
||||
###### Imagem capturada do site [https://flatuicolors.com](https://flatuicolors.com)
|
||||
|
||||
### 🦋 Aparência
|
||||
|
||||
**NOVIDADE** Os skeletons tem uma aparência padrão. Então, quando você não especifíca a cor, gradiente ou propriedades de várias linhas, `SkeletonView` usa os valores padrões.
|
||||
|
||||
Valores padrões:
|
||||
- **tintColor**: UIColor
|
||||
- *default: .clouds*
|
||||
- **gradient**: SkeletonGradient
|
||||
- *default: SkeletonGradient(baseColor: .clouds)*
|
||||
- **multilineHeight**: CGFloat
|
||||
- *default: 15*
|
||||
- **multilineSpacing**: CGFloat
|
||||
- *default: 10*
|
||||
- **multilineLastLineFillPercent**: Int
|
||||
- *default: 70*
|
||||
- **multilineCornerRadius**: Int
|
||||
- *default: 0*
|
||||
|
||||
Para obter esses valores padrões você pode usar `SkeletonAppearance.default`. Usando essa propriedade você pode declarar os valores também:
|
||||
```Swift
|
||||
SkeletonAppearance.default.multilineHeight = 20
|
||||
SkeletonAppearance.default.tintColor = .green
|
||||
```
|
||||
|
||||
|
||||
### 🤓 Animações customizadas
|
||||
|
||||
```SkeletonView``` tem duas animações pré-definidas, *pulse* para skeletons solidos e *sliding* para gradientes.
|
||||
|
||||
Além disso, se você quiser fazer suas próprias animações no skeleton, é muito fácil.
|
||||
|
||||
|
||||
Skeleton disponibiliza a função `showAnimatedSkeleton` que tem o closure ```SkeletonLayerAnimation``` onde você pode definir sua animação customizada.
|
||||
|
||||
```swift
|
||||
public typealias SkeletonLayerAnimation = (CALayer) -> CAAnimation
|
||||
```
|
||||
|
||||
Você pode chamar esta função assim:
|
||||
|
||||
```swift
|
||||
view.showAnimatedSkeleton { (layer) -> CAAnimation in
|
||||
let animation = CAAnimation()
|
||||
// Customize here your animation
|
||||
|
||||
return animation
|
||||
}
|
||||
```
|
||||
|
||||
Está disponível ```SkeletonAnimationBuilder```. É um construtor para ```SkeletonLayerAnimation```.
|
||||
|
||||
Hoje, você pode criar **sliding animations** para gradientes, decidindo a **direction** e setando a **duration** da animaçāo (padrão = 1.5s).
|
||||
|
||||
```swift
|
||||
// func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation
|
||||
|
||||
let animation = SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: .leftToRight)
|
||||
view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
|
||||
|
||||
```
|
||||
|
||||
```GradientDirection``` é um enum, com os seguintes cases:
|
||||
|
||||
| Direction | Preview
|
||||
|------- | -------
|
||||
| .leftRight | 
|
||||
| .rightLeft | 
|
||||
| .topBottom | 
|
||||
| .bottomTop | 
|
||||
| .topLeftBottomRight | 
|
||||
| .bottomRightTopLeft | 
|
||||
|
||||
> **😉 TRUQUE!**
|
||||
Existe outra forma de criar sliding animations, apenas usando este atalho:
|
||||
>>```let animation = GradientDirection.leftToRight.slidingAnimation()```
|
||||
|
||||
### 👨👧👦 Hierarquia
|
||||
|
||||
Já que ```SkeletonView``` é recursiva, e queremos que o skeleton seja muito eficiente, queremos parar a recursão assim que possível. Por este motivo, você deve setar a container view como `Skeletonable`, porque o Skeleton vai parar de procurar por subviews `skeletonable` assim que a view não for mais skeletonable, quebrando a recursão.
|
||||
|
||||
Porque uma imagem vale mais que mil palavras:
|
||||
|
||||
> ```ìsSkeletonable```= ☠️
|
||||
|
||||
| Configuration | Result
|
||||
|------- | -------
|
||||
| | 
|
||||
| | 
|
||||
| | 
|
||||
| | 
|
||||
|
||||
|
||||
|
||||
### 📚 Documentação
|
||||
Em breve...😅
|
||||
|
||||
## 📬 Próximos passos
|
||||
|
||||
* [x] Setar o percentual de preenchimento da última linha em elementos de várias linhas
|
||||
* [x] Adicionar mais animações de gradiente
|
||||
* [x] Suporte para resizable cells
|
||||
* [x] Compatível com CollectionView
|
||||
* [x] Compatível com tvOS
|
||||
* [x] Adicionar recovery state
|
||||
* [x] Aparência padrão customizável
|
||||
* [ ] Compatível com coleções customizáveis
|
||||
* [ ] Adicionar animações quando mostra/esconde os skeletons
|
||||
* [ ] Compatível com MacOS e WatchOS
|
||||
|
||||
## ❤️ Contribuindo
|
||||
Este é um projeto de código aberto, então sinta-se a vontade para contribuir. Como?
|
||||
- Abra uma [issue](https://github.com/Juanpe/SkeletonView/issues/new).
|
||||
- Envie feedback por [email](mailto://juanpecatalan.com).
|
||||
- Proponha seus próprios fixes, sugestões e abra um pull request com as alterações.
|
||||
|
||||
Ver [todos os contribuidores](https://github.com/Juanpe/SkeletonView/graphs/contributors)
|
||||
|
||||
###### Projeto gerado com [SwiftPlate](https://github.com/JohnSundell/SwiftPlate)
|
||||
|
||||
## 📢 Menções
|
||||
|
||||
- [iOS Dev Weekly #327](https://iosdevweekly.com/issues/327#start)
|
||||
- [Hacking with Swift Articles](https://www.hackingwithswift.com/articles/40/skeletonview-makes-loading-content-beautiful)
|
||||
- [Top 10 Swift Articles November](https://medium.mybridge.co/swift-top-10-articles-for-the-past-month-v-nov-2017-dfed7861cd65)
|
||||
- [30 Amazing iOS Swift Libraries (v2018)](https://medium.mybridge.co/30-amazing-ios-swift-libraries-for-the-past-year-v-2018-7cf15027eee9)
|
||||
- [AppCoda Weekly #44](http://digest.appcoda.com/issues/appcoda-weekly-issue-44-81899)
|
||||
- [iOS Cookies Newsletter #103](https://us11.campaign-archive.com/?u=cd1f3ed33c6527331d82107ba&id=48131a516d)
|
||||
- [Swift Developments Newsletter #113](https://andybargh.com/swiftdevelopments-113/)
|
||||
- [iOS Goodies #204](http://ios-goodies.com/post/167557280951/week-204)
|
||||
- [Swift Weekly #96](http://digest.swiftweekly.com/issues/swift-weekly-issue-96-81759)
|
||||
- [CocoaControls](https://www.cocoacontrols.com/controls/skeletonview)
|
||||
- [Awesome iOS Newsletter #74](https://ios.libhunt.com/newsletter/74)
|
||||
|
||||
|
||||
|
||||
## 👨🏻💻 Autor
|
||||
[1.1]: http://i.imgur.com/tXSoThF.png
|
||||
[1]: http://www.twitter.com/JuanpeCatalan
|
||||
|
||||
* Juanpe Catalán [![alt text][1.1]][1]
|
||||
|
||||
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
|
||||
|
||||
## 👮🏻 Licença
|
||||
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Juanpe Catalán
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
+3
-1
@@ -31,7 +31,9 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
🌎 翻译: [ [原版的](https://github.com/Juanpe/SkeletonView) ]
|
||||
🌎 翻译: [ [原版的](https://github.com/Juanpe/SkeletonView) ] </br>
|
||||
[🇧🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_pt-br.md) [@brunomunizaf](https://twitter.com/brunomuniz_af)
|
||||
|
||||
|
||||
今天,几乎所有的应用程序都有异步流程,例如:Api请求、长时间运行的流程等。虽然流程正在运行,但通常开发人员会设置一个加载视图来向用户显示正在发生的事情。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "SkeletonView"
|
||||
s.version = "1.3"
|
||||
s.version = "1.4.1"
|
||||
s.summary = "An elegant way to show users that something is happening and also prepare them to which contents he is waiting"
|
||||
s.description = <<-DESC
|
||||
Today almost all apps have async processes, as API requests, long runing processes, etc. And while the processes are working, usually developers place a loading view to show users that something is going on.
|
||||
|
||||
@@ -38,11 +38,12 @@
|
||||
42ABD07A210B54E200BEEFF4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 42ABD072210B54E100BEEFF4 /* Assets.xcassets */; };
|
||||
42ABD07B210B54E200BEEFF4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42ABD073210B54E100BEEFF4 /* ViewController.swift */; };
|
||||
42ABD07C210B54E200BEEFF4 /* Base.lproj in Resources */ = {isa = PBXBuildFile; fileRef = 42ABD074210B54E100BEEFF4 /* Base.lproj */; };
|
||||
42ABD07D210B54E200BEEFF4 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42ABD075210B54E100BEEFF4 /* Constants.swift */; };
|
||||
42ABD07E210B54E200BEEFF4 /* SkeletonViewExampleCollectionview-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 42ABD076210B54E200BEEFF4 /* SkeletonViewExampleCollectionview-Info.plist */; };
|
||||
42ABD07F210B54E200BEEFF4 /* CollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42ABD077210B54E200BEEFF4 /* CollectionViewCell.swift */; };
|
||||
8748240D20C6A88A00E92179 /* UIView+IBInspectable.swift in Headers */ = {isa = PBXBuildFile; fileRef = F5F899CF1FAA6A4D002E8FDA /* UIView+IBInspectable.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8748240E20C6A88E00E92179 /* ContainsMultilineText.swift in Headers */ = {isa = PBXBuildFile; fileRef = F5307E3A1FB123C100EE67C5 /* ContainsMultilineText.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8785E3A1211C9C9800CC9DFD /* SkeletonDebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8785E3A0211C9C9800CC9DFD /* SkeletonDebug.swift */; };
|
||||
8785E3A2211C9CA500CC9DFD /* SkeletonDebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8785E3A0211C9C9800CC9DFD /* SkeletonDebug.swift */; };
|
||||
8785E3A3211C9CE800CC9DFD /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DEA97D1FCDBD1F006C80EF /* Constants.swift */; };
|
||||
88DEA97F1FCDBD78006C80EF /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DEA97D1FCDBD1F006C80EF /* Constants.swift */; };
|
||||
8933C7851EB5B820000D00A4 /* SkeletonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7841EB5B820000D00A4 /* SkeletonView.swift */; };
|
||||
F51DE1091FBF70A70037919A /* SkeletonAnimationBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */; };
|
||||
@@ -71,6 +72,8 @@
|
||||
F58A6E6C20A8C54100612494 /* RecoverableViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F58A6E6A20A8C54100612494 /* RecoverableViewState.swift */; };
|
||||
F58A6E6E20A8C66300612494 /* Recoverable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F58A6E6D20A8C66300612494 /* Recoverable.swift */; };
|
||||
F58A6E6F20A8C66300612494 /* Recoverable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F58A6E6D20A8C66300612494 /* Recoverable.swift */; };
|
||||
F5A5E8B4211DCE7000FD20D0 /* Int+Whitespaces.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A5E8B3211DCE7000FD20D0 /* Int+Whitespaces.swift */; };
|
||||
F5A5E8B5211DCE7000FD20D0 /* Int+Whitespaces.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A5E8B3211DCE7000FD20D0 /* Int+Whitespaces.swift */; };
|
||||
F5D3FB0B209DCAA300003FCF /* SubviewsSkeletonables.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D3FB0A209DCAA300003FCF /* SubviewsSkeletonables.swift */; };
|
||||
F5D3FB0C209DCAA300003FCF /* SubviewsSkeletonables.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D3FB0A209DCAA300003FCF /* SubviewsSkeletonables.swift */; };
|
||||
F5F622411FAC6E31007C062A /* UIColor+Skeleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5F622401FAC6E31007C062A /* UIColor+Skeleton.swift */; };
|
||||
@@ -142,10 +145,10 @@
|
||||
42ABD072210B54E100BEEFF4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
42ABD073210B54E100BEEFF4 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
42ABD074210B54E100BEEFF4 /* Base.lproj */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Base.lproj; sourceTree = "<group>"; };
|
||||
42ABD075210B54E100BEEFF4 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
42ABD076210B54E200BEEFF4 /* SkeletonViewExampleCollectionview-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SkeletonViewExampleCollectionview-Info.plist"; sourceTree = "<group>"; };
|
||||
42ABD077210B54E200BEEFF4 /* CollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
52D6D97C1BEFF229002C0205 /* SkeletonView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SkeletonView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8785E3A0211C9C9800CC9DFD /* SkeletonDebug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonDebug.swift; sourceTree = "<group>"; };
|
||||
88DEA97D1FCDBD1F006C80EF /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
8933C7841EB5B820000D00A4 /* SkeletonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SkeletonView.swift; sourceTree = "<group>"; };
|
||||
F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonAnimationBuilder.swift; sourceTree = "<group>"; };
|
||||
@@ -167,6 +170,7 @@
|
||||
F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+UIApplicationDelegate.swift"; sourceTree = "<group>"; };
|
||||
F58A6E6A20A8C54100612494 /* RecoverableViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoverableViewState.swift; sourceTree = "<group>"; };
|
||||
F58A6E6D20A8C66300612494 /* Recoverable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Recoverable.swift; sourceTree = "<group>"; };
|
||||
F5A5E8B3211DCE7000FD20D0 /* Int+Whitespaces.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Int+Whitespaces.swift"; sourceTree = "<group>"; };
|
||||
F5D3FB0A209DCAA300003FCF /* SubviewsSkeletonables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubviewsSkeletonables.swift; sourceTree = "<group>"; };
|
||||
F5F622401FAC6E31007C062A /* UIColor+Skeleton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Skeleton.swift"; sourceTree = "<group>"; };
|
||||
F5F622421FAC81FD007C062A /* CALayer+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CALayer+Extensions.swift"; sourceTree = "<group>"; };
|
||||
@@ -226,7 +230,6 @@
|
||||
42ABD072210B54E100BEEFF4 /* Assets.xcassets */,
|
||||
42ABD074210B54E100BEEFF4 /* Base.lproj */,
|
||||
42ABD077210B54E200BEEFF4 /* CollectionViewCell.swift */,
|
||||
42ABD075210B54E100BEEFF4 /* Constants.swift */,
|
||||
42ABD071210B54E100BEEFF4 /* Main.storyboard */,
|
||||
42ABD073210B54E100BEEFF4 /* ViewController.swift */,
|
||||
);
|
||||
@@ -267,15 +270,32 @@
|
||||
path = Configs;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8785E39E211C9C6D00CC9DFD /* Appearance */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F5307E2F1FB0EC9D00EE67C5 /* SkeletonAppearance.swift */,
|
||||
);
|
||||
path = Appearance;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8785E39F211C9C7C00CC9DFD /* Debug */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8785E3A0211C9C9800CC9DFD /* SkeletonDebug.swift */,
|
||||
);
|
||||
path = Debug;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8933C7811EB5B7E0000D00A4 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8785E39F211C9C7C00CC9DFD /* Debug */,
|
||||
8785E39E211C9C6D00CC9DFD /* Appearance */,
|
||||
F58A6E7020A8C87100612494 /* Recoverable */,
|
||||
F5307E331FB1068500EE67C5 /* Collections */,
|
||||
F5307E341FB106A500EE67C5 /* Extensions */,
|
||||
F5307E351FB106BF00EE67C5 /* Helpers */,
|
||||
F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */,
|
||||
F5307E2F1FB0EC9D00EE67C5 /* SkeletonAppearance.swift */,
|
||||
F587FB83202CBFC8002DB5FE /* SkeletonFlow.swift */,
|
||||
F5307E2B1FAF6BC900EE67C5 /* SkeletonGradient.swift */,
|
||||
F5F899E81FAB9D2B002E8FDA /* SkeletonLayer.swift */,
|
||||
@@ -343,6 +363,7 @@
|
||||
F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */,
|
||||
F5F899CF1FAA6A4D002E8FDA /* UIView+IBInspectable.swift */,
|
||||
F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift */,
|
||||
F5A5E8B3211DCE7000FD20D0 /* Int+Whitespaces.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@@ -502,7 +523,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0910;
|
||||
LastUpgradeCheck = 0930;
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = SkeletonView;
|
||||
TargetAttributes = {
|
||||
17DD0DFF207FB27400C56334 = {
|
||||
@@ -510,17 +531,16 @@
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
42ABD05A210B548200BEEFF4 = {
|
||||
DevelopmentTeam = KWEMDK92F4;
|
||||
LastSwiftMigration = 0940;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
52D6D97B1BEFF229002C0205 = {
|
||||
CreatedOnToolsVersion = 7.1;
|
||||
LastSwiftMigration = 0800;
|
||||
LastSwiftMigration = 1000;
|
||||
};
|
||||
F5F899F11FABA607002E8FDA = {
|
||||
CreatedOnToolsVersion = 9.1;
|
||||
DevelopmentTeam = KWEMDK92F4;
|
||||
LastSwiftMigration = 1000;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
@@ -558,7 +578,6 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
42ABD07E210B54E200BEEFF4 /* SkeletonViewExampleCollectionview-Info.plist in Resources */,
|
||||
42ABD07A210B54E200BEEFF4 /* Assets.xcassets in Resources */,
|
||||
42ABD07C210B54E200BEEFF4 /* Base.lproj in Resources */,
|
||||
42ABD079210B54E200BEEFF4 /* Main.storyboard in Resources */,
|
||||
@@ -593,6 +612,7 @@
|
||||
17DD0E1E207FB32100C56334 /* PrepareForSkeletonProtocol.swift in Sources */,
|
||||
F51ED28520973CC9008B2434 /* SkeletonReusableCell.swift in Sources */,
|
||||
17DD0E17207FB28F00C56334 /* SkeletonLayer.swift in Sources */,
|
||||
8785E3A2211C9CA500CC9DFD /* SkeletonDebug.swift in Sources */,
|
||||
17DD0E08207FB28900C56334 /* CollectionSkeletonProtocol.swift in Sources */,
|
||||
F58A6E6C20A8C54100612494 /* RecoverableViewState.swift in Sources */,
|
||||
17DD0E0B207FB28900C56334 /* SkeletonTableViewProtocols.swift in Sources */,
|
||||
@@ -614,6 +634,7 @@
|
||||
F51ED28420973CC6008B2434 /* GenericCollectionView.swift in Sources */,
|
||||
17DD0E0A207FB28900C56334 /* SkeletonCollectionViewProtocols.swift in Sources */,
|
||||
17DD0E1C207FB32100C56334 /* AssociationPolicy.swift in Sources */,
|
||||
F5A5E8B5211DCE7000FD20D0 /* Int+Whitespaces.swift in Sources */,
|
||||
17DD0E1D207FB32100C56334 /* ContainsMultilineText.swift in Sources */,
|
||||
17DD0E0F207FB28C00C56334 /* CALayer+Extensions.swift in Sources */,
|
||||
17DD0E16207FB28F00C56334 /* SkeletonGradient.swift in Sources */,
|
||||
@@ -627,7 +648,7 @@
|
||||
42ABD07B210B54E200BEEFF4 /* ViewController.swift in Sources */,
|
||||
42ABD078210B54E200BEEFF4 /* AppDelegate.swift in Sources */,
|
||||
42ABD07F210B54E200BEEFF4 /* CollectionViewCell.swift in Sources */,
|
||||
42ABD07D210B54E200BEEFF4 /* Constants.swift in Sources */,
|
||||
8785E3A3211C9CE800CC9DFD /* Constants.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -639,6 +660,7 @@
|
||||
F54CF5E42024CEB000330B0D /* UIView+CollectionSkeleton.swift in Sources */,
|
||||
F5307E371FB1076E00EE67C5 /* SkeletonTableViewProtocols.swift in Sources */,
|
||||
8933C7851EB5B820000D00A4 /* SkeletonView.swift in Sources */,
|
||||
8785E3A1211C9C9800CC9DFD /* SkeletonDebug.swift in Sources */,
|
||||
F5307E301FB0EC9D00EE67C5 /* SkeletonAppearance.swift in Sources */,
|
||||
F58A6E6B20A8C54100612494 /* RecoverableViewState.swift in Sources */,
|
||||
F54CF5E52024CEB000330B0D /* UITableView+CollectionSkeleton.swift in Sources */,
|
||||
@@ -660,6 +682,7 @@
|
||||
F5307E3B1FB123C100EE67C5 /* ContainsMultilineText.swift in Sources */,
|
||||
F5F899E91FAB9D2B002E8FDA /* SkeletonLayer.swift in Sources */,
|
||||
F5307E2E1FB0E5E400EE67C5 /* UIView+Frame.swift in Sources */,
|
||||
F5A5E8B4211DCE7000FD20D0 /* Int+Whitespaces.swift in Sources */,
|
||||
F51DF871206E91B300D23301 /* SkeletonReusableCell.swift in Sources */,
|
||||
F51DF879206E9F5500D23301 /* SkeletonCollectionDelegate.swift in Sources */,
|
||||
F51DE1091FBF70A70037919A /* SkeletonAnimationBuilder.swift in Sources */,
|
||||
@@ -738,7 +761,7 @@
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
@@ -770,7 +793,7 @@
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
@@ -789,9 +812,9 @@
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = KWEMDK92F4;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = "SkeletonViewExample copy-Info.plist";
|
||||
INFOPLIST_FILE = "Configs/SkeletonViewExampleCollectionview-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.juanpecatalan.SkeletonViewExample;
|
||||
@@ -816,9 +839,9 @@
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = KWEMDK92F4;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = "SkeletonViewExample copy-Info.plist";
|
||||
INFOPLIST_FILE = "Configs/SkeletonViewExampleCollectionview-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.juanpecatalan.SkeletonViewExample;
|
||||
@@ -961,7 +984,7 @@
|
||||
PRODUCT_NAME = SkeletonView;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -985,7 +1008,7 @@
|
||||
PRODUCT_NAME = SkeletonView;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -1001,7 +1024,7 @@
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = KWEMDK92F4;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Configs/SkeletonViewExampleInfo.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
@@ -1009,7 +1032,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.juanpecatalan.SkeletonViewExample;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -1026,7 +1049,7 @@
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = KWEMDK92F4;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Configs/SkeletonViewExampleInfo.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
@@ -1034,7 +1057,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.juanpecatalan.SkeletonViewExample;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -28,6 +28,6 @@ extension CollectionSkeleton where Self: UIScrollView {
|
||||
var estimatedNumberOfRows: Int { return 0 }
|
||||
func addDummyDataSource() {}
|
||||
func removeDummyDataSource(reloadAfter: Bool) {}
|
||||
func disableUserInteraction() { isUserInteractionEnabled = false }
|
||||
func enableUserInteraction() { isUserInteractionEnabled = true }
|
||||
func disableUserInteraction() { isScrollEnabled = false }
|
||||
func enableUserInteraction() { isScrollEnabled = true }
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ extension UITableView: CollectionSkeleton {
|
||||
}
|
||||
|
||||
private func calculateRowHeight() -> CGFloat {
|
||||
guard rowHeight == UITableViewAutomaticDimension else { return rowHeight }
|
||||
guard rowHeight == UITableView.automaticDimension else { return rowHeight }
|
||||
rowHeight = estimatedRowHeight
|
||||
return estimatedRowHeight
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
enum SkeletonEnvironmentKey: String {
|
||||
case debugMode = "SKELETON_DEBUG"
|
||||
}
|
||||
|
||||
extension Dictionary {
|
||||
subscript (_ key: SkeletonEnvironmentKey) -> Value? {
|
||||
return self[key.rawValue as! Key]
|
||||
}
|
||||
}
|
||||
|
||||
func printSkeletonHierarchy(in view: UIView) {
|
||||
skeletonLog(view.skeletonHierarchy())
|
||||
}
|
||||
|
||||
func skeletonLog(_ message: String) {
|
||||
if let _ = ProcessInfo.processInfo.environment[.debugMode] {
|
||||
print(message)
|
||||
}
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
|
||||
public var skeletonDescription: String {
|
||||
var description = "<\(type(of: self)): \(Unmanaged.passUnretained(self).toOpaque())"
|
||||
let subSkeletons = subviewsSkeletonables
|
||||
if subSkeletons.count != 0 {
|
||||
description += " | (\(subSkeletons.count)) subSkeletons"
|
||||
}
|
||||
if isSkeletonable {
|
||||
description += " | ☠️ "
|
||||
}
|
||||
return description + ">"
|
||||
}
|
||||
|
||||
public func skeletonHierarchy(index: Int = 0) -> String {
|
||||
var description = index == 0 ? "\n ⬇⬇ ☠️ Root view hierarchy with Skeletons ⬇⬇ \n" : ""
|
||||
description += "\(index == 0 ? "\n" : 3.whitespaces) \(skeletonDescription) \n"
|
||||
subviewsToSkeleton.forEach {
|
||||
description += (index + 2).whitespaces
|
||||
description += $0.skeletonHierarchy(index: index + 1)
|
||||
}
|
||||
return description
|
||||
}
|
||||
}
|
||||
@@ -10,18 +10,20 @@ import UIKit
|
||||
|
||||
extension CALayer {
|
||||
@objc func tint(withColors colors: [UIColor]) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { backgroundColor = colors.first?.cgColor }) {
|
||||
$0.tint(withColors: colors)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
backgroundColor = colors.first?.cgColor
|
||||
}) {
|
||||
$0.tint(withColors: colors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CAGradientLayer {
|
||||
override func tint(withColors colors: [UIColor]) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { self.colors = colors.map { $0.cgColor } }) {
|
||||
$0.tint(withColors: colors)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
self.colors = colors.map { $0.cgColor }
|
||||
}) {
|
||||
$0.tint(withColors: colors)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +68,7 @@ public extension CALayer {
|
||||
pulseAnimation.fromValue = backgroundColor
|
||||
pulseAnimation.toValue = UIColor(cgColor: backgroundColor!).complementaryColor.cgColor
|
||||
pulseAnimation.duration = 1
|
||||
pulseAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
|
||||
pulseAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
|
||||
pulseAnimation.autoreverses = true
|
||||
pulseAnimation.repeatCount = .infinity
|
||||
return pulseAnimation
|
||||
@@ -84,23 +86,25 @@ public extension CALayer {
|
||||
let animGroup = CAAnimationGroup()
|
||||
animGroup.animations = [startPointAnim, endPointAnim]
|
||||
animGroup.duration = 1.5
|
||||
animGroup.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
|
||||
animGroup.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
|
||||
animGroup.repeatCount = .infinity
|
||||
|
||||
return animGroup
|
||||
}
|
||||
|
||||
func playAnimation(_ anim: SkeletonLayerAnimation, key: String) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { add(anim(self), forKey: key) }) {
|
||||
$0.playAnimation(anim, key: key)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
add(anim(self), forKey: key)
|
||||
}) {
|
||||
$0.playAnimation(anim, key: key)
|
||||
}
|
||||
}
|
||||
|
||||
func stopAnimation(forKey key: String) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { removeAnimation(forKey: key) }) {
|
||||
$0.stopAnimation(forKey: key)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
removeAnimation(forKey: key)
|
||||
}) {
|
||||
$0.stopAnimation(forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Int {
|
||||
|
||||
var whitespace: String {
|
||||
return whitespaces
|
||||
}
|
||||
|
||||
var whitespaces: String {
|
||||
return String(repeating: " ", count: self)
|
||||
}
|
||||
}
|
||||
@@ -32,12 +32,12 @@ extension UIView {
|
||||
}
|
||||
|
||||
var maxWidthEstimated: CGFloat {
|
||||
let constraintsWidth = nonContentSizeLayoutConstraints.filter({ $0.firstAttribute == NSLayoutAttribute.width })
|
||||
let constraintsWidth = nonContentSizeLayoutConstraints.filter({ $0.firstAttribute == NSLayoutConstraint.Attribute.width })
|
||||
return max(between: frame.size.width, andContantsOf: constraintsWidth)
|
||||
}
|
||||
|
||||
var maxHeightEstimated: CGFloat {
|
||||
let constraintsHeight = nonContentSizeLayoutConstraints.filter({ $0.firstAttribute == NSLayoutAttribute.height })
|
||||
let constraintsHeight = nonContentSizeLayoutConstraints.filter({ $0.firstAttribute == NSLayoutConstraint.Attribute.height })
|
||||
return max(between: frame.size.height, andContantsOf: constraintsHeight)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import UIKit
|
||||
extension UIView {
|
||||
|
||||
enum Constants {
|
||||
static let becomeActiveNotification = NSNotification.Name.UIApplicationDidBecomeActive
|
||||
static let enterForegroundNotification = NSNotification.Name.UIApplicationDidEnterBackground
|
||||
static let becomeActiveNotification = UIApplication.didBecomeActiveNotification
|
||||
static let enterForegroundNotification = UIApplication.didEnterBackgroundNotification
|
||||
static let needAnimatedSkeletonKey = "needAnimateSkeleton"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +1,28 @@
|
||||
//
|
||||
// HelperProtocols.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Juanpe Catalán on 06/11/2017.
|
||||
// Copyright © 2017 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
typealias VoidBlock = () -> Void
|
||||
typealias RecursiveBlock<T> = (T) -> Void
|
||||
|
||||
protocol IterableElement {}
|
||||
extension UIView: IterableElement {}
|
||||
extension CALayer: IterableElement {}
|
||||
|
||||
//MARK: Recursive
|
||||
protocol Recursive {
|
||||
associatedtype Element
|
||||
func recursiveSearch(inArray array:[Element], leafBlock: VoidBlock, recursiveBlock: RecursiveBlock<Element>)
|
||||
associatedtype Element: IterableElement
|
||||
func recursiveSearch(leafBlock: VoidBlock, recursiveBlock: RecursiveBlock<Element>)
|
||||
}
|
||||
|
||||
extension Recursive {
|
||||
func recursiveSearch(inArray array:[Element], leafBlock: VoidBlock, recursiveBlock: RecursiveBlock<Element>) {
|
||||
guard array.count > 0 else {
|
||||
extension Array: Recursive where Element: IterableElement {
|
||||
func recursiveSearch(leafBlock: VoidBlock, recursiveBlock: RecursiveBlock<Element>) {
|
||||
guard count > 0 else {
|
||||
leafBlock()
|
||||
return
|
||||
}
|
||||
array.forEach { recursiveBlock($0) }
|
||||
forEach { recursiveBlock($0) }
|
||||
}
|
||||
}
|
||||
|
||||
extension UIView: Recursive {
|
||||
typealias Element = UIView
|
||||
}
|
||||
extension CALayer: Recursive {
|
||||
typealias Element = CALayer
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ public class SkeletonAnimationBuilder {
|
||||
let animGroup = CAAnimationGroup()
|
||||
animGroup.animations = [startPointAnim, endPointAnim]
|
||||
animGroup.duration = duration
|
||||
animGroup.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
|
||||
animGroup.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
|
||||
animGroup.repeatCount = .infinity
|
||||
|
||||
return animGroup
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
//
|
||||
// SkeletonFlow.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Juanpe Catalán on 08/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
protocol SkeletonFlowDelegate {
|
||||
func willBeginShowingSkeletons(withRootView rootView: UIView)
|
||||
func didShowSkeletons(withRootView rootView: UIView)
|
||||
func willBeginHidingSkeletons(withRootView rootView: UIView)
|
||||
func didHideSkeletons(withRootView rootView: UIView)
|
||||
|
||||
}
|
||||
|
||||
class SkeletonFlowHandler: SkeletonFlowDelegate {
|
||||
|
||||
|
||||
func willBeginShowingSkeletons(withRootView rootView: UIView) {
|
||||
rootView.addAppNotificationsObservers()
|
||||
}
|
||||
|
||||
func didShowSkeletons(withRootView rootView: UIView) {
|
||||
printSkeletonHierarchy(in: rootView)
|
||||
}
|
||||
|
||||
func willBeginHidingSkeletons(withRootView rootView: UIView) {
|
||||
rootView.removeAppNoticationsObserver()
|
||||
}
|
||||
|
||||
func didHideSkeletons(withRootView rootView: UIView) {
|
||||
rootView.flowDelegate = nil
|
||||
}
|
||||
}
|
||||
|
||||
+31
-27
@@ -22,22 +22,20 @@ public extension UIView {
|
||||
|
||||
func hideSkeleton(reloadDataAfter reload: Bool = true) {
|
||||
flowDelegate?.willBeginHidingSkeletons(withRootView: self)
|
||||
recursiveHideSkeleton(reloadDataAfter: reload)
|
||||
recursiveHideSkeleton(reloadDataAfter: reload, root: self)
|
||||
}
|
||||
|
||||
func startSkeletonAnimation(_ anim: SkeletonLayerAnimation? = nil) {
|
||||
skeletonIsAnimated = true
|
||||
recursiveSearch(inArray: subviewsSkeletonables,
|
||||
leafBlock: startSkeletonLayerAnimationBlock(anim)) {
|
||||
$0.startSkeletonAnimation(anim)
|
||||
}
|
||||
subviewsSkeletonables.recursiveSearch(leafBlock: startSkeletonLayerAnimationBlock(anim)) { subview in
|
||||
subview.startSkeletonAnimation(anim)
|
||||
}
|
||||
}
|
||||
|
||||
func stopSkeletonAnimation() {
|
||||
skeletonIsAnimated = false
|
||||
recursiveSearch(inArray: subviewsSkeletonables,
|
||||
leafBlock: stopSkeletonLayerAnimationBlock) {
|
||||
$0.stopSkeletonAnimation()
|
||||
subviewsSkeletonables.recursiveSearch(leafBlock: stopSkeletonLayerAnimationBlock) { subview in
|
||||
subview.stopSkeletonAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,33 +46,39 @@ extension UIView {
|
||||
skeletonIsAnimated = animated
|
||||
flowDelegate = SkeletonFlowHandler()
|
||||
flowDelegate?.willBeginShowingSkeletons(withRootView: self)
|
||||
recursiveShowSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation)
|
||||
recursiveShowSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation, root: self)
|
||||
}
|
||||
|
||||
fileprivate func recursiveShowSkeleton(withType type: SkeletonType, usingColors colors: [UIColor], animated: Bool, animation: SkeletonLayerAnimation?) {
|
||||
fileprivate func recursiveShowSkeleton(withType type: SkeletonType, usingColors colors: [UIColor], animated: Bool, animation: SkeletonLayerAnimation?, root: UIView? = nil) {
|
||||
addDummyDataSourceIfNeeded()
|
||||
recursiveSearch(inArray: subviewsSkeletonables,
|
||||
leafBlock: {
|
||||
guard !isSkeletonActive else { return }
|
||||
isUserInteractionEnabled = false
|
||||
saveViewState()
|
||||
(self as? PrepareForSkeleton)?.prepareViewForSkeleton()
|
||||
addSkeletonLayer(withType: type, usingColors: colors, animated: animated, animation: animation)
|
||||
}) {
|
||||
$0.recursiveShowSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation)
|
||||
|
||||
subviewsSkeletonables.recursiveSearch(leafBlock: {
|
||||
guard !isSkeletonActive else { return }
|
||||
isUserInteractionEnabled = false
|
||||
saveViewState()
|
||||
(self as? PrepareForSkeleton)?.prepareViewForSkeleton()
|
||||
addSkeletonLayer(withType: type, usingColors: colors, animated: animated, animation: animation)
|
||||
}) { subview in
|
||||
subview.recursiveShowSkeleton(withType: type, usingColors: colors, animated: animated, animation: animation)
|
||||
}
|
||||
|
||||
if let root = root {
|
||||
flowDelegate?.didShowSkeletons(withRootView: root)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func recursiveHideSkeleton(reloadDataAfter reload: Bool) {
|
||||
fileprivate func recursiveHideSkeleton(reloadDataAfter reload: Bool, root: UIView? = nil) {
|
||||
removeDummyDataSourceIfNeeded()
|
||||
isUserInteractionEnabled = true
|
||||
recursiveSearch(inArray: subviewsSkeletonables,
|
||||
leafBlock: {
|
||||
recoverViewState(forced: false)
|
||||
removeSkeletonLayer()
|
||||
}, recursiveBlock: {
|
||||
$0.recursiveHideSkeleton(reloadDataAfter: reload)
|
||||
})
|
||||
subviewsSkeletonables.recursiveSearch(leafBlock: {
|
||||
recoverViewState(forced: false)
|
||||
removeSkeletonLayer()
|
||||
}) { subview in
|
||||
subview.recursiveHideSkeleton(reloadDataAfter: reload)
|
||||
}
|
||||
if let root = root {
|
||||
flowDelegate?.didHideSkeletons(withRootView: root)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func startSkeletonLayerAnimationBlock(_ anim: SkeletonLayerAnimation? = nil) -> VoidBlock {
|
||||
|
||||
@@ -1,45 +1,48 @@
|
||||
//
|
||||
// SubviewsSkeletonables.swift
|
||||
// SkeletonView
|
||||
//
|
||||
// Created by Juanpe Catalán on 05/05/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
@objc var subviewsSkeletonables: [UIView] {
|
||||
return subviews.filter { $0.isSkeletonable }
|
||||
return subviewsToSkeleton.filter { $0.isSkeletonable }
|
||||
}
|
||||
|
||||
@objc var subviewsToSkeleton: [UIView] {
|
||||
return subviews
|
||||
}
|
||||
}
|
||||
|
||||
extension UITableView {
|
||||
override var subviewsSkeletonables: [UIView] {
|
||||
return visibleCells.filter { $0.isSkeletonable }
|
||||
|
||||
override var subviewsToSkeleton: [UIView] {
|
||||
return visibleCells
|
||||
}
|
||||
}
|
||||
|
||||
extension UITableViewCell {
|
||||
override var subviewsSkeletonables: [UIView] {
|
||||
return contentView.subviews.filter { $0.isSkeletonable }
|
||||
|
||||
override var subviewsToSkeleton: [UIView] {
|
||||
return contentView.subviews
|
||||
}
|
||||
}
|
||||
|
||||
extension UICollectionView {
|
||||
override var subviewsSkeletonables: [UIView] {
|
||||
return subviews.filter { $0.isSkeletonable }
|
||||
|
||||
override var subviewsToSkeleton: [UIView] {
|
||||
return subviews
|
||||
}
|
||||
}
|
||||
|
||||
extension UICollectionViewCell {
|
||||
override var subviewsSkeletonables: [UIView] {
|
||||
return contentView.subviews.filter { $0.isSkeletonable }
|
||||
|
||||
override var subviewsToSkeleton: [UIView] {
|
||||
return contentView.subviews
|
||||
}
|
||||
}
|
||||
|
||||
extension UIStackView {
|
||||
override var subviewsSkeletonables: [UIView] {
|
||||
return arrangedSubviews.filter { $0.isSkeletonable }
|
||||
|
||||
override var subviewsToSkeleton: [UIView] {
|
||||
return arrangedSubviews
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user