Compare commits

...

72 Commits

Author SHA1 Message Date
Juanpe Catalán 83e7e48caa feat: Bump cocoapod version 2019-02-26 17:54:53 +01:00
Juanpe Catalán c03af15070 Merge branch 'master' into develop 2019-02-02 10:30:30 +01:00
Juanpe Catalán ed82f74ba8 Merge pull request #131 from grifas/hotfix/reloadDataAfter
🐛 Fix  removeDummyDataSourceIfNeeded passing the reload parameter
2019-02-02 10:27:18 +01:00
Juanpe Catalán 01aba0b3ff Merge pull request #128 from jehlert-trip/feature/podspec_swift_version
Include swift_version in podspec
2019-02-02 10:24:14 +01:00
Aurélien Grifasi 6352030012 🐛 Fix removeDummyDataSourceIfNeeded passing the reload parameter 2019-01-15 11:53:45 +01:00
Justin Ehlert 4b06c30b9d Include swift_version in podspec 2019-01-10 14:33:15 -05:00
Juanpe Catalán 3dcde46fe9 feat: Update gitignore 2018-12-18 11:48:58 +01:00
Juanpe Catalán c9de28eb37 feat: update README file 2018-12-13 10:23:09 +01:00
Juanpe Catalán 915e838994 Merge branch 'develop'
# Conflicts:
#	README.md
2018-12-13 10:17:38 +01:00
Juanpe Catalán 74b44264ec Merge pull request #117 from Juanpe/feature/codebeat_refactor
Feature/codebeat refactor
2018-12-13 10:17:03 +01:00
Juanpe Catalán a9ad72aa0c feat: Update README file 2018-12-13 10:16:28 +01:00
Juanpe Catalán d535529be8 feat: Mute gradient switch 2018-12-13 10:03:13 +01:00
Juanpe Catalán a6bff05ca4 feat: Split line into two 2018-12-13 09:48:35 +01:00
Juanpe Catalán bc98cd600e feat: Refactor associated keys 2018-12-13 09:42:44 +01:00
Juanpe Catalán 8f1cfc0045 feat: Mute associated keys many instance variables 2018-12-13 08:51:35 +01:00
Juanpe Catalán 432ec6caa2 feat: Split associated keys 2018-12-12 18:59:34 +01:00
Juanpe Catalán e18aedbbf8 feat: Move examples files 2018-12-12 18:32:52 +01:00
Juanpe Catalán 4dc67ac3d7 feat: Refactor some classes 2018-12-12 18:28:42 +01:00
Juanpe Catalán aa29cd3d6b feat: Mute too many instance variables 2018-12-12 18:02:54 +01:00
Juanpe Catalán a2def55880 feat: Reorder section in README file 2018-12-12 16:01:44 +01:00
Juanpe Catalán 97f5e3e2e1 feat: Update README file 2018-12-12 15:59:40 +01:00
Juanpe Catalán 420cc7a669 Merge branch 'develop' 2018-12-12 09:11:09 +01:00
Juanpe Catalán b9601f56c3 Merge pull request #115 from Juanpe/feature/configure_fastlane
Feature/configure fastlane
2018-12-12 09:09:59 +01:00
Juanpe Catalán fbca1092c3 feat: Remove Appfile 2018-12-12 09:05:50 +01:00
Juanpe Catalán eb90faf413 fix: URL of bitrise badge 2018-12-11 11:21:57 +01:00
Juanpe Catalán f0cc7125ef feat: update readme 2018-12-11 11:20:44 +01:00
Juanpe Catalán f5b493d6f0 feat: Add bitrise in README file 2018-12-11 11:05:08 +01:00
Juanpe Catalán 48bc217413 feat: Update lane to create new version 2018-12-11 10:56:45 +01:00
Juanpe Catalán 516fcecce2 testing bitrise trigger 2018-12-11 10:41:51 +01:00
Juanpe Catalán 9052d5d806 feat: test bitrise 2018-12-11 09:44:15 +01:00
Juanpe Catalán 12dff52238 feat: remove useless code 2018-12-11 09:43:03 +01:00
Juanpe Catalán f0b4575de6 feat: Create fastfile 2018-12-11 09:42:09 +01:00
Juanpe Catalán 7be8ddd70a Merge pull request #114 from Juanpe/refactor_builder
feat: Create SkeletonLayerBuilder and SkeletonMultilineLayerBuilder
2018-12-10 20:48:49 +01:00
Juanpe Catalán a9628c0de8 feat: Create SkeletonLayerBuilder and SkeletonMultilineLayerBuilder 2018-12-10 20:04:07 +01:00
Juanpe Catalán 339191f016 feat: update changelog file 2018-12-10 19:34:33 +01:00
Juanpe Catalán 7022942d92 feat: Update Changelog file 2018-12-10 19:33:02 +01:00
Juanpe Catalán 03cf1bfea8 Merge pull request #113 from osterbergmarcus/patch-1
Adding swift news to mentioned section
2018-12-10 18:13:46 +01:00
Marcus Osterberg 9f46e7a647 Adding swift news to mentioned section 2018-12-06 19:31:12 +01:00
Juanpe Catalán 674cd1aa9f feat: Update README file to include swift 4.2 2018-10-04 16:15:40 +02:00
Juanpe Catalán 36a863b557 feat: Bump cocoapod version 2018-10-02 11:37:25 +02:00
Juanpe Catalán 3b83b85249 feat: Upgrade swift version 2018-10-02 11:33:55 +02:00
Juanpe Catalán afbb10d785 Update .travis.yml 2018-10-02 11:25:06 +02:00
Juanpe Catalán 99ccd1e640 Update .travis.yml 2018-10-02 11:15:02 +02:00
Juanpe Catalán e6834d1296 Merge pull request #99 from mohpor/master
Updated to Swift 4.2
2018-10-02 11:12:14 +02:00
Mohammad Porooshani 89cb6f4116 Updated to Swift 4.2
Signed-off-by: Mohammad Porooshani <porooshani@gmail.com>
2018-09-15 11:36:30 +04:30
Juanpe Catalán b74592e6be feat: Change guide image 2018-09-04 09:16:10 +02:00
Juanpe Catalán 5f79708f03 feat: Update thumbnail guide 2018-09-04 02:49:10 +02:00
Juanpe Catalán a83e1a00bf feat: Add guides section in README file 2018-09-04 00:52:14 +02:00
Juanpe Catalán 61e98b26ad Merge pull request #95 from arn00s/fix/demoProjectSettings
Fix/demo project settings
2018-08-20 23:48:30 +02:00
Arnaud 0ec754dfc5 use safe area for iPhone X 2018-08-20 17:22:09 +02:00
Arnaud 78b4b7b31c fix info.plist path 2018-08-20 17:17:51 +02:00
Juanpe Catalán e3ddc4fe98 Merge pull request #89 from brunomunizaf/translate-readme-brazil-portuguese
Translate readme file to Brazilian Portuguese
2018-08-13 11:23:34 +02:00
Bruno Muniz 13485e61f7 Translate readme file to Brazilian Portuguese 2018-08-13 11:11:23 +02:00
Juanpe Catalán 8f5d409304 feat: revert last changes in README file 2018-08-10 17:43:15 +02:00
Juanpe Catalán bc3258b8a2 feat: update README 2018-08-10 17:42:24 +02:00
Juanpe Catalán fd4683f555 Merge pull request #90 from Juanpe/debug_system
Debug system
2018-08-10 17:40:11 +02:00
Juanpe Catalán 97ebbcc917 feat: update README 2018-08-10 17:36:49 +02:00
Juanpe Catalán a02922dba6 feat: Update README file 2018-08-10 17:30:43 +02:00
Juanpe Catalán 4ac1abe50e feat: BUMP version 1.4 2018-08-10 17:28:31 +02:00
Juanpe Catalán 25e313850e feat: Update CHANGELOG file 2018-08-10 17:28:12 +02:00
Juanpe Catalán 88914f7816 feat: Update README file explaining debug mode 2018-08-10 17:10:49 +02:00
Juanpe Catalán 14ab00d13a feat: update README file 2018-08-10 14:23:48 +02:00
Juanpe Catalán 90b993a16b feat: Create skeletonHierarchy 2018-08-10 14:17:30 +02:00
Juanpe Catalán 413867718e feat: Improve recursive protocol 2018-08-10 13:23:24 +02:00
Juanpe Catalán e43b3f3750 feat: Add skeleton hierarchy 2018-08-10 08:27:51 +02:00
Juanpe Catalán b9b368b7e8 feat: Create Environment variable 2018-08-09 18:45:03 +02:00
Juanpe Catalán fc22d58f89 Merge pull request #87 from reececomo/alternate-user-interaction
#86 disableUserInteraction() on UIScrollView just to prevent scroll
2018-08-06 10:24:18 +02:00
Reece Como 8988b22784 style consistency 2018-08-06 11:09:20 +08:00
Reece Como 3cb1602e11 Merge https://github.com/Juanpe/SkeletonView into alternate-user-interaction 2018-08-06 11:08:31 +08:00
Reece Como 649672182e allow UIScrollViews to accept button taps 2018-08-06 10:58:10 +08:00
Juanpe Catalán 3c16416dbb feat: update README 2018-08-02 17:55:14 +02:00
Reece Como 0eff052314 Merge pull request #1 from reececomo/83-Customisable-Defaults
#83 Customisable Defaults
2018-08-02 16:32:39 +08:00
63 changed files with 1385 additions and 497 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ playground.xcworkspace
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
Pods/
# Carthage
#
+1 -1
View File
@@ -1 +1 @@
4.1
4.2
+4 -4
View File
@@ -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

+19
View File
@@ -1,6 +1,25 @@
# Change Log
All notable changes to this project will be documented in this file
## Next version
### New
- Adding swift news to mentioned section (thanks @osterbergmarcus)
## [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,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
-11
View File
@@ -1,11 +0,0 @@
//
// Constants.swift
// SkeletonView-iOS
//
// Created by Renato Mendes on 28/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
let colors = [(UIColor.turquoise,"turquoise"), (UIColor.emerald,"emerald"), (UIColor.peterRiver,"peterRiver"), (UIColor.amethyst,"amethyst"),(UIColor.wetAsphalt,"wetAsphalt"), (UIColor.nephritis,"nephritis"), (UIColor.belizeHole,"belizeHole"), (UIColor.wisteria,"wisteria"), (UIColor.midnightBlue,"midnightBlue"), (UIColor.sunFlower,"sunFlower"), (UIColor.carrot,"carrot"), (UIColor.alizarin,"alizarin"),(UIColor.clouds,"clouds"), (UIColor.concrete,"concrete"), (UIColor.flatOrange,"flatOrange"), (UIColor.pumpkin,"pumpkin"), (UIColor.pomegranate,"pomegranate"), (UIColor.silver,"silver"), (UIColor.asbestos,"asbestos")]
@@ -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
}

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 933 B

@@ -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,12 +1,5 @@
//
// 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")]
@@ -13,7 +13,7 @@ class ViewController: UIViewController {
@IBOutlet weak var tableview: UITableView! {
didSet {
tableview.rowHeight = UITableViewAutomaticDimension
tableview.rowHeight = UITableView.automaticDimension
tableview.estimatedRowHeight = 120.0
}
}
+3
View File
@@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "fastlane"
+159
View File
@@ -0,0 +1,159 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.0)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
atomos (0.1.3)
babosa (1.0.2)
claide (1.0.2)
colored (1.2)
colored2 (3.1.2)
commander-fastlane (4.4.6)
highline (~> 1.7.2)
declarative (0.0.10)
declarative-option (0.1.0)
digest-crc (0.4.1)
domain_name (0.5.20180417)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.5.0)
emoji_regex (0.1.1)
excon (0.62.0)
faraday (0.15.4)
multipart-post (>= 1.2, < 3)
faraday-cookie_jar (0.0.6)
faraday (>= 0.7.4)
http-cookie (~> 1.0.0)
faraday_middleware (0.12.2)
faraday (>= 0.7.4, < 1.0)
fastimage (2.1.5)
fastlane (2.110.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
babosa (>= 1.0.2, < 2.0.0)
bundler (>= 1.12.0, < 2.0.0)
colored
commander-fastlane (>= 4.4.6, < 5.0.0)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (~> 0.1)
excon (>= 0.45.0, < 1.0.0)
faraday (~> 0.9)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 0.9)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-api-client (>= 0.21.2, < 0.24.0)
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
multi_xml (~> 0.5)
multipart-post (~> 2.0.0)
plist (>= 3.1.0, < 4.0.0)
public_suffix (~> 2.0.0)
rubyzip (>= 1.2.2, < 2.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
slack-notifier (>= 2.0.0, < 3.0.0)
terminal-notifier (>= 1.6.2, < 2.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.6.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
google-api-client (0.23.9)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.5, < 0.7.0)
httpclient (>= 2.8.1, < 3.0)
mime-types (~> 3.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
signet (~> 0.9)
google-cloud-core (1.2.7)
google-cloud-env (~> 1.0)
google-cloud-env (1.0.5)
faraday (~> 0.11)
google-cloud-storage (1.15.0)
digest-crc (~> 0.4)
google-api-client (~> 0.23)
google-cloud-core (~> 1.2)
googleauth (~> 0.6.2)
googleauth (0.6.7)
faraday (~> 0.12)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.7)
highline (1.7.10)
http-cookie (1.0.3)
domain_name (~> 0.5)
httpclient (2.8.3)
json (2.1.0)
jwt (2.1.0)
memoist (0.16.0)
mime-types (3.2.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2018.0812)
mini_magick (4.5.1)
multi_json (1.13.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
nanaimo (0.2.6)
naturally (2.2.0)
os (1.0.0)
plist (3.4.0)
public_suffix (2.0.5)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rouge (2.0.7)
rubyzip (1.2.2)
security (0.1.3)
signet (0.11.0)
addressable (~> 2.3)
faraday (~> 0.9)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.5)
CFPropertyList
naturally
slack-notifier (2.3.2)
terminal-notifier (1.8.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
tty-cursor (0.6.0)
tty-screen (0.6.5)
tty-spinner (0.9.0)
tty-cursor (~> 0.6.0)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.5)
unicode-display_width (1.4.0)
word_wrap (1.0.0)
xcodeproj (1.7.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.2.6)
xcpretty (0.3.0)
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.0)
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
ruby
DEPENDENCIES
fastlane
BUNDLED WITH
1.16.2
+60 -22
View File
@@ -1,19 +1,17 @@
![](Assets/header2.jpg)
<p align="center">
<a href="https://travis-ci.org/Juanpe/SkeletonView">
<img src="https://img.shields.io/travis/Juanpe/SkeletonView.svg">
<a href="https://app.bitrise.io/app/6d289a17e22c8323">
<img src="https://app.bitrise.io/app/6d289a17e22c8323/status.svg?token=fI7gKC41XD9-aRXDScCKBw&branch=master">
</a>
<a href="https://instagram.github.io/IGListKit/">
<a href="https://codebeat.co/projects/github-com-juanpe-skeletonview-master"><img alt="codebeat badge" src="https://codebeat.co/badges/f854fdfd-31e5-4689-ba04-075d83653e60" /></a>
<a href="https://github.com/Juanpe/SkeletonView">
<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" />
<img src="https://img.shields.io/badge/Swift-4.2-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>
@@ -23,15 +21,15 @@
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=MJ4Y2D9DEX6FL&lc=ES&item_name=SkeletonView&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted">
<img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Paypal" />
</a>
<br/>
<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>
🌎 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.
@@ -40,8 +38,7 @@ Today almost all apps have async processes, such as Api requests, long running p
Enjoy it! 🙂
* [Features](#-features)
* [Requirements](#-supported-os--sdk-versions)
* [Example Project](#-example)
* [Guides](#-guides)
* [Installation](#-installation)
* [Cocoapods](#using-cocoapods)
* [Carthage](#using-carthage)
@@ -52,7 +49,9 @@ Enjoy it! 🙂
* [Appearance](#-appearance)
* [Custom animations](#-custom-animations)
* [Hierarchy](#-hierarchy)
* [Debug](#-debug)
* [Documentation](#-documentation)
* [Supported OS & SDK Versions](#-supported-os--sdk-versions)
* [Next steps](#-next-steps)
* [Contributing](#-contributing)
* [Mentions](#-mentions)
@@ -70,15 +69,9 @@ Enjoy it! 🙂
- [x] Simple Swift syntax
- [x] Lightweight readable codebase
### 📋 Supported OS & SDK Versions
## 🎬 Guides
* iOS 9.0+
* tvOS 9.0+
* Swift 4
### 🔮 Example
To run the example project, clone the repo and run `SkeletonViewExample` target.
[<img src="Assets/thumb_getting_started.png">](https://youtu.be/75kgOhWsPNA)
## 📲 Installation
@@ -280,11 +273,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,10 +359,41 @@ Because an image is worth a thousand words:
|![](Assets/all_skeletonables.png) | ![](Assets/all_skeletonables_result.png)
### 🔬 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:
![](Assets/debug_description.png)
Besides, you can activate the new **debug mode**. You just add the environment variable `SKELETON_DEBUG` and activate it.
![](Assets/debug_mode.png)
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...😅
### 📋 Supported OS & SDK Versions
* iOS 9.0+
* tvOS 9.0+
* Swift 4.2
## 📬 Next steps
* [x] Set the filling percent of the last line in multiline elements
@@ -367,6 +403,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
@@ -394,6 +431,7 @@ See [all contributors](https://github.com/Juanpe/SkeletonView/graphs/contributor
- [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)
- [Swift News #36](https://www.youtube.com/watch?v=mAGpsQiy6so)
+446
View File
@@ -0,0 +1,446 @@
![](Assets/header2.jpg)
<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.2-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&currency_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.2
### 🔮 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:**
![](Assets/storyboard.png)
**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
![](Assets/multilines2.png)
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%` | ![](Assets/multiline_lastline.png)
| **Corner radius** of lines. (**NEW**) | `0...10` | `0` | ![](Assets/multiline_corner.png)
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**:
![](Assets/multiline_customize.png)
### 🎨 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 ...```
![](Assets/flatcolors.png)
###### 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 | ![](Assets/sliding_left_to_right.gif)
| .rightLeft | ![](Assets/sliding_right_to_left.gif)
| .topBottom | ![](Assets/sliding_top_to_bottom.gif)
| .bottomTop | ![](Assets/sliding_bottom_to_top.gif)
| .topLeftBottomRight | ![](Assets/sliding_topLeft_to_bottomRight.gif)
| .bottomRightTopLeft | ![](Assets/sliding_bottomRight_to_topLeft.gif)
> **😉 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
|------- | -------
|![](Assets/no_skeletonable.png) | ![](Assets/no_skeletonables_result.png)
|![](Assets/container_no_skeletonable.png) | ![](Assets/no_skeletonables_result.png)
|![](Assets/container_skeletonable.png) | ![](Assets/container_skeletonable_result.png)
|![](Assets/all_skeletonables.png) | ![](Assets/all_skeletonables_result.png)
### 📚 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.
```
+5 -3
View File
@@ -7,7 +7,7 @@
<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" />
<img src="https://img.shields.io/badge/Swift-4.2-orange.svg" />
<a href="https://cocoapods.org/pods/SkeletonView">
<img src="https://img.shields.io/cocoapods/v/SkeletonView.svg" alt="CocoaPods" />
</a>
@@ -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请求、长时间运行的流程等。虽然流程正在运行,但通常开发人员会设置一个加载视图来向用户显示正在发生的事情。
@@ -73,7 +75,7 @@
* iOS 9.0+
* tvOS 9.0+
* Swift 4
* Swift 4.2
### 🔮 示例
+2 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SkeletonView"
s.version = "1.3"
s.version = "1.4.2"
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.
@@ -12,6 +12,7 @@ Pod::Spec.new do |s|
s.social_media_url = "https://twitter.com/JuanpeCatalan"
s.ios.deployment_target = "9.0"
s.tvos.deployment_target = "9.0"
s.swift_version = "4.2"
s.source = { :git => "https://github.com/Juanpe/SkeletonView.git", :tag => s.version.to_s }
s.source_files = "Sources/**/*"
end
+122 -49
View File
@@ -29,7 +29,6 @@
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 */; };
3B83EE4720C41488005178A4 /* ContainsMultilineText.swift in Headers */ = {isa = PBXBuildFile; fileRef = 3B83EE4520C41488005178A4 /* ContainsMultilineText.swift */; settings = {ATTRIBUTES = (Public, ); }; };
3B83EE4820C41488005178A4 /* UIView+IBInspectable.swift in Headers */ = {isa = PBXBuildFile; fileRef = 3B83EE4620C41488005178A4 /* UIView+IBInspectable.swift */; settings = {ATTRIBUTES = (Public, ); }; };
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, ); }; };
@@ -38,11 +37,22 @@
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 */; };
872D5A5621C177E20037D763 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872D5A5521C177E20037D763 /* UIView+Extension.swift */; };
872D5A5721C177E20037D763 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872D5A5521C177E20037D763 /* UIView+Extension.swift */; };
872D5A5C21C24EDD0037D763 /* UILabel+Multiline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872D5A5B21C24EDD0037D763 /* UILabel+Multiline.swift */; };
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 */; };
877EFA4821BEED760031FC00 /* SkeletonMultilineLayerBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877EFA4721BEED760031FC00 /* SkeletonMultilineLayerBuilder.swift */; };
877EFA4921BEED760031FC00 /* SkeletonMultilineLayerBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877EFA4721BEED760031FC00 /* SkeletonMultilineLayerBuilder.swift */; };
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 +81,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 */; };
@@ -134,7 +146,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>"; };
3B83EE4520C41488005178A4 /* ContainsMultilineText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ContainsMultilineText.swift; path = Sources/Helpers/ContainsMultilineText.swift; 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>"; };
@@ -142,10 +153,15 @@
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; };
872D5A5521C177E20037D763 /* UIView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extension.swift"; sourceTree = "<group>"; };
872D5A5B21C24EDD0037D763 /* UILabel+Multiline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Multiline.swift"; sourceTree = "<group>"; };
872D5A5E21C24F8E0037D763 /* UITextView+Multiline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+Multiline.swift"; sourceTree = "<group>"; };
877EFA4421BEE9D80031FC00 /* SkeletonLayerBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonLayerBuilder.swift; sourceTree = "<group>"; };
877EFA4721BEED760031FC00 /* SkeletonMultilineLayerBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonMultilineLayerBuilder.swift; sourceTree = "<group>"; };
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 +183,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>"; };
@@ -219,26 +236,10 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
42ABD06F210B54BC00BEEFF4 /* Example UICollectionView */ = {
isa = PBXGroup;
children = (
42ABD070210B54E100BEEFF4 /* AppDelegate.swift */,
42ABD072210B54E100BEEFF4 /* Assets.xcassets */,
42ABD074210B54E100BEEFF4 /* Base.lproj */,
42ABD077210B54E200BEEFF4 /* CollectionViewCell.swift */,
42ABD075210B54E100BEEFF4 /* Constants.swift */,
42ABD071210B54E100BEEFF4 /* Main.storyboard */,
42ABD073210B54E100BEEFF4 /* ViewController.swift */,
);
path = "Example UICollectionView";
sourceTree = "<group>";
};
52D6D9721BEFF229002C0205 = {
isa = PBXGroup;
children = (
3B83EE4520C41488005178A4 /* ContainsMultilineText.swift */,
3B83EE4620C41488005178A4 /* UIView+IBInspectable.swift */,
42ABD06F210B54BC00BEEFF4 /* Example UICollectionView */,
F5F899F31FABA607002E8FDA /* Example */,
8933C7811EB5B7E0000D00A4 /* Sources */,
52D6D99C1BEFF38C002C0205 /* Configs */,
@@ -267,15 +268,80 @@
path = Configs;
sourceTree = "<group>";
};
872D5A5821C17D850037D763 /* CollectionView */ = {
isa = PBXGroup;
children = (
42ABD070210B54E100BEEFF4 /* AppDelegate.swift */,
42ABD072210B54E100BEEFF4 /* Assets.xcassets */,
42ABD074210B54E100BEEFF4 /* Base.lproj */,
42ABD077210B54E200BEEFF4 /* CollectionViewCell.swift */,
42ABD071210B54E100BEEFF4 /* Main.storyboard */,
42ABD073210B54E100BEEFF4 /* ViewController.swift */,
);
path = CollectionView;
sourceTree = "<group>";
};
872D5A5921C17D980037D763 /* TableView */ = {
isa = PBXGroup;
children = (
F5F899F41FABA607002E8FDA /* AppDelegate.swift */,
88DEA97D1FCDBD1F006C80EF /* Constants.swift */,
F5F899F61FABA607002E8FDA /* ViewController.swift */,
F5F622441FACA338007C062A /* Cell.swift */,
F5F899F81FABA607002E8FDA /* Main.storyboard */,
F5F899FB1FABA607002E8FDA /* Assets.xcassets */,
F5F899FD1FABA607002E8FDA /* LaunchScreen.storyboard */,
);
path = TableView;
sourceTree = "<group>";
};
872D5A5A21C24E7C0037D763 /* Multilines */ = {
isa = PBXGroup;
children = (
F5307E3A1FB123C100EE67C5 /* ContainsMultilineText.swift */,
872D5A5B21C24EDD0037D763 /* UILabel+Multiline.swift */,
872D5A5E21C24F8E0037D763 /* UITextView+Multiline.swift */,
);
path = Multilines;
sourceTree = "<group>";
};
877EFA4321BEE9C40031FC00 /* Builders */ = {
isa = PBXGroup;
children = (
877EFA4421BEE9D80031FC00 /* SkeletonLayerBuilder.swift */,
877EFA4721BEED760031FC00 /* SkeletonMultilineLayerBuilder.swift */,
);
path = Builders;
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 = (
872D5A5A21C24E7C0037D763 /* Multilines */,
877EFA4321BEE9C40031FC00 /* Builders */,
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 */,
@@ -342,7 +408,9 @@
F5F622401FAC6E31007C062A /* UIColor+Skeleton.swift */,
F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */,
F5F899CF1FAA6A4D002E8FDA /* UIView+IBInspectable.swift */,
872D5A5521C177E20037D763 /* UIView+Extension.swift */,
F587FB85202CEC95002DB5FE /* UIView+UIApplicationDelegate.swift */,
F5A5E8B3211DCE7000FD20D0 /* Int+Whitespaces.swift */,
);
path = Extensions;
sourceTree = "<group>";
@@ -351,7 +419,6 @@
isa = PBXGroup;
children = (
F5F899D11FAB9630002E8FDA /* AssociationPolicy.swift */,
F5307E3A1FB123C100EE67C5 /* ContainsMultilineText.swift */,
F56B94451FAE20AF0095662F /* PrepareForSkeletonProtocol.swift */,
F5307E311FB0F42F00EE67C5 /* RecursiveProtocol.swift */,
);
@@ -370,13 +437,8 @@
F5F899F31FABA607002E8FDA /* Example */ = {
isa = PBXGroup;
children = (
F5F899F41FABA607002E8FDA /* AppDelegate.swift */,
88DEA97D1FCDBD1F006C80EF /* Constants.swift */,
F5F899F61FABA607002E8FDA /* ViewController.swift */,
F5F622441FACA338007C062A /* Cell.swift */,
F5F899F81FABA607002E8FDA /* Main.storyboard */,
F5F899FB1FABA607002E8FDA /* Assets.xcassets */,
F5F899FD1FABA607002E8FDA /* LaunchScreen.storyboard */,
872D5A5921C17D980037D763 /* TableView */,
872D5A5821C17D850037D763 /* CollectionView */,
);
path = Example;
sourceTree = "<group>";
@@ -413,7 +475,6 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
3B83EE4720C41488005178A4 /* ContainsMultilineText.swift in Headers */,
3B83EE4820C41488005178A4 /* UIView+IBInspectable.swift in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -502,7 +563,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0910;
LastUpgradeCheck = 0930;
LastUpgradeCheck = 1000;
ORGANIZATIONNAME = SkeletonView;
TargetAttributes = {
17DD0DFF207FB27400C56334 = {
@@ -510,17 +571,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 +618,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 */,
@@ -589,15 +648,19 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
872D5A5721C177E20037D763 /* UIView+Extension.swift in Sources */,
17DD0E1F207FB32100C56334 /* RecursiveProtocol.swift in Sources */,
872D5A5D21C24EDD0037D763 /* UILabel+Multiline.swift in Sources */,
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 */,
17DD0E0D207FB28900C56334 /* UITableView+CollectionSkeleton.swift in Sources */,
17DD0E0E207FB28900C56334 /* UIView+CollectionSkeleton.swift in Sources */,
877EFA4921BEED760031FC00 /* SkeletonMultilineLayerBuilder.swift in Sources */,
F51ED28320973CBB008B2434 /* SkeletonCollectionDelegate.swift in Sources */,
F58A6E6F20A8C66300612494 /* Recoverable.swift in Sources */,
17DD0E18207FB28F00C56334 /* SkeletonView.swift in Sources */,
@@ -610,10 +673,13 @@
17DD0E14207FB28F00C56334 /* SkeletonAnimationBuilder.swift in Sources */,
17DD0E11207FB28C00C56334 /* UIView+Frame.swift in Sources */,
17DD0E15207FB28F00C56334 /* SkeletonAppearance.swift in Sources */,
872D5A6021C24F8E0037D763 /* UITextView+Multiline.swift in Sources */,
17DD0E10207FB28C00C56334 /* UIColor+Skeleton.swift in Sources */,
F51ED28420973CC6008B2434 /* GenericCollectionView.swift in Sources */,
17DD0E0A207FB28900C56334 /* SkeletonCollectionViewProtocols.swift in Sources */,
17DD0E1C207FB32100C56334 /* AssociationPolicy.swift in Sources */,
877EFA4621BEE9D80031FC00 /* SkeletonLayerBuilder.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 +693,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;
};
@@ -635,15 +701,19 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
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 */,
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 */,
F5307E321FB0F42F00EE67C5 /* RecursiveProtocol.swift in Sources */,
F5F622431FAC81FD007C062A /* CALayer+Extensions.swift in Sources */,
877EFA4821BEED760031FC00 /* SkeletonMultilineLayerBuilder.swift in Sources */,
F5F899ED1FAB9F04002E8FDA /* CollectionSkeletonProtocol.swift in Sources */,
F58A6E6E20A8C66300612494 /* Recoverable.swift in Sources */,
F5307E2C1FAF6BC900EE67C5 /* SkeletonGradient.swift in Sources */,
@@ -656,10 +726,13 @@
F54CF5E62024CEB000330B0D /* UICollectionView+CollectionSkeleton.swift in Sources */,
F56B94461FAE20AF0095662F /* PrepareForSkeletonProtocol.swift in Sources */,
F5307E391FB1078E00EE67C5 /* SkeletonCollectionViewProtocols.swift in Sources */,
872D5A5F21C24F8E0037D763 /* UITextView+Multiline.swift in Sources */,
F51DF873206E91FB00D23301 /* GenericCollectionView.swift in Sources */,
F5307E3B1FB123C100EE67C5 /* ContainsMultilineText.swift in Sources */,
F5F899E91FAB9D2B002E8FDA /* SkeletonLayer.swift in Sources */,
F5307E2E1FB0E5E400EE67C5 /* UIView+Frame.swift in Sources */,
877EFA4521BEE9D80031FC00 /* SkeletonLayerBuilder.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 +811,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 +843,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 +862,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 +889,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 +1034,7 @@
PRODUCT_NAME = SkeletonView;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
};
name = Debug;
};
@@ -985,7 +1058,7 @@
PRODUCT_NAME = SkeletonView;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
};
name = Release;
};
@@ -1001,7 +1074,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 +1082,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 +1099,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 +1107,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"
-45
View File
@@ -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>
@@ -15,6 +15,7 @@ public enum SkeletonAppearance {
public static var `default`: Appearance = SkeletonViewAppearance.shared
}
// codebeat:disable[TOO_MANY_IVARS]
class SkeletonViewAppearance: Appearance {
static var shared = SkeletonViewAppearance()
@@ -31,3 +32,4 @@ class SkeletonViewAppearance: Appearance {
var multilineCornerRadius: Int = 0
}
// codebeat:enable[TOO_MANY_IVARS]
@@ -0,0 +1,41 @@
// Copyright © 2018 SkeletonView. All rights reserved.
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?
func setSkeletonType(_ type: SkeletonType) -> SkeletonLayerBuilder {
self.skeletonType = type
return self
}
func addColor(_ color: UIColor) -> SkeletonLayerBuilder {
return addColors([color])
}
func addColors(_ colors: [UIColor]) -> SkeletonLayerBuilder {
self.colors.append(contentsOf: colors)
return self
}
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)
}
}
@@ -0,0 +1,52 @@
// Copyright © 2018 SkeletonView. All rights reserved.
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?
var cornerRadius: Int?
func setSkeletonType(_ type: SkeletonType) -> SkeletonMultilineLayerBuilder {
self.skeletonType = type
return self
}
func setIndex(_ index: Int) -> SkeletonMultilineLayerBuilder {
self.index = index
return self
}
func setWidth(_ width: CGFloat) -> SkeletonMultilineLayerBuilder {
self.width = width
return self
}
func setCornerRadius(_ radius: Int) -> SkeletonMultilineLayerBuilder {
self.cornerRadius = radius
return self
}
func build() -> CALayer? {
guard let type = skeletonType,
let index = index,
let width = width,
let radius = cornerRadius
else { return nil }
let spaceRequiredForEachLine = SkeletonAppearance.default.multilineHeight + SkeletonAppearance.default.multilineSpacing
let layer = type.layer
layer.anchorPoint = .zero
layer.name = CALayer.skeletonSubLayersName
layer.frame = CGRect(x: 0.0, y: CGFloat(index) * spaceRequiredForEachLine, width: width, height: SkeletonAppearance.default.multilineHeight)
layer.cornerRadius = CGFloat(radius)
layer.masksToBounds = true
return layer
}
}
@@ -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 }
}
@@ -16,17 +16,17 @@ extension UICollectionView: CollectionSkeleton {
}
var skeletonDataSource: SkeletonCollectionDataSource? {
get { return objc_getAssociatedObject(self, &CollectionAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
get { return ao_get(pkey: &CollectionAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
set {
objc_setAssociatedObject(self, &CollectionAssociatedKeys.dummyDataSource, newValue, AssociationPolicy.retain.objc)
ao_setOptional(newValue, pkey: &CollectionAssociatedKeys.dummyDataSource)
self.dataSource = newValue
}
}
var skeletonDelegate: SkeletonCollectionDelegate? {
get { return objc_getAssociatedObject(self, &CollectionAssociatedKeys.dummyDelegate) as? SkeletonCollectionDelegate }
get { return ao_get(pkey: &CollectionAssociatedKeys.dummyDelegate) as? SkeletonCollectionDelegate }
set {
objc_setAssociatedObject(self, &CollectionAssociatedKeys.dummyDelegate, newValue, AssociationPolicy.retain.objc)
ao_setOptional(newValue, pkey: &CollectionAssociatedKeys.dummyDelegate)
self.delegate = newValue
}
}
@@ -15,17 +15,17 @@ extension UITableView: CollectionSkeleton {
}
var skeletonDataSource: SkeletonCollectionDataSource? {
get { return objc_getAssociatedObject(self, &CollectionAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
get { return ao_get(pkey: &CollectionAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
set {
objc_setAssociatedObject(self, &CollectionAssociatedKeys.dummyDataSource, newValue, AssociationPolicy.retain.objc)
ao_setOptional(newValue, pkey: &CollectionAssociatedKeys.dummyDataSource)
self.dataSource = newValue
}
}
var skeletonDelegate: SkeletonCollectionDelegate? {
get { return objc_getAssociatedObject(self, &CollectionAssociatedKeys.dummyDelegate) as? SkeletonCollectionDelegate }
get { return ao_get(pkey: &CollectionAssociatedKeys.dummyDelegate) as? SkeletonCollectionDelegate }
set {
objc_setAssociatedObject(self, &CollectionAssociatedKeys.dummyDelegate, newValue, AssociationPolicy.retain.objc)
ao_setOptional(newValue, pkey: &CollectionAssociatedKeys.dummyDelegate)
self.delegate = newValue
}
}
@@ -34,7 +34,9 @@ extension UITableView: CollectionSkeleton {
guard let originalDataSource = self.dataSource as? SkeletonTableViewDataSource,
!(originalDataSource is SkeletonCollectionDataSource)
else { return }
let dataSource = SkeletonCollectionDataSource(tableViewDataSource: originalDataSource, rowHeight: calculateRowHeight())
let rowHeight = calculateRowHeight()
let dataSource = SkeletonCollectionDataSource(tableViewDataSource: originalDataSource,
rowHeight: rowHeight)
self.skeletonDataSource = dataSource
reloadData()
}
@@ -53,7 +55,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
}
+50
View File
@@ -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
}
}
+33 -21
View File
@@ -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)
}
}
}
@@ -38,15 +40,23 @@ extension CALayer {
func addMultilinesLayers(lines: Int, type: SkeletonType, lastLineFillPercent: Int, multilineCornerRadius: Int) {
let numberOfSublayers = calculateNumLines(maxLines: lines)
for index in 0..<numberOfSublayers {
let layerBuilder = SkeletonMultilineLayerBuilder()
.setSkeletonType(type)
.setCornerRadius(multilineCornerRadius)
(0..<numberOfSublayers).forEach { index in
var width = bounds.width
if index == numberOfSublayers-1 && numberOfSublayers != 1 {
width = width * CGFloat(lastLineFillPercent)/100;
if index == numberOfSublayers - 1 && numberOfSublayers != 1 {
width = width * CGFloat(lastLineFillPercent) / 100;
}
if let layer = layerBuilder
.setIndex(index)
.setWidth(width)
.build() {
addSublayer(layer)
}
let layer = SkeletonLayerFactory().makeMultilineLayer(withType: type, for: index, width: width, multilineCornerRadius: multilineCornerRadius)
addSublayer(layer)
}
}
@@ -66,7 +76,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 +94,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)
}
}
}
+14
View File
@@ -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)
}
}
+3 -9
View File
@@ -1,13 +1,8 @@
//
// UIColor+Skeleton.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 03/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
// codebeat:disable[TOO_MANY_IVARS]
extension UIColor {
convenience init(_ hex: UInt) {
@@ -20,9 +15,8 @@ extension UIColor {
}
func isLight() -> Bool {
// algorithm from: http://www.w3.org/WAI/ER/WD-AERT/#color-contrast
guard let components = cgColor.components,
components.count >= 3 else { return false }
components.count >= 3 else { return false }
let brightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000
return !(brightness < 0.5)
}
@@ -72,4 +66,4 @@ public extension UIColor {
static var silver = UIColor(0xbdc3c7)
static var asbestos = UIColor(0x7f8c8d)
}
// codebeat:enable[TOO_MANY_IVARS]
+42
View File
@@ -0,0 +1,42 @@
// Copyright © 2018 SkeletonView. All rights reserved.
import UIKit
// codebeat:disable[TOO_MANY_IVARS]
enum ViewAssociatedKeys {
static var skeletonable = "skeletonable"
static var status = "status"
static var skeletonLayer = "layer"
static var flowDelegate = "flowDelegate"
static var isSkeletonAnimated = "isSkeletonAnimated"
static var viewState = "viewState"
}
// codebeat:enable[TOO_MANY_IVARS]
extension UIView {
enum Status {
case on
case off
}
var flowDelegate: SkeletonFlowDelegate? {
get { return ao_get(pkey: &ViewAssociatedKeys.flowDelegate) as? SkeletonFlowDelegate }
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.flowDelegate) }
}
var skeletonLayer: SkeletonLayer? {
get { return ao_get(pkey: &ViewAssociatedKeys.skeletonLayer) as? SkeletonLayer }
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.skeletonLayer) }
}
var status: Status! {
get { return ao_get(pkey: &ViewAssociatedKeys.status) as? Status ?? .off }
set { ao_set(newValue, pkey: &ViewAssociatedKeys.status) }
}
var skeletonIsAnimated: Bool! {
get { return ao_get(pkey: &ViewAssociatedKeys.isSkeletonAnimated) as? Bool ?? false }
set { ao_set(newValue, pkey: &ViewAssociatedKeys.isSkeletonAnimated) }
}
}
+2 -2
View File
@@ -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)
}
+2 -50
View File
@@ -1,22 +1,7 @@
//
// UIView+IBInspectable.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 01/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
private enum AssociatedKeys {
static var skeletonable = "skeletonable"
static var status = "status"
static var skeletonLayer = "layer"
static var flowDelegate = "flowDelegate"
static var isSkeletonAnimated = "isSkeletonAnimated"
static var viewState = "viewState"
}
public extension UIView {
@IBInspectable
@@ -28,43 +13,10 @@ public extension UIView {
var isSkeletonActive: Bool {
return status == .on || (subviewsSkeletonables.first(where: { $0.isSkeletonActive }) != nil)
}
}
extension UIView {
enum Status {
case on
case off
}
var flowDelegate: SkeletonFlowDelegate? {
get { return objc_getAssociatedObject(self, &AssociatedKeys.flowDelegate) as? SkeletonFlowDelegate }
set { objc_setAssociatedObject(self, &AssociatedKeys.flowDelegate, newValue, AssociationPolicy.retain.objc) }
}
var skeletonLayer: SkeletonLayer? {
get { return objc_getAssociatedObject(self, &AssociatedKeys.skeletonLayer) as? SkeletonLayer }
set { objc_setAssociatedObject(self, &AssociatedKeys.skeletonLayer, newValue, AssociationPolicy.retain.objc) }
}
var status: Status! {
get { return objc_getAssociatedObject(self, &AssociatedKeys.status) as? Status ?? .off }
set { objc_setAssociatedObject(self, &AssociatedKeys.status, newValue, AssociationPolicy.retain.objc) }
}
var viewState: RecoverableViewState? {
get { return objc_getAssociatedObject(self, &AssociatedKeys.viewState) as? RecoverableViewState }
set { objc_setAssociatedObject(self, &AssociatedKeys.viewState, newValue, AssociationPolicy.retain.objc) }
}
var skeletonIsAnimated: Bool! {
get { return objc_getAssociatedObject(self, &AssociatedKeys.isSkeletonAnimated) as? Bool ?? false }
set { objc_setAssociatedObject(self, &AssociatedKeys.isSkeletonAnimated, newValue, AssociationPolicy.retain.objc) }
}
fileprivate var skeletonable: Bool! {
get { return objc_getAssociatedObject(self, &AssociatedKeys.skeletonable) as? Bool ?? false }
set { objc_setAssociatedObject(self, &AssociatedKeys.skeletonable, newValue, AssociationPolicy.retain.objc) }
get { return ao_get(pkey: &ViewAssociatedKeys.skeletonable) as? Bool ?? false }
set { ao_set(newValue, pkey: &ViewAssociatedKeys.skeletonable) }
}
}
@@ -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"
}
+29 -6
View File
@@ -1,10 +1,4 @@
//
// AssociationPolicy.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 02/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import Foundation
@@ -21,3 +15,32 @@ enum AssociationPolicy: UInt {
return objc_AssociationPolicy(rawValue: rawValue)!
}
}
protocol AssociatedObjects: class { }
// transparent wrappers
extension AssociatedObjects {
/// wrapper around `objc_getAssociatedObject`
func ao_get(pkey: UnsafeRawPointer) -> Any? {
return objc_getAssociatedObject(self, pkey)
}
/// wrapper around `objc_setAssociatedObject`
func ao_setOptional(_ value: Any?, pkey: UnsafeRawPointer, policy: AssociationPolicy = .retainNonatomic) {
guard let value = value else { return }
objc_setAssociatedObject(self, pkey, value, policy.objc)
}
/// wrapper around `objc_setAssociatedObject`
func ao_set(_ value: Any, pkey: UnsafeRawPointer, policy: AssociationPolicy = .retainNonatomic) {
objc_setAssociatedObject(self, pkey, value, policy.objc)
}
/// wrapper around 'objc_removeAssociatedObjects'
func ao_removeAll() {
objc_removeAssociatedObjects(self)
}
}
extension NSObject: AssociatedObjects { }
@@ -1,82 +0,0 @@
//
// ContainsMultilineText.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 07/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
private enum AssociatedKeys {
static var lastLineFillingPercent = "lastLineFillingPercent"
static var multilineCornerRadius = "multilineCornerRadius"
}
protocol ContainsMultilineText {
var numLines: Int { get }
var lastLineFillingPercent: Int { get }
var multilineCornerRadius: Int { get }
}
extension ContainsMultilineText {
var numLines: Int { return 0 }
}
public extension UILabel {
@IBInspectable
var lastLineFillPercent: Int {
get { return lastLineFillingPercent }
set { lastLineFillingPercent = min(newValue, 100) }
}
@IBInspectable
var linesCornerRadius: Int {
get { return multilineCornerRadius }
set { multilineCornerRadius = min(newValue, 10) }
}
}
public extension UITextView {
@IBInspectable
var lastLineFillPercent: Int {
get { return lastLineFillingPercent }
set { lastLineFillingPercent = min(newValue, 100) }
}
@IBInspectable
var linesCornerRadius: Int {
get { return multilineCornerRadius }
set { multilineCornerRadius = min(newValue, 10) }
}
}
extension UILabel: ContainsMultilineText {
var numLines: Int {
return numberOfLines
}
var lastLineFillingPercent: Int {
get { return objc_getAssociatedObject(self, &AssociatedKeys.lastLineFillingPercent) as? Int ?? SkeletonAppearance.default.multilineLastLineFillPercent }
set { objc_setAssociatedObject(self, &AssociatedKeys.lastLineFillingPercent, newValue, AssociationPolicy.retain.objc) }
}
var multilineCornerRadius: Int {
get { return objc_getAssociatedObject(self, &AssociatedKeys.multilineCornerRadius) as? Int ?? SkeletonAppearance.default.multilineCornerRadius }
set { objc_setAssociatedObject(self, &AssociatedKeys.multilineCornerRadius, newValue, AssociationPolicy.retain.objc) }
}
}
extension UITextView: ContainsMultilineText {
var lastLineFillingPercent: Int {
get { return objc_getAssociatedObject(self, &AssociatedKeys.lastLineFillingPercent) as? Int ?? SkeletonAppearance.default.multilineLastLineFillPercent }
set { objc_setAssociatedObject(self, &AssociatedKeys.lastLineFillingPercent, newValue, AssociationPolicy.retain.objc) }
}
var multilineCornerRadius: Int {
get { return objc_getAssociatedObject(self, &AssociatedKeys.multilineCornerRadius) as? Int ?? SkeletonAppearance.default.multilineCornerRadius }
set { objc_setAssociatedObject(self, &AssociatedKeys.multilineCornerRadius, newValue, AssociationPolicy.retain.objc) }
}
}
+10 -19
View File
@@ -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
}
@@ -0,0 +1,18 @@
// Copyright © 2017 SkeletonView. All rights reserved.
import UIKit
enum MultilineAssociatedKeys {
static var lastLineFillingPercent = "lastLineFillingPercent"
static var multilineCornerRadius = "multilineCornerRadius"
}
protocol ContainsMultilineText {
var numLines: Int { get }
var lastLineFillingPercent: Int { get }
var multilineCornerRadius: Int { get }
}
extension ContainsMultilineText {
var numLines: Int { return 0 }
}
@@ -0,0 +1,32 @@
// Copyright © 2018 SkeletonView. All rights reserved.
import UIKit
public extension UILabel {
@IBInspectable
var lastLineFillPercent: Int {
get { return lastLineFillingPercent }
set { lastLineFillingPercent = min(newValue, 100) }
}
@IBInspectable
var linesCornerRadius: Int {
get { return multilineCornerRadius }
set { multilineCornerRadius = min(newValue, 10) }
}
}
extension UILabel: ContainsMultilineText {
var numLines: Int {
return numberOfLines
}
var lastLineFillingPercent: Int {
get { return ao_get(pkey: &MultilineAssociatedKeys.lastLineFillingPercent) as? Int ?? SkeletonAppearance.default.multilineLastLineFillPercent }
set { ao_set(newValue, pkey: &MultilineAssociatedKeys.lastLineFillingPercent) }
}
var multilineCornerRadius: Int {
get { return ao_get(pkey: &MultilineAssociatedKeys.multilineCornerRadius) as? Int ?? SkeletonAppearance.default.multilineCornerRadius }
set { ao_set(newValue, pkey: &MultilineAssociatedKeys.multilineCornerRadius) }
}
}
@@ -0,0 +1,36 @@
// Copyright © 2018 SkeletonView. All rights reserved.
import UIKit
public extension UITextView {
@IBInspectable
var lastLineFillPercent: Int {
get { return lastLineFillingPercent }
set { lastLineFillingPercent = min(newValue, 100) }
}
@IBInspectable
var linesCornerRadius: Int {
get { return multilineCornerRadius }
set { multilineCornerRadius = min(newValue, 10) }
}
}
extension UITextView: ContainsMultilineText {
var lastLineFillingPercent: Int {
get {
let defaultValue = SkeletonAppearance.default.multilineLastLineFillPercent
return ao_get(pkey: &MultilineAssociatedKeys.lastLineFillingPercent) as? Int ?? defaultValue
}
set { ao_set(newValue, pkey: &MultilineAssociatedKeys.lastLineFillingPercent) }
}
var multilineCornerRadius: Int {
get {
let defaultValue = SkeletonAppearance.default.multilineCornerRadius
return ao_get(pkey: &MultilineAssociatedKeys.multilineCornerRadius) as? Int ?? defaultValue
}
set { ao_set(newValue, pkey: &MultilineAssociatedKeys.multilineCornerRadius) }
}
}
+5
View File
@@ -15,6 +15,11 @@ protocol Recoverable {
}
extension UIView: Recoverable {
var viewState: RecoverableViewState? {
get { return ao_get(pkey: &ViewAssociatedKeys.viewState) as? RecoverableViewState }
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.viewState) }
}
@objc func saveViewState() {
viewState = RecoverableViewState(view: self)
+4 -2
View File
@@ -21,7 +21,8 @@ public enum GradientDirection {
public func slidingAnimation(duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation {
return SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: self, duration: duration)
}
// codebeat:disable[ABC]
var startPoint: GradientAnimationPoint {
switch self {
case .leftRight:
@@ -55,6 +56,7 @@ public enum GradientDirection {
return ( from: CGPoint(x:2, y:2), to: CGPoint(x:0, y:0))
}
}
// codebeat:enable[ABC]
}
public class SkeletonAnimationBuilder {
@@ -76,7 +78,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
+10 -7
View File
@@ -1,26 +1,29 @@
//
// 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
}
}
-20
View File
@@ -8,26 +8,6 @@
import UIKit
class SkeletonLayerFactory {
func makeSkeletonLayer(withType type: SkeletonType, usingColors colors: [UIColor], andHolder holder: UIView) -> SkeletonLayer {
return SkeletonLayer(withType: type, usingColors: colors, andSkeletonHolder: holder)
}
func makeMultilineLayer(withType type: SkeletonType, for index: Int, width: CGFloat, multilineCornerRadius: Int) -> CALayer {
let spaceRequiredForEachLine = SkeletonAppearance.default.multilineHeight + SkeletonAppearance.default.multilineSpacing
let layer = type.layer
layer.anchorPoint = .zero
layer.name = CALayer.skeletonSubLayersName
layer.frame = CGRect(x: 0.0, y: CGFloat(index) * spaceRequiredForEachLine, width: width, height: SkeletonAppearance.default.multilineHeight)
layer.cornerRadius = CGFloat(multilineCornerRadius)
layer.masksToBounds = true
return layer
}
}
public typealias SkeletonLayerAnimation = (CALayer) -> CAAnimation
public enum SkeletonType {
+42 -31
View File
@@ -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) {
removeDummyDataSourceIfNeeded()
fileprivate func recursiveHideSkeleton(reloadDataAfter reload: Bool, root: UIView? = nil) {
removeDummyDataSourceIfNeeded(reloadAfter: reload)
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 {
@@ -95,9 +99,16 @@ extension UIView {
extension UIView {
func addSkeletonLayer(withType type: SkeletonType, usingColors colors: [UIColor], gradientDirection direction: GradientDirection? = nil, animated: Bool, animation: SkeletonLayerAnimation? = nil) {
self.skeletonLayer = SkeletonLayerFactory().makeSkeletonLayer(withType: type, usingColors: colors, andHolder: self)
layer.insertSublayer(skeletonLayer!.contentLayer, at: UInt32.max)
if animated { skeletonLayer!.start(animation) }
guard let skeletonLayer = SkeletonLayerBuilder()
.setSkeletonType(type)
.addColors(colors)
.setHolder(self)
.build()
else { return }
self.skeletonLayer = skeletonLayer
layer.insertSublayer(skeletonLayer.contentLayer, at: UInt32.max)
if animated { skeletonLayer.start(animation) }
status = .on
}
+20 -17
View File
@@ -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
}
}
+13
View File
@@ -0,0 +1,13 @@
default_platform(:ios)
podspec_name = "SkeletonView.podspec"
lane :release_current do
version = version_get_podspec(path: @podspec_name)
if git_tag_exists(tag: version)
UI.user_error!("The tag #{version} already exists on the repo. To release a new version of the library bump the version on #{@podspec_name}")
end
pod_lib_lint
add_git_tag(tag: "#{version}")
push_git_tags
pod_push
end
+28
View File
@@ -0,0 +1,28 @@
fastlane documentation
================
# Installation
Make sure you have the latest version of the Xcode command line tools installed:
```
xcode-select --install
```
Install _fastlane_ using
```
[sudo] gem install fastlane -NV
```
or alternatively using `brew cask install fastlane`
# Available Actions
### release_current
```
fastlane release_current
```
----
This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).