Compare commits

...

51 Commits

Author SHA1 Message Date
Juanpe Catalán 2edd715a87 Fix skeleton flow notifications triggered multiple times (#476)
* Fix notification names

* Fix problem with multiple notifications
2022-01-07 16:55:19 +01:00
Juanpe f3cc8f0aba Bump version 1.26.0 2021-11-23 10:41:10 +00:00
Juanpe Catalán a9c22f502a Improve multiline height calculation (#466)
* update line height logic

* update property name

* update README

* update README

* Update README.md

* fix typo
2021-11-23 11:25:59 +01:00
Juanpe ee17db61c6 Bump version 1.25.2 2021-10-21 14:49:00 +00:00
Sharma Elanthiraiyan ff1a7e299b Vertically center align UILabel's skeleton. (#456)
- Introduce `shouldCenterTextVertically`  in `SkeletonTextNode` to center align UILabels and keep UITextViews unaltered.
- Shift down CALayers after assigning frames in `updateMultilinesLayers` function in `CALayer+Extensions.swift`
2021-10-21 16:47:42 +02:00
Juanpe Catalán 4994907234 Update README.md 2021-10-20 09:39:41 +02:00
Juanpe 17fb1b9950 Bump version 1.25.1 2021-09-14 05:58:22 +00:00
Juanpe Catalán 138dc8bf82 Update CD.yml 2021-09-14 07:55:33 +02:00
Juanpe Catalán 0b308f5ef5 Update release.yml 2021-09-14 07:52:13 +02:00
Sharma Elanthiraiyan af94b7e30b Global setter for useFontLineHeight (#454)
- Add useFontLineHeight to SkeletonViewAppearance.
- Update README file to include useFontLineHeight under SkeletonAppearance.
2021-09-14 07:14:50 +02:00
Juanpe 14c138ec3e Bump version 1.25.0 2021-09-09 07:46:08 +00:00
Sharma Elanthiraiyan 2691572392 Apply lastLineFillPercent for single line views as well. (#449)
* Apply lastLineFillPercent for single line views as well.
Fixes #430

* Update readme to include single_lastline.png

* Remove singleline_lastline.png asset added to demo last line in single line views.

* Simplify lastLineFillPercent related update in readme file.

* Fix grammar in readme.
2021-09-09 09:39:26 +02:00
Juanpe 1b9586e2d7 Bump version 1.24.4 2021-08-23 12:00:05 +00:00
Juanpe Catalán a819e69cee make skeletonPaddingInsets public again (#446) 2021-08-23 13:58:33 +02:00
Juanpe 88cd082d8e Bump version 1.24.3 2021-08-23 10:36:24 +00:00
Juanpe Catalán 1ab26cd869 Merge branch 'main' of https://github.com/Juanpe/SkeletonView 2021-08-23 12:29:16 +02:00
Juanpe Catalán 8e369c9df2 fix build fails 2021-08-23 12:29:01 +02:00
Juanpe 5fc720d3ab Bump version 1.24.2 2021-08-23 10:24:52 +00:00
Juanpe Catalán 34ce9365f6 Update main.yml 2021-08-23 12:22:06 +02:00
Juanpe Catalán 3708c0da7f Improve debug description and create SkeletonExtensions (#444)
* create sk extension and improve debug

* update README

* fix readme

* Update README.md

* include SkeletonTreeNode
2021-08-23 12:20:47 +02:00
Juanpe 9103c14cc5 Bump version 1.24.0 2021-08-19 15:48:14 +00:00
Juanpe Catalán 5ce17f7a40 Add new property useFontLineHeight to disable the auto-adjustment (#443) 2021-08-19 17:46:59 +02:00
Juanpe dfc2d60daa Bump version 1.23.1 2021-08-19 12:48:19 +00:00
Juanpe Catalán d8436f79f6 Codebase refactor (#442)
* files reorganization (#432)

* fix podspec

* only include swift files

* Fix broken readme paths (#433)

* update links

* fix french link

* split skeleton debug to public and internal methods (#434)

* Add build phase to execute SwiftLint (#435)

* update tvOS tests

* Refactor Extensions folder (#436)

* Reorganize SkeletonAppearance (#437)

* reorganize helpers and builders folders (#438)

* Refactor flow and multilines (#439)

* Reorganize collections folder (#440)

* reorganize collections folder

* update podspec

* Refactor SkeletonView facade (#441)

* reorganize collections folder

* update podspec

* refactor skeletonview facade

* fix conflict

* update iOS example

* fix github workflows

* update tvOS example project build settings
2021-08-19 14:45:33 +02:00
Juanpe 35db69e513 Bump version 1.23.0 2021-08-19 06:15:26 +00:00
ankitagarwal007 6b5002b9a7 Use fontLine for skeleton in labels (#427)
Co-authored-by: Ankit Agarwal <ankit.agarwal@naukri.com>
2021-08-19 08:04:01 +02:00
Juanpe 2d9f3192d3 Bump version 1.22.0 2021-08-17 17:08:39 +00:00
Sofia Silva ae44d9f07a Align last line of skeleton view according to text alignment (#431)
* feature: align last line of skeleton view according to text alignment

* code review changes
2021-08-17 19:03:13 +02:00
Juanpe Catalán 25c47d3029 update file header 2021-08-02 19:10:46 +02:00
Juanpe 11c90283ff Bump version 1.21.2 2021-07-23 13:54:10 +00:00
Juanpe Catalán 49fafccd3f set status off before the transition is finished (#423) 2021-07-23 15:52:52 +02:00
Juanpe 1f70ee4573 Bump version 1.21.1 2021-07-13 11:51:26 +00:00
dependabot[bot] d13369a0dd Bump addressable from 2.6.0 to 2.8.0 (#420)
Bumps [addressable](https://github.com/sporkmonger/addressable) from 2.6.0 to 2.8.0.
- [Release notes](https://github.com/sporkmonger/addressable/releases)
- [Changelog](https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sporkmonger/addressable/compare/addressable-2.6.0...addressable-2.8.0)

---
updated-dependencies:
- dependency-name: addressable
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-13 13:50:06 +02:00
Juanpe Catalán 35d63041d2 Update README.md 2021-07-05 20:01:41 +02:00
Juanpe 4514b509cc Bump version 1.21.0 2021-07-02 14:10:57 +00:00
Guglielmo Faglioni 795fd7d0f1 Fallback to non-skeleton Header (#416)
Sometimes my collectionview's header doesn't need to be 'skeletoned' while the content does.  

When  collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -> ReusableCellIdentifier? returns nil, it's best if we fallback to the non-skeleton header.
2021-07-02 16:05:16 +02:00
Juanpe Catalán 6cc6f5aa80 Update README.md 2021-06-29 11:08:52 +02:00
Juanpe Catalán 3ecc3c3b39 Update README.md 2021-06-29 11:06:05 +02:00
Juanpe Catalán 511535921f Update README.md 2021-06-29 11:05:20 +02:00
Juanpe a6d1ae0b95 Bump version 1.20.0 2021-06-28 15:47:21 +00:00
Juanpe Catalán 220fc4016d Fixed background color warning in UITableViewHeaderFooterView (#417) 2021-06-28 17:45:59 +02:00
Juanpe Catalán ee94dd8aec Update README.md 2021-06-24 16:00:38 +02:00
Juanpe Catalán be2aa4f4ab create CD workflow 2021-06-24 13:26:25 +02:00
Juanpe 55f16d9d51 Bump version 1.19.0 2021-06-24 06:21:47 +00:00
Nemanja Markicevic 9fccaf4fbd Add prepareCellForSkeleton for UITableView and UICollectionView (#415)
* Add prepareCellForSkeleton for UITableView and UICollectionView

* Update README to add collectionSkeletonView(_ skeletonView: UICollectionView, prepareCellForSkeleton cell: UICollectionViewCell, at indexPath: IndexPath)

* Update README.md

Co-authored-by: Juanpe Catalán <juanpecm@gmail.com>
2021-06-24 08:09:36 +02:00
Juanpe Catalán 58959a5f9b Add both skeletonCellForRowAt and skeletonCellForItemAt methods (#414)
* add skeletonCellForIndexPath

* included in README file the new data source methods

* fix typo in the README file
2021-06-23 17:49:31 +02:00
Juanpe Catalán 5838f7881b update README 2021-06-22 13:09:46 +02:00
Juanpe 41173471f6 Bump version 1.18.0 2021-06-22 10:59:04 +00:00
Juanpe Catalán 12e5688b31 Delay the presentation of the skeletons (#411) 2021-06-22 12:54:33 +02:00
Juanpe Catalán 816b2965ff Improved the algorithm that calculates the number of skeleton lines for UITextViews (#410) 2021-06-22 11:23:08 +02:00
Juanpe e12e4a0fd1 Bump version 1.17.2 2021-06-11 20:24:41 +00:00
166 changed files with 5258 additions and 2738 deletions
+64
View File
@@ -0,0 +1,64 @@
name: CD
on:
pull_request_target:
branches: [main]
types: [closed]
jobs:
release_version:
if: github.event.pull_request.milestone == null && github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup fastlane
run: brew install fastlane
- name: Publish release
id: publish_release
uses: release-drafter/release-drafter@v5
with:
publish: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update podspec
run: fastlane bump_version next_version:${{ steps.publish_release.outputs.tag_name }}
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
branch: 'main'
commit_message: 'Bump version ${{ steps.publish_release.outputs.tag_name }}'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Cocoapods
env:
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
run: |
set -eo pipefail
pod lib lint --allow-warnings
pod trunk push --allow-warnings
- name: Communicate on PR released
uses: unsplash/comment-on-pr@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
msg: |
Congratulations! 🎉 This was released as part of [SkeletonView ${{ steps.publish_release.outputs.tag_name }}](${{ steps.publish_release.outputs.html_url }}) 🚀
- name: Tweet the release
uses: ethomson/send-tweet-action@v1
with:
consumer-key: ${{ secrets.TWITTER_CONSUMER_API_KEY }}
consumer-secret: ${{ secrets.TWITTER_CONSUMER_API_SECRET }}
access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }}
access-token-secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
status: |
🎉 New release ${{ steps.publish_release.outputs.tag_name }} is out 🚀
Check out all the changes here:
${{ steps.publish_release.outputs.html_url }}
+7 -4
View File
@@ -3,6 +3,7 @@ name: CI
on:
pull_request:
branches: [main]
workflow_dispatch:
jobs:
build:
@@ -10,10 +11,12 @@ jobs:
strategy:
matrix:
build-config:
- { target: 'SkeletonView-iOS', destination: 'platform=iOS Simulator,name=iPhone 8', sdk: 'iphonesimulator' }
- { target: 'SkeletonView-tvOS', destination: 'platform=tvOS Simulator,name=Apple TV', sdk: 'appletvsimulator' }
- { target: 'SkeletonViewExample', destination: 'platform=iOS Simulator,name=iPhone 8', sdk: 'iphonesimulator' }
- { scheme: 'SkeletonView iOS', destination: 'platform=iOS Simulator,name=iPhone 8', sdk: 'iphonesimulator' }
- { scheme: 'SkeletonView tvOS', destination: 'platform=tvOS Simulator,name=Apple TV', sdk: 'appletvsimulator' }
- { scheme: 'iOS Example', destination: 'platform=iOS Simulator,name=iPhone 8', sdk: 'iphonesimulator' }
- { scheme: 'tvOS Example', destination: 'platform=tvOS Simulator,name=Apple TV', sdk: 'appletvsimulator' }
steps:
- uses: actions/checkout@v2
- name: Build
run: xcodebuild clean build -target '${{ matrix.build-config['target'] }}' -sdk '${{ matrix.build-config['sdk'] }}' -destination '${{ matrix.build-config['destination'] }}'
run: xcodebuild clean build -workspace 'SkeletonView.xcworkspace' -scheme '${{ matrix.build-config['scheme'] }}' -sdk '${{ matrix.build-config['sdk'] }}' -destination '${{ matrix.build-config['destination'] }}'
+13 -1
View File
@@ -35,4 +35,16 @@ jobs:
run: |
set -eo pipefail
pod lib lint --allow-warnings
pod trunk push --allow-warnings
pod trunk push --allow-warnings
- name: Tweet the release
uses: ethomson/send-tweet-action@v1
with:
consumer-key: ${{ secrets.TWITTER_CONSUMER_API_KEY }}
consumer-secret: ${{ secrets.TWITTER_CONSUMER_API_SECRET }}
access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }}
access-token-secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
status: |
🎉 New release ${{ steps.publish_release.outputs.tag_name }} is out 🚀
Check out all the changes here:
${{ steps.publish_release.outputs.html_url }}
+9 -4
View File
@@ -1,5 +1,5 @@
included:
- Sources
- SkeletonViewCore/Sources
disabled_rules:
- trailing_whitespace
- line_length
@@ -20,6 +20,8 @@ disabled_rules:
- function_default_parameter_at_end
- unowned_variable_capture
- legacy_constructor
- redundant_type_annotation
- vertical_whitespace_opening_braces
opt_in_rules:
- multiline_arguments
- multiline_parameters
@@ -49,18 +51,21 @@ opt_in_rules:
- private_outlet
- redundant_optional_initialization
- redundant_set_access_control
- redundant_type_annotation
- sorted_first_last
- switch_case_on_newline
- unneeded_parentheses_in_closure_argument
- unused_declaration
- unused_import
- vertical_whitespace_opening_braces
- discouraged_optional_collection
- enum_case_associated_values_counts
- enum_case_associated_values_count
- legacy_multiple
- legacy_random
indentation: 2
type_name:
min_length: 2
max_length:
warning: 50
error: 60
file_length:
- 2500
- 3000
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

-24
View File
@@ -1,24 +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>en</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>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
</dict>
</plist>
@@ -1,6 +0,0 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 933 B

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

@@ -174,6 +174,12 @@ extension ViewController: SkeletonCollectionViewDataSource {
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionSkeletonView(_ skeletonView: UICollectionView, skeletonCellForItemAt indexPath: IndexPath) -> UICollectionViewCell? {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as? CollectionViewCell
cell?.isSkeletonable = indexPath.row != 0
return cell
}
// MARK: - UICollectionViewDataSource
@@ -184,6 +190,10 @@ extension ViewController: SkeletonCollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
return cell
}
func collectionSkeletonView(_ skeletonView: UICollectionView, prepareCellForSkeleton cell: UICollectionViewCell, at indexPath: IndexPath) {
let cell = cell as? CollectionViewCell
cell?.isSkeletonable = indexPath.row != 0
}
}
@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 933 B

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Va7-1y-Tel">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Va7-1y-Tel">
<device id="retina5_9" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -50,7 +50,7 @@
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CJW-A4-Fb8">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CJW-A4-Fb8">
<rect key="frame" x="166" y="27" width="166" height="12"/>
<color key="backgroundColor" red="0.92156862750000001" green="0.16862745100000001" blue="0.54901960780000003" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="10"/>
@@ -89,7 +89,7 @@
<color key="separatorColor" red="0.1061807256" green="0.84678786989999999" blue="0.031482450150000001" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="CellIdentifier" rowHeight="120" id="2dN-Bd-tdy" customClass="Cell" customModule="SkeletonViewExample" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="375" height="120"/>
<rect key="frame" x="0.0" y="24.333333969116211" width="375" height="120"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="2dN-Bd-tdy" id="7IN-F3-Mr6">
<rect key="frame" x="0.0" y="0.0" width="375" height="120"/>
@@ -13,13 +13,15 @@
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.3</string>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
@@ -76,8 +76,8 @@ class ViewController: UIViewController {
}
@IBAction func showOrHideSkeleton(_ sender: Any) {
showOrHideSkeletonButton.setTitle((view.isSkeletonActive ? "Show skeleton" : "Hide skeleton"), for: .normal)
view.isSkeletonActive ? hideSkeleton() : showSkeleton()
showOrHideSkeletonButton.setTitle((view.sk.isSkeletonActive ? "Show skeleton" : "Hide skeleton"), for: .normal)
view.sk.isSkeletonActive ? hideSkeleton() : showSkeleton()
}
@IBAction func transitionDurationStepperAction(_ sender: Any) {
@@ -183,6 +183,17 @@ extension ViewController: SkeletonTableViewDataSource {
cell.label1.text = "cell -> \(indexPath.row)"
return cell
}
func collectionSkeletonView(_ skeletonView: UITableView, skeletonCellForRowAt indexPath: IndexPath) -> UITableViewCell? {
let cell = skeletonView.dequeueReusableCell(withIdentifier: "CellIdentifier", for: indexPath) as? Cell
cell?.textField.isHidden = indexPath.row == 0
return cell
}
func collectionSkeletonView(_ skeletonView: UITableView, prepareCellForSkeleton cell: UITableViewCell, at indexPath: IndexPath) {
let cell = cell as? Cell
cell?.textField.isHidden = indexPath.row == 0
}
}
extension ViewController: SkeletonTableViewDelegate {
@@ -0,0 +1,453 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
F556F5C026CD20A300A80B83 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F5B726CD20A300A80B83 /* ViewController.swift */; };
F556F5C126CD20A300A80B83 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F556F5B826CD20A300A80B83 /* Assets.xcassets */; };
F556F5C226CD20A300A80B83 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F556F5B926CD20A300A80B83 /* LaunchScreen.storyboard */; };
F556F5C326CD20A300A80B83 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F556F5BB26CD20A300A80B83 /* Main.storyboard */; };
F556F5C426CD20A300A80B83 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F5BD26CD20A300A80B83 /* AppDelegate.swift */; };
F556F5E626CD21D300A80B83 /* SkeletonView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F556F5E026CD21CB00A80B83 /* SkeletonView.framework */; };
F556F6EE26CE813F00A80B83 /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6E626CE813F00A80B83 /* Cell.swift */; };
F556F6EF26CE813F00A80B83 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6EC26CE813F00A80B83 /* Constants.swift */; };
F556F6F026CE813F00A80B83 /* HeaderFooterSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F6ED26CE813F00A80B83 /* HeaderFooterSection.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
F556F5DF26CD21CB00A80B83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F556F5D926CD21CB00A80B83 /* SkeletonView.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = "SkeletonView::SkeletonView::Product";
remoteInfo = "SkeletonView iOS";
};
F556F5E126CD21CB00A80B83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F556F5D926CD21CB00A80B83 /* SkeletonView.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = "SkeletonView::SkeletonViewTests::Product";
remoteInfo = SkeletonViewTests;
};
F556F5E326CD21CB00A80B83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F556F5D926CD21CB00A80B83 /* SkeletonView.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = F556F59426CD1F3900A80B83;
remoteInfo = "SkeletonView tvOS";
};
F556F5E926CD21DA00A80B83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F556F5D926CD21CB00A80B83 /* SkeletonView.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = "SkeletonView::SkeletonView";
remoteInfo = "SkeletonView iOS";
};
F556F6EA26CE813F00A80B83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F556F5D926CD21CB00A80B83 /* SkeletonView.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = F556F67126CD458500A80B83;
remoteInfo = "SkeletonView tvOS Tests";
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
F556F59F26CD201B00A80B83 /* iOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
F556F5B726CD20A300A80B83 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
F556F5B826CD20A300A80B83 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
F556F5BA26CD20A300A80B83 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
F556F5BC26CD20A300A80B83 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
F556F5BD26CD20A300A80B83 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
F556F5BE26CD20A300A80B83 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F556F5D926CD21CB00A80B83 /* SkeletonView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SkeletonView.xcodeproj; path = ../../SkeletonView.xcodeproj; sourceTree = "<group>"; };
F556F6E626CE813F00A80B83 /* Cell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cell.swift; sourceTree = "<group>"; };
F556F6EC26CE813F00A80B83 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
F556F6ED26CE813F00A80B83 /* HeaderFooterSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderFooterSection.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
F556F59C26CD201B00A80B83 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F556F5E626CD21D300A80B83 /* SkeletonView.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
F556F59626CD201B00A80B83 = {
isa = PBXGroup;
children = (
F556F5B626CD20A300A80B83 /* Sources */,
F556F5A026CD201B00A80B83 /* Products */,
F556F5D926CD21CB00A80B83 /* SkeletonView.xcodeproj */,
);
sourceTree = "<group>";
};
F556F5A026CD201B00A80B83 /* Products */ = {
isa = PBXGroup;
children = (
F556F59F26CD201B00A80B83 /* iOS Example.app */,
);
name = Products;
sourceTree = "<group>";
};
F556F5B626CD20A300A80B83 /* Sources */ = {
isa = PBXGroup;
children = (
F556F6E626CE813F00A80B83 /* Cell.swift */,
F556F6EC26CE813F00A80B83 /* Constants.swift */,
F556F6ED26CE813F00A80B83 /* HeaderFooterSection.swift */,
F556F5B726CD20A300A80B83 /* ViewController.swift */,
F556F5B826CD20A300A80B83 /* Assets.xcassets */,
F556F5B926CD20A300A80B83 /* LaunchScreen.storyboard */,
F556F5BB26CD20A300A80B83 /* Main.storyboard */,
F556F5BD26CD20A300A80B83 /* AppDelegate.swift */,
F556F5BE26CD20A300A80B83 /* Info.plist */,
);
path = Sources;
sourceTree = "<group>";
};
F556F5DA26CD21CB00A80B83 /* Products */ = {
isa = PBXGroup;
children = (
F556F5E026CD21CB00A80B83 /* SkeletonView.framework */,
F556F5E226CD21CB00A80B83 /* SkeletonViewTests.xctest */,
F556F5E426CD21CB00A80B83 /* SkeletonView.framework */,
F556F6EB26CE813F00A80B83 /* SkeletonView tvOS Tests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
F556F59E26CD201B00A80B83 /* iOS Example */ = {
isa = PBXNativeTarget;
buildConfigurationList = F556F5B326CD201C00A80B83 /* Build configuration list for PBXNativeTarget "iOS Example" */;
buildPhases = (
F556F59B26CD201B00A80B83 /* Sources */,
F556F59C26CD201B00A80B83 /* Frameworks */,
F556F59D26CD201B00A80B83 /* Resources */,
);
buildRules = (
);
dependencies = (
F556F5EA26CD21DA00A80B83 /* PBXTargetDependency */,
);
name = "iOS Example";
productName = "iOS Example";
productReference = F556F59F26CD201B00A80B83 /* iOS Example.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
F556F59726CD201B00A80B83 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1250;
LastUpgradeCheck = 1300;
TargetAttributes = {
F556F59E26CD201B00A80B83 = {
CreatedOnToolsVersion = 12.5.1;
};
};
};
buildConfigurationList = F556F59A26CD201B00A80B83 /* Build configuration list for PBXProject "iOS Example" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = F556F59626CD201B00A80B83;
productRefGroup = F556F5A026CD201B00A80B83 /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = F556F5DA26CD21CB00A80B83 /* Products */;
ProjectRef = F556F5D926CD21CB00A80B83 /* SkeletonView.xcodeproj */;
},
);
projectRoot = "";
targets = (
F556F59E26CD201B00A80B83 /* iOS Example */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
F556F5E026CD21CB00A80B83 /* SkeletonView.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = SkeletonView.framework;
remoteRef = F556F5DF26CD21CB00A80B83 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
F556F5E226CD21CB00A80B83 /* SkeletonViewTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = SkeletonViewTests.xctest;
remoteRef = F556F5E126CD21CB00A80B83 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
F556F5E426CD21CB00A80B83 /* SkeletonView.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = SkeletonView.framework;
remoteRef = F556F5E326CD21CB00A80B83 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
F556F6EB26CE813F00A80B83 /* SkeletonView tvOS Tests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = "SkeletonView tvOS Tests.xctest";
remoteRef = F556F6EA26CE813F00A80B83 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
F556F59D26CD201B00A80B83 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F556F5C326CD20A300A80B83 /* Main.storyboard in Resources */,
F556F5C126CD20A300A80B83 /* Assets.xcassets in Resources */,
F556F5C226CD20A300A80B83 /* LaunchScreen.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
F556F59B26CD201B00A80B83 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F556F6EF26CE813F00A80B83 /* Constants.swift in Sources */,
F556F5C426CD20A300A80B83 /* AppDelegate.swift in Sources */,
F556F6EE26CE813F00A80B83 /* Cell.swift in Sources */,
F556F5C026CD20A300A80B83 /* ViewController.swift in Sources */,
F556F6F026CE813F00A80B83 /* HeaderFooterSection.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
F556F5EA26CD21DA00A80B83 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "SkeletonView iOS";
targetProxy = F556F5E926CD21DA00A80B83 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
F556F5B926CD20A300A80B83 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
F556F5BA26CD20A300A80B83 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
F556F5BB26CD20A300A80B83 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
F556F5BC26CD20A300A80B83 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
F556F5B126CD201C00A80B83 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
F556F5B226CD201C00A80B83 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
F556F5B426CD201C00A80B83 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.skeletonview.iOS-Example";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
F556F5B526CD201C00A80B83 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.skeletonview.iOS-Example";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
F556F59A26CD201B00A80B83 /* Build configuration list for PBXProject "iOS Example" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F556F5B126CD201C00A80B83 /* Debug */,
F556F5B226CD201C00A80B83 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F556F5B326CD201C00A80B83 /* Build configuration list for PBXNativeTarget "iOS Example" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F556F5B426CD201C00A80B83 /* Debug */,
F556F5B526CD201C00A80B83 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = F556F59726CD201B00A80B83 /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,40 @@
//
// AppDelegate.swift
// tvOS Example
//
// Created by Juanpe Catalán on 18/8/21.
//
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
}
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,11 @@
{
"images" : [
{
"idiom" : "tv"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,17 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"layers" : [
{
"filename" : "Front.imagestacklayer"
},
{
"filename" : "Middle.imagestacklayer"
},
{
"filename" : "Back.imagestacklayer"
}
]
}
@@ -0,0 +1,11 @@
{
"images" : [
{
"idiom" : "tv"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,11 @@
{
"images" : [
{
"idiom" : "tv"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,16 @@
{
"images" : [
{
"idiom" : "tv",
"scale" : "1x"
},
{
"idiom" : "tv",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,17 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"layers" : [
{
"filename" : "Front.imagestacklayer"
},
{
"filename" : "Middle.imagestacklayer"
},
{
"filename" : "Back.imagestacklayer"
}
]
}
@@ -0,0 +1,16 @@
{
"images" : [
{
"idiom" : "tv",
"scale" : "1x"
},
{
"idiom" : "tv",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,16 @@
{
"images" : [
{
"idiom" : "tv",
"scale" : "1x"
},
{
"idiom" : "tv",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,32 @@
{
"assets" : [
{
"filename" : "App Icon - App Store.imagestack",
"idiom" : "tv",
"role" : "primary-app-icon",
"size" : "1280x768"
},
{
"filename" : "App Icon.imagestack",
"idiom" : "tv",
"role" : "primary-app-icon",
"size" : "400x240"
},
{
"filename" : "Top Shelf Image Wide.imageset",
"idiom" : "tv",
"role" : "top-shelf-image-wide",
"size" : "2320x720"
},
{
"filename" : "Top Shelf Image.imageset",
"idiom" : "tv",
"role" : "top-shelf-image",
"size" : "1920x720"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,24 @@
{
"images" : [
{
"idiom" : "tv",
"scale" : "1x"
},
{
"idiom" : "tv",
"scale" : "2x"
},
{
"idiom" : "tv-marketing",
"scale" : "1x"
},
{
"idiom" : "tv-marketing",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,24 @@
{
"images" : [
{
"idiom" : "tv",
"scale" : "1x"
},
{
"idiom" : "tv",
"scale" : "2x"
},
{
"idiom" : "tv-marketing",
"scale" : "1x"
},
{
"idiom" : "tv-marketing",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="13122.16" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="wu6-TO-1qx"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="13122.16" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="wu6-TO-1qx"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
@@ -13,12 +13,22 @@
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Automatic</string>
</dict>
</plist>
@@ -0,0 +1,19 @@
//
// ViewController.swift
// tvOS Example
//
// Created by Juanpe Catalán on 18/8/21.
//
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
@@ -0,0 +1,441 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
F556F61226CD224900A80B83 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F60A26CD224900A80B83 /* ViewController.swift */; };
F556F61326CD224900A80B83 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F556F60B26CD224900A80B83 /* Assets.xcassets */; };
F556F61426CD224900A80B83 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F556F60C26CD224900A80B83 /* LaunchScreen.storyboard */; };
F556F61526CD224900A80B83 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F556F60E26CD224900A80B83 /* Main.storyboard */; };
F556F61626CD224900A80B83 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F61026CD224900A80B83 /* AppDelegate.swift */; };
F556F62526CD225C00A80B83 /* SkeletonView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F556F62326CD224F00A80B83 /* SkeletonView.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
F556F61E26CD224F00A80B83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F556F61826CD224F00A80B83 /* SkeletonView.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = "SkeletonView::SkeletonView::Product";
remoteInfo = "SkeletonView iOS";
};
F556F62026CD224F00A80B83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F556F61826CD224F00A80B83 /* SkeletonView.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = "SkeletonView::SkeletonViewTests::Product";
remoteInfo = SkeletonViewTests;
};
F556F62226CD224F00A80B83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F556F61826CD224F00A80B83 /* SkeletonView.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = F556F59426CD1F3900A80B83;
remoteInfo = "SkeletonView tvOS";
};
F556F62826CD226600A80B83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F556F61826CD224F00A80B83 /* SkeletonView.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = F556F56426CD1F3900A80B83;
remoteInfo = "SkeletonView tvOS";
};
F556F6FE26CE88DC00A80B83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F556F61826CD224F00A80B83 /* SkeletonView.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = F556F67126CD458500A80B83;
remoteInfo = "SkeletonView tvOS Tests";
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
F556F5F426CD221300A80B83 /* tvOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "tvOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
F556F60A26CD224900A80B83 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
F556F60B26CD224900A80B83 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
F556F60D26CD224900A80B83 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
F556F60F26CD224900A80B83 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
F556F61026CD224900A80B83 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
F556F61126CD224900A80B83 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F556F61826CD224F00A80B83 /* SkeletonView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SkeletonView.xcodeproj; path = ../../SkeletonView.xcodeproj; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
F556F5F126CD221300A80B83 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F556F62526CD225C00A80B83 /* SkeletonView.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
F556F5EB26CD221300A80B83 = {
isa = PBXGroup;
children = (
F556F60926CD224900A80B83 /* Sources */,
F556F5F526CD221300A80B83 /* Products */,
F556F61826CD224F00A80B83 /* SkeletonView.xcodeproj */,
);
sourceTree = "<group>";
};
F556F5F526CD221300A80B83 /* Products */ = {
isa = PBXGroup;
children = (
F556F5F426CD221300A80B83 /* tvOS Example.app */,
);
name = Products;
sourceTree = "<group>";
};
F556F60926CD224900A80B83 /* Sources */ = {
isa = PBXGroup;
children = (
F556F60A26CD224900A80B83 /* ViewController.swift */,
F556F60B26CD224900A80B83 /* Assets.xcassets */,
F556F60C26CD224900A80B83 /* LaunchScreen.storyboard */,
F556F60E26CD224900A80B83 /* Main.storyboard */,
F556F61026CD224900A80B83 /* AppDelegate.swift */,
F556F61126CD224900A80B83 /* Info.plist */,
);
path = Sources;
sourceTree = "<group>";
};
F556F61926CD224F00A80B83 /* Products */ = {
isa = PBXGroup;
children = (
F556F61F26CD224F00A80B83 /* SkeletonView.framework */,
F556F62126CD224F00A80B83 /* SkeletonViewTests.xctest */,
F556F62326CD224F00A80B83 /* SkeletonView.framework */,
F556F6FF26CE88DC00A80B83 /* SkeletonView tvOS Tests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
F556F5F326CD221300A80B83 /* tvOS Example */ = {
isa = PBXNativeTarget;
buildConfigurationList = F556F60626CD221400A80B83 /* Build configuration list for PBXNativeTarget "tvOS Example" */;
buildPhases = (
F556F5F026CD221300A80B83 /* Sources */,
F556F5F126CD221300A80B83 /* Frameworks */,
F556F5F226CD221300A80B83 /* Resources */,
);
buildRules = (
);
dependencies = (
F556F62926CD226600A80B83 /* PBXTargetDependency */,
);
name = "tvOS Example";
productName = "tvOS Example";
productReference = F556F5F426CD221300A80B83 /* tvOS Example.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
F556F5EC26CD221300A80B83 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1250;
LastUpgradeCheck = 1300;
TargetAttributes = {
F556F5F326CD221300A80B83 = {
CreatedOnToolsVersion = 12.5.1;
};
};
};
buildConfigurationList = F556F5EF26CD221300A80B83 /* Build configuration list for PBXProject "tvOS Example" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = F556F5EB26CD221300A80B83;
productRefGroup = F556F5F526CD221300A80B83 /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = F556F61926CD224F00A80B83 /* Products */;
ProjectRef = F556F61826CD224F00A80B83 /* SkeletonView.xcodeproj */;
},
);
projectRoot = "";
targets = (
F556F5F326CD221300A80B83 /* tvOS Example */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
F556F61F26CD224F00A80B83 /* SkeletonView.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = SkeletonView.framework;
remoteRef = F556F61E26CD224F00A80B83 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
F556F62126CD224F00A80B83 /* SkeletonViewTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = SkeletonViewTests.xctest;
remoteRef = F556F62026CD224F00A80B83 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
F556F62326CD224F00A80B83 /* SkeletonView.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = SkeletonView.framework;
remoteRef = F556F62226CD224F00A80B83 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
F556F6FF26CE88DC00A80B83 /* SkeletonView tvOS Tests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = "SkeletonView tvOS Tests.xctest";
remoteRef = F556F6FE26CE88DC00A80B83 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
F556F5F226CD221300A80B83 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F556F61526CD224900A80B83 /* Main.storyboard in Resources */,
F556F61326CD224900A80B83 /* Assets.xcassets in Resources */,
F556F61426CD224900A80B83 /* LaunchScreen.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
F556F5F026CD221300A80B83 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F556F61626CD224900A80B83 /* AppDelegate.swift in Sources */,
F556F61226CD224900A80B83 /* ViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
F556F62926CD226600A80B83 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "SkeletonView tvOS";
targetProxy = F556F62826CD226600A80B83 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
F556F60C26CD224900A80B83 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
F556F60D26CD224900A80B83 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
F556F60E26CD224900A80B83 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
F556F60F26CD224900A80B83 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
F556F60426CD221400A80B83 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = appletvos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TVOS_DEPLOYMENT_TARGET = 12.0;
};
name = Debug;
};
F556F60526CD221400A80B83 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = appletvos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TVOS_DEPLOYMENT_TARGET = 12.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
F556F60726CD221400A80B83 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = Sources/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.skeletonview.tvOS-Example";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 12.0;
};
name = Debug;
};
F556F60826CD221400A80B83 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = Sources/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.skeletonview.tvOS-Example";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 12.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
F556F5EF26CD221300A80B83 /* Build configuration list for PBXProject "tvOS Example" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F556F60426CD221400A80B83 /* Debug */,
F556F60526CD221400A80B83 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F556F60626CD221400A80B83 /* Build configuration list for PBXNativeTarget "tvOS Example" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F556F60726CD221400A80B83 /* Debug */,
F556F60826CD221400A80B83 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = F556F5EC26CD221300A80B83 /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
+2 -2
View File
@@ -7,8 +7,8 @@ GEM
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.6.0)
public_suffix (>= 2.0.2, < 4.0)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
atomos (0.1.3)
babosa (1.0.2)
claide (1.0.2)
+19 -13
View File
@@ -4,20 +4,26 @@ import PackageDescription
let package = Package(
name: "SkeletonView",
platforms: [
.iOS(.v9),
.tvOS(.v9)
],
platforms: [
.iOS(.v9),
.tvOS(.v9)
],
products: [
.library(
name: "SkeletonView",
targets: ["SkeletonView"])
],
targets: [
.target(
name: "SkeletonView",
dependencies: [],
path: "Sources")
],
swiftLanguageVersions: [.v5]
targets: ["SkeletonView"]
)
],
targets: [
.target(
name: "SkeletonView",
path: "SkeletonViewCore/Sources"
),
.testTarget(
name: "SkeletonViewTests",
dependencies: ["SkeletonView"],
path: "SkeletonViewCore/Tests"
)
],
swiftLanguageVersions: [.v5]
)
+119 -59
View File
@@ -4,10 +4,12 @@
<a href="https://github.com/Juanpe/SkeletonView/actions?query=workflow%3ACI">
<img src="https://github.com/Juanpe/SkeletonView/workflows/CI/badge.svg">
</a>
<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>
<img src="http://img.shields.io/badge/dependency%20manager-swiftpm%2Bcocoapods%2Bcarthage-green" />
<img src="https://img.shields.io/badge/platforms-ios%2Btvos-green" />
<a href="https://badge.bow-swift.io/recipe?name=SkeletonView&description=An%20elegant%20way%20to%20show%20users%20that%20something%20is%20happening%20and%20also%20prepare%20them%20to%20which%20contents%20he%20is%20waiting&url=https://github.com/juanpe/skeletonview&owner=Juanpe&avatar=https://avatars0.githubusercontent.com/u/1409041?v=4&tag=1.8.7"><img src="https://raw.githubusercontent.com/bow-swift/bow-art/master/badges/nef-playgrounds-badge.svg" alt="SkeletonView Playground" style="height:20px"></a>
<a href="https://codebeat.co/projects/github-com-juanpe-skeletonview-main"><img alt="codebeat badge" src="https://codebeat.co/badges/1f37bbab-a1c8-4a4a-94d7-f21740d461e9" /></a>
<a href="https://cocoapods.org/pods/SkeletonView"><img src="https://img.shields.io/cocoapods/v/SkeletonView.svg?style=flat"></a>
<a href="https://github.com/Carthage/Carthage/"><img src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat"></a>
<a href="https://swift.org/package-manager/"><img src="https://img.shields.io/badge/SPM-supported-Green.svg?style=flat"></a>
<img src="https://img.shields.io/badge/platforms-iOS_tvOS-green" />
<a href="https://badge.bow-swift.io/recipe?name=SkeletonView&description=An%20elegant%20way%20to%20show%20users%20that%20something%20is%20happening%20and%20also%20prepare%20them%20to%20which%20contents%20he%20is%20waiting&url=https://github.com/juanpe/skeletonview&owner=Juanpe&avatar=https://avatars0.githubusercontent.com/u/1409041?v=4&tag=1.20.0"><img src="https://raw.githubusercontent.com/bow-swift/bow-art/master/badges/nef-playgrounds-badge.svg" alt="SkeletonView Playground" style="height:20px"></a>
</p>
<p align="center">
@@ -19,7 +21,7 @@
• <a href="#-contributing">Contributing</a>
</p>
**🌎 README is available in other languages: [🇪🇸](https://github.com/Juanpe/SkeletonView/blob/main/README_es.md) . [🇨🇳](https://github.com/Juanpe/SkeletonView/blob/master/README_zh.md) . [🇧🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_pt-br.md) . [🇰🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_ko.md) . [🇫🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_fr.md)**
**🌎 README is available in other languages: [🇪🇸](Translations/README_es.md) . [🇨🇳](Translations/README_zh.md) . [🇧🇷](Translations/README_pt-br.md) . [🇰🇷](Translations/README_ko.md) . [🇫🇷](Translations/README_fr.md)**
Today almost all apps have async processes, such as API requests, long running processes, etc. While the processes are working, usually developers place a loading view to show users that something is going on.
@@ -37,12 +39,12 @@ Enjoy it! 🙂
- [🔠 Texts](#-texts)
- [🦋 Appearance](#-appearance)
- [🎨 Custom colors](#-custom-colors)
- [Image captured from website https://flatuicolors.com](#image-captured-from-website-httpsflatuicolorscom)
- [🏃‍♀️ Animations](#-animations)
- [🏄 Transitions](#-transitions)
- [✨ Miscellaneous](#-miscellaneous)
- [❤️ Contributing](#-contributing)
- [📢 Mentions](#-mentions)
- [🏆 Sponsors](#-sponsors)
- [👨🏻‍💻 Author](#-author)
- [👮🏻 License](#-license)
@@ -61,9 +63,9 @@ Enjoy it! 🙂
## 🎬 Guides
| [![](https://img.youtube.com/vi/75kgOhWsPNA/maxresdefault.jpg)](https://youtu.be/75kgOhWsPNA)|[![](https://img.youtube.com/vi/MVCiM_VdxVA/maxresdefault.jpg)](https://youtu.be/MVCiM_VdxVA)|[![](https://img.youtube.com/vi/Qq3Evspeea8/maxresdefault.jpg)](https://youtu.be/Qq3Evspeea8)|[![](https://img.youtube.com/vi/ZOoPtBwDRT0/maxresdefault.jpg)](https://youtu.be/ZOoPtBwDRT0)|[![](https://img.youtube.com/vi/Zx1Pg1gPfxA/maxresdefault.jpg)](https://www.youtube.com/watch?v=Zx1Pg1gPfxA)
|:---: | :---: |:---: | :---: | :---:
|[**SkeletonView Guides - Getting started**](https://youtu.be/75kgOhWsPNA)|[**How to Create Loading View with Skeleton View in Swift 5.2**](https://youtu.be/MVCiM_VdxVA) by iKh4ever Studio|[**Create Skeleton Loading View in App (Swift 5) - Xcode 11, 2020**](https://youtu.be/Qq3Evspeea8) by iOS Academy| [**Add An Elegant Loading Animation in Swift***](https://youtu.be/ZOoPtBwDRT0) by Gary Tokman| [**Cómo crear una ANIMACIÓN de CARGA de DATOS en iOS**](https://www.youtube.com/watch?v=Zx1Pg1gPfxA) by MoureDev
| [![](https://img.youtube.com/vi/75kgOhWsPNA/maxresdefault.jpg)](https://youtu.be/75kgOhWsPNA)|[![](https://img.youtube.com/vi/MVCiM_VdxVA/maxresdefault.jpg)](https://youtu.be/MVCiM_VdxVA)|[![](https://img.youtube.com/vi/Qq3Evspeea8/maxresdefault.jpg)](https://youtu.be/Qq3Evspeea8)|[![](https://img.youtube.com/vi/Zx1Pg1gPfxA/maxresdefault.jpg)](https://www.youtube.com/watch?v=Zx1Pg1gPfxA)
|:---: | :---: | :---: | :---:
|[**SkeletonView Guides - Getting started**](https://youtu.be/75kgOhWsPNA)|[**How to Create Loading View with Skeleton View in Swift 5.2**](https://youtu.be/MVCiM_VdxVA) by iKh4ever Studio|[**Create Skeleton Loading View in App (Swift 5) - Xcode 11, 2020**](https://youtu.be/Qq3Evspeea8) by iOS Academy| [**Cómo crear una ANIMACIÓN de CARGA de DATOS en iOS**](https://www.youtube.com/watch?v=Zx1Pg1gPfxA) by MoureDev
## 📲 Installation
@@ -169,19 +171,16 @@ If you want to show the skeleton in a ```UITableView```, you need to conform to
``` swift
public protocol SkeletonTableViewDataSource: UITableViewDataSource {
func numSections(in collectionSkeletonView: UITableView) -> Int
func numSections(in collectionSkeletonView: UITableView) -> Int // Default: 1
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
func collectionSkeletonView(_ skeletonView: UITableView, skeletonCellForRowAt indexPath: IndexPath) -> UITableViewCell? // Default: nil
func collectionSkeletonView(_ skeletonView: UITableView, prepareCellForSkeleton cell: UITableViewCell, at indexPath: IndexPath)
}
```
As you can see, this protocol inherits from ```UITableViewDataSource```, so you can replace this protocol with the skeleton protocol.
This protocol has a default implementation:
``` swift
func numSections(in collectionSkeletonView: UITableView) -> Int
// Default: 1
```
This protocol has a default implementation for some methods. For example, the number of rows for each section is calculated in runtime:
``` swift
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int
@@ -194,17 +193,30 @@ func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection s
> If you return `UITableView.automaticNumberOfSkeletonRows` in the above method, it acts like the default behavior (i.e. it calculates how many cells needed to populate the whole tableview).
There is only one method you need to implement to let Skeleton know the cell identifier. This method doesn't have default implementation:
``` swift
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
```
**Example**
``` swift
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier {
return "CellIdentifier"
}
```
By default, the library dequeues the cells from each indexPath, but you can also do this if you want to make some changes before the skeleton appears:
``` swift
func collectionSkeletonView(_ skeletonView: UITableView, skeletonCellForRowAt indexPath: IndexPath) -> UITableViewCell? {
let cell = skeletonView.dequeueReusableCell(withIdentifier: "CellIdentifier", for: indexPath) as? Cell
cell?.textField.isHidden = indexPath.row == 0
return cell
}
```
If you prefer to leave the deque part to the library you can configure the cell using this method:
``` swift
func collectionSkeletonView(_ skeletonView: UITableView, prepareCellForSkeleton cell: UITableViewCell, at indexPath: IndexPath) {
let cell = cell as? Cell
cell?.textField.isHidden = indexPath.row == 0
}
```
Besides, you can skeletonize both the headers and footers. You need to conform to `SkeletonTableViewDelegate` protocol.
```swift
@@ -232,10 +244,12 @@ For `UICollectionView`, you need to conform to `SkeletonCollectionViewDataSource
``` swift
public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
func numSections(in collectionSkeletonView: UICollectionView) -> Int // default: 1
func numSections(in collectionSkeletonView: UICollectionView) -> Int // default: 1
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int
func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier
func collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -> ReusableCellIdentifier? // default: nil
func collectionSkeletonView(_ skeletonView: UICollectionView, skeletonCellForItemAt indexPath: IndexPath) -> UICollectionViewCell? // default: nil
func collectionSkeletonView(_ skeletonView: UICollectionView, prepareCellForSkeleton cell: UICollectionViewCell, at indexPath: IndexPath)
}
```
@@ -251,13 +265,30 @@ Besides, you can decide how many lines you want. If ```numberOfLines``` is set
You can set some properties for multilines elements.
| Property | Values | Default | Preview
| Property | Type | 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)
| **lastLineFillPercent** | `CGFloat` | `70`| ![](Assets/multiline_lastline.png)
| **linesCornerRadius** | `Int` | `0` | ![](Assets/multiline_corner.png)
| **skeletonLineSpacing** | `CGFloat` | `10` | ![](Assets/multiline_lineSpacing.png)
| **skeletonPaddingInsets** | `UIEdgeInsets` | `.zero` | ![](Assets/multiline_insets.png)
| **skeletonTextLineHeight** | `SkeletonTextLineHeight` | `.fixed(15)` | ![](Assets/multiline_lineHeight.png)
<br />
> **⚠️ DEPRECATED!**
>
> **useFontLineHeight** has been deprecated. You can use **skeletonTextLineHeight** instead:
> ```swift
> descriptionTextView.skeletonTextLineHeight = .relativeToFont
> ```
> **📣 IMPORTANT!**
>
> Please note that for views without multiple lines, the single line will be considered
> as the last line.
<br />
To modify the percent or radius **using code**, set the properties:
```swift
@@ -275,19 +306,19 @@ Or, if you prefer use **IB/Storyboard**:
The skeletons have a default appearance. So, when you don't specify the color, gradient or multilines properties, `SkeletonView` uses the default values.
Default values:
- **tintColor**: UIColor
- **tintColor**: `UIColor`
- *default: `.skeletonDefault` (same as `.clouds` but adaptive to dark mode)*
- **gradient**: SkeletonGradient
- *default: `SkeletonGradient(baseColor: .skeletonDefault)`*
- **multilineHeight**: CGFloat
- **multilineHeight**: `CGFloat`
- *default: 15*
- **multilineSpacing**: CGFloat
- **multilineSpacing**: `CGFloat`
- *default: 10*
- **multilineLastLineFillPercent**: Int
- **multilineLastLineFillPercent**: `Int`
- *default: 70*
- **multilineCornerRadius**: Int
- **multilineCornerRadius**: `Int`
- *default: 0*
- **skeletonCornerRadius**: CGFloat (IBInspectable) (Make your skeleton view with corner)
- **skeletonCornerRadius**: `CGFloat` (IBInspectable) (Make your skeleton view with corner)
- *default: 0*
To get these default values you can use `SkeletonAppearance.default`. Using this property you can set the values as well:
@@ -296,11 +327,12 @@ SkeletonAppearance.default.multilineHeight = 20
SkeletonAppearance.default.tintColor = .green
```
You can also specifiy these line appearance properties on a per-label basis:
- **lastLineFillPercent**: Int
- **linesCornerRadius**: Int
- **skeletonLineSpacing**: CGFloat
- **skeletonPaddingInsets**: UIEdgeInsets
> **⚠️ DEPRECATED!**
>
> **useFontLineHeight** has been deprecated. You can use **textLineHeight** instead:
> ```swift
> SkeletonAppearance.default.textLineHeight = .relativeToFont
> ```
### 🎨 Custom colors
@@ -447,16 +479,6 @@ view.showSkeleton()
**Hierarchy in collections**
Here is an illustration that shows how you should specify which elements are skeletonables when you are using an `UITableView`:
<img src="Assets/tableview_scheme.png" width="700px">
As you can see, we have to make skeletonable the tableview, the cell and the UI elements, but we don't need to set as skeletonable the `contentView`
**Skeleton views layout**
Sometimes skeleton layout may not fit your layout because the parent view bounds have changed. ~For example, rotating the device.~
@@ -504,18 +526,41 @@ By default, the user interaction is disabled for skeletonized items, but if you
view.isUserInteractionDisabledWhenSkeletonIsActive = false // The view will be active when the skeleton will be active.
```
**Don't use the font line height for the skeleton lines in labels**
False to disable skeleton to auto-adjust to font height for a `UILabel` or `UITextView`. By default, the skeleton lines height is auto-adjusted to font height to more accurately reflect the text in the label rect rather than using the bounding box.
```swift
label.useFontLineHeight = false
```
**Delayed show skeleton**
You can delay the presentation of the skeleton if the views update quickly.
```swift
func showSkeleton(usingColor: UIColor,
animated: Bool,
delay: TimeInterval,
transition: SkeletonTransitionStyle)
```
```swift
func showGradientSkeleton(usingGradient: SkeletonGradient,
animated: Bool,
delay: TimeInterval,
transition: SkeletonTransitionStyle)
```
**Debug**
To facilitate the debug tasks when something is not working fine. **`SkeletonView`** has some new tools.
First, `UIView` has available a new property with his skeleton info:
First, `UIView` has available a property with his skeleton info:
```swift
var skeletonDescription: String
var sk.skeletonTreeDescription: String
```
The skeleton representation looks like this:
![](Assets/debug_description.png)
Besides, you can activate the new **debug mode**. You just add the environment variable `SKELETON_DEBUG` and activate it.
@@ -523,21 +568,31 @@ Besides, you can activate the new **debug mode**. You just add the environment v
Then, when the skeleton appears, you can see the view hierarchy in the Xcode console.
<details>
<summary>Open to see an output example </summary>
<img src="Assets/hierarchy_output.png" />
</details>
```
{
"type" : "UIView", // UITableView, UILabel...
"isSkeletonable" : true,
"reference" : "0x000000014751ce30",
"children" : [
{
"type" : "UIView",
"isSkeletonable" : true,
"children" : [ ... ],
"reference" : "0x000000014751cfa0"
}
]
}
```
**Supported OS & SDK Versions**
* iOS 9.0+
* tvOS 9.0+
* Swift 5
* Swift 5.3
## ❤️ Contributing
This is an open source project, so feel free to contribute. How?
- Open an [issue](https://github.com/Juanpe/SkeletonView/issues/new).
- Send feedback via [email](mailto://juanpecatalan.com).
- Propose your own fixes, suggestions and open a pull request with the changes.
@@ -563,7 +618,12 @@ For more information, please read the [contributing guidelines](https://github.c
- [Swift News #36](https://www.youtube.com/watch?v=mAGpsQiy6so)
- [Best iOS articles, new tools & more](https://medium.com/flawless-app-stories/best-ios-articles-new-tools-more-fcbe673e10d)
## 🏆 Sponsors
Open-source projects cannot live long without your help. If you find **SkeletonView** is useful, please consider supporting this
project by becoming a sponsor.
Become a sponsor through [GitHub Sponsors](https://github.com/sponsors/Juanpe) :heart:
## 👨🏻‍💻 Author
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:SkeletonView.xcodeproj">
</FileRef>
<FileRef
location = "group:Examples/iOS Example/iOS Example.xcodeproj">
</FileRef>
<FileRef
location = "group:Examples/tvOS Example/tvOS Example.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
+2 -2
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SkeletonView"
s.version = "1.17.1"
s.version = "1.26.0"
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.
@@ -14,5 +14,5 @@ Pod::Spec.new do |s|
s.tvos.deployment_target = "9.0"
s.swift_version = "5.0"
s.source = { :git => "https://github.com/Juanpe/SkeletonView.git", :tag => s.version.to_s }
s.source_files = "Sources/**/*"
s.source_files = "SkeletonViewCore/Sources/**/*.{swift,h}"
end
File diff suppressed because it is too large Load Diff
@@ -4,4 +4,4 @@
<FileRef
location = "self:">
</FileRef>
</Workspace>
</Workspace>
@@ -0,0 +1,8 @@
<?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>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
</plist>
@@ -3,6 +3,17 @@
<plist version="1.0">
<dict>
<key>FILEHEADER</key>
<string> ___COPYRIGHT___</string>
<string>
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the &quot;License&quot;);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// ___FILENAME___
//
// Created by ___FULLUSERNAME___ on ___DATE___.</string>
</dict>
</plist>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -14,9 +14,9 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "17DD0DFF207FB27400C56334"
BlueprintIdentifier = "SkeletonView::SkeletonView"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-tvOS"
BlueprintName = "SkeletonView iOS"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@@ -28,9 +28,17 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "SkeletonView::SkeletonViewTests"
BuildableName = "SkeletonViewTests.xctest"
BlueprintName = "SkeletonView iOS Tests"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -42,17 +50,6 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "17DD0DFF207FB27400C56334"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-tvOS"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@@ -60,15 +57,6 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "17DD0DFF207FB27400C56334"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-tvOS"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -14,9 +14,23 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "52D6D97B1BEFF229002C0205"
BlueprintIdentifier = "F556F56426CD1F3900A80B83"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-iOS"
BlueprintName = "SkeletonView tvOS"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F556F67026CD458500A80B83"
BuildableName = "SkeletonView tvOS Tests.xctest"
BlueprintName = "SkeletonView tvOS Tests"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@@ -28,18 +42,17 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F556F67026CD458500A80B83"
BuildableName = "SkeletonView tvOS Tests.xctest"
BlueprintName = "SkeletonView tvOS Tests"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "52D6D97B1BEFF229002C0205"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-iOS"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -51,17 +64,6 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "52D6D97B1BEFF229002C0205"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-iOS"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@@ -72,9 +74,9 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "52D6D97B1BEFF229002C0205"
BlueprintIdentifier = "F556F56426CD1F3900A80B83"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-iOS"
BlueprintName = "SkeletonView tvOS"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -1,91 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F5F899F11FABA607002E8FDA"
BuildableName = "SkeletonViewExample.app"
BlueprintName = "SkeletonViewExample"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F5F899F11FABA607002E8FDA"
BuildableName = "SkeletonViewExample.app"
BlueprintName = "SkeletonViewExample"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F5F899F11FABA607002E8FDA"
BuildableName = "SkeletonViewExample.app"
BlueprintName = "SkeletonViewExample"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F5F899F11FABA607002E8FDA"
BuildableName = "SkeletonViewExample.app"
BlueprintName = "SkeletonViewExample"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,91 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "42ABD05A210B548200BEEFF4"
BuildableName = "SkeletonViewExampleUICollectionView.app"
BlueprintName = "SkeletonViewExampleUICollectionView"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "42ABD05A210B548200BEEFF4"
BuildableName = "SkeletonViewExampleUICollectionView.app"
BlueprintName = "SkeletonViewExampleUICollectionView"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "42ABD05A210B548200BEEFF4"
BuildableName = "SkeletonViewExampleUICollectionView.app"
BlueprintName = "SkeletonViewExampleUICollectionView"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "42ABD05A210B548200BEEFF4"
BuildableName = "SkeletonViewExampleUICollectionView.app"
BlueprintName = "SkeletonViewExampleUICollectionView"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,39 @@
//
// SkeletonAnimationBuilder.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 17/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
public typealias SkeletonLayerAnimation = (CALayer) -> CAAnimation
public class SkeletonAnimationBuilder {
public init() { }
public func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5, autoreverses: Bool = false) -> SkeletonLayerAnimation {
{ _ in
let startPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.startPoint))
startPointAnim.fromValue = direction.startPoint.from
startPointAnim.toValue = direction.startPoint.to
let endPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.endPoint))
endPointAnim.fromValue = direction.endPoint.from
endPointAnim.toValue = direction.endPoint.to
let animGroup = CAAnimationGroup()
animGroup.animations = [startPointAnim, endPointAnim]
animGroup.duration = duration
animGroup.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
animGroup.repeatCount = .infinity
animGroup.autoreverses = autoreverses
animGroup.isRemovedOnCompletion = false
return animGroup
}
}
}
@@ -0,0 +1,41 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// SkeletonAppearance.swift
//
import UIKit
public enum SkeletonAppearance {
public static var `default` = SkeletonViewAppearance.shared
}
// codebeat:disable[TOO_MANY_IVARS]
public class SkeletonViewAppearance {
static var shared = SkeletonViewAppearance()
public var tintColor: UIColor = .skeletonDefault
public var gradient = SkeletonGradient(baseColor: .skeletonDefault)
public var multilineHeight: CGFloat = 15
public lazy var textLineHeight: SkeletonTextLineHeight = .fixed(SkeletonAppearance.default.multilineHeight)
public var multilineSpacing: CGFloat = 10
public var multilineLastLineFillPercent: Int = 70
public var multilineCornerRadius: Int = 0
public var renderSingleLineAsView: Bool = false
}
// codebeat:enable[TOO_MANY_IVARS]
@@ -13,20 +13,28 @@ public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int
func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier
func collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -> ReusableCellIdentifier?
func collectionSkeletonView(_ skeletonView: UICollectionView, skeletonCellForItemAt indexPath: IndexPath) -> UICollectionViewCell?
func collectionSkeletonView(_ skeletonView: UICollectionView, prepareCellForSkeleton cell: UICollectionViewCell, at indexPath: IndexPath)
}
public extension SkeletonCollectionViewDataSource {
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return UICollectionView.automaticNumberOfSkeletonItems
UICollectionView.automaticNumberOfSkeletonItems
}
func collectionSkeletonView(_ skeletonView: UICollectionView,
supplementaryViewIdentifierOfKind: String,
at indexPath: IndexPath) -> ReusableCellIdentifier? {
return nil
func collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -> ReusableCellIdentifier? {
nil
}
func numSections(in collectionSkeletonView: UICollectionView) -> Int { return 1 }
func numSections(in collectionSkeletonView: UICollectionView) -> Int {
1
}
func collectionSkeletonView(_ skeletonView: UICollectionView, skeletonCellForItemAt indexPath: IndexPath) -> UICollectionViewCell? {
nil
}
func collectionSkeletonView(_ skeletonView: UICollectionView, prepareCellForSkeleton cell: UICollectionViewCell, at indexPath: IndexPath) { }
}
public protocol SkeletonCollectionViewDelegate: UICollectionViewDelegate { }
@@ -8,10 +8,18 @@
import UIKit
extension UITableView {
public static let automaticNumberOfSkeletonRows = -1
}
public typealias ReusableHeaderFooterIdentifier = String
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
func collectionSkeletonView(_ skeletonView: UITableView, skeletonCellForRowAt indexPath: IndexPath) -> UITableViewCell?
func collectionSkeletonView(_ skeletonView: UITableView, prepareCellForSkeleton cell: UITableViewCell, at indexPath: IndexPath)
}
public extension SkeletonTableViewDataSource {
@@ -27,6 +35,12 @@ public extension SkeletonTableViewDataSource {
func collectionSkeletonView(_ skeletonView: UITableView, cellIdenfierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier {
return collectionSkeletonView(skeletonView, cellIdentifierForRowAt: indexPath)
}
func collectionSkeletonView(_ skeletonView: UITableView, skeletonCellForRowAt indexPath: IndexPath) -> UITableViewCell? {
nil
}
func collectionSkeletonView(_ skeletonView: UITableView, prepareCellForSkeleton cell: UITableViewCell, at indexPath: IndexPath) { }
}
public protocol SkeletonTableViewDelegate: UITableViewDelegate {
@@ -0,0 +1,94 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// Deprecated.swift
//
// Created by Juanpe Catalán on 18/8/21.
import UIKit
public extension Notification.Name {
@available(*, deprecated, renamed: "skeletonWillAppear")
static let willBeginShowingSkeletons = Notification.Name.skeletonWillAppearNotification
@available(*, deprecated, renamed: "skeletonDidAppear")
static let didShowSkeletons = Notification.Name.skeletonDidAppearNotification
@available(*, deprecated, renamed: "skeletonWillUpdate")
static let willBeginUpdatingSkeletons = Notification.Name.skeletonWillUpdateNotification
@available(*, deprecated, renamed: "skeletonDidUpdate")
static let didUpdateSkeletons = Notification.Name.skeletonDidUpdateNotification
@available(*, deprecated, renamed: "skeletonWillDisappear")
static let willBeginHidingSkeletons = Notification.Name.skeletonWillDisappearNotification
@available(*, deprecated, renamed: "skeletonDidDisappear")
static let didHideSkeletons = Notification.Name.skeletonDidDisappearNotification
}
public extension UIView {
@available(*, deprecated, renamed: "sk.treeNodesDescription")
var skeletonDescription: String {
sk.skeletonTreeDescription
}
@available(*, deprecated, renamed: "sk.isSkeletonActive")
var isSkeletonActive: Bool {
sk.isSkeletonActive
}
}
public extension UILabel {
@IBInspectable
@available(*, deprecated, renamed: "skeletonTextLineHeight")
var useFontLineHeight: Bool {
get {
textLineHeight == .relativeToFont
}
set {
textLineHeight = newValue ? .relativeToFont : .fixed(SkeletonAppearance.default.multilineHeight)
}
}
}
public extension UITextView {
@IBInspectable
@available(*, deprecated, renamed: "skeletonTextLineHeight")
var useFontLineHeight: Bool {
get {
textLineHeight == .relativeToFont
}
set {
textLineHeight = newValue ? .relativeToFont : .fixed(SkeletonAppearance.default.multilineHeight)
}
}
}
public extension SkeletonViewAppearance {
@available(*, deprecated, renamed: "textLineHeight")
var useFontLineHeight: Bool {
get {
textLineHeight == .relativeToFont
}
set {
textLineHeight = newValue ? .relativeToFont : .fixed(SkeletonAppearance.default.multilineHeight)
}
}
}
@@ -0,0 +1,25 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// Notification+SkeletonFlow.swift
//
// Created by Juanpe Catalán on 18/8/21.
import Foundation
public extension Notification.Name {
static let skeletonWillAppearNotification = Notification.Name("skeletonWillAppear")
static let skeletonDidAppearNotification = Notification.Name("skeletonDidAppear")
static let skeletonWillUpdateNotification = Notification.Name("skeletonWillUpdate")
static let skeletonDidUpdateNotification = Notification.Name("skeletonDidUpdate")
static let skeletonWillDisappearNotification = Notification.Name("skeletonWillDisappear")
static let skeletonDidDisappearNotification = Notification.Name("skeletonDidDisappear")
}
@@ -0,0 +1,29 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// GradientDirection.swift
//
// Created by Juanpe Catalán on 19/8/21.
import UIKit
public enum GradientDirection {
case leftRight
case rightLeft
case topBottom
case bottomTop
case topLeftBottomRight
case bottomRightTopLeft
public func slidingAnimation(duration: CFTimeInterval = 1.5, autoreverses: Bool = false) -> SkeletonLayerAnimation {
return SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: self, duration: duration, autoreverses: autoreverses)
}
}
@@ -1,14 +1,20 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// SkeletonGradient.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 05/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
public struct SkeletonGradient {
private let gradientColors: [UIColor]
public var colors: [UIColor] {
@@ -22,4 +28,5 @@ public struct SkeletonGradient {
self.gradientColors = baseColor.makeGradient()
}
}
}
@@ -0,0 +1,30 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// SkeletonTextLineHeight.swift
//
// Created by Juanpe Catalán on 22/11/21.
import UIKit
public enum SkeletonTextLineHeight: Equatable {
/// Calculates the line height based on the font line height.
case relativeToFont
/// Calculates the line height based on the height constraints.
///
/// If no constraints exist, the height will be set to the `multilineHeight`
/// value defined in the `SkeletonAppearance`.
case relativeToConstraints
/// Returns the specific height specified as the associated value.
case fixed(CGFloat)
}
@@ -0,0 +1,39 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// SkeletonType.swift
//
// Created by Juanpe Catalán on 19/8/21.
import UIKit
public enum SkeletonType {
case solid
case gradient
var layer: CALayer {
switch self {
case .solid:
return CALayer()
case .gradient:
return CAGradientLayer()
}
}
func defaultLayerAnimation(isRTL: Bool) -> SkeletonLayerAnimation {
switch self {
case .solid:
return { $0.pulse }
case .gradient:
return { SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: isRTL ? .rightLeft : .leftRight) }()
}
}
}
@@ -0,0 +1,45 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// SkeletonExtended.swift
//
// Created by Juanpe Catalán on 23/8/21.
import Foundation
/// Type that acts as a generic extension point for all `SkeletonViewExtended` types.
public struct SkeletonViewExtension<ExtendedType> {
/// Stores the type or meta-type of any extended type.
public private(set) var type: ExtendedType
/// Create an instance from the provided value.
///
/// - Parameter type: Instance being extended.
public init(_ type: ExtendedType) {
self.type = type
}
}
/// Protocol describing the `sk` extension points for SkeletonView extended types.
public protocol SkeletonViewExtended {
/// Type being extended.
associatedtype ExtendedType
/// Instance SkeletonView extension point.
var sk: SkeletonViewExtension<ExtendedType> { get set }
}
extension SkeletonViewExtended {
/// Instance SkeletonView extension point.
public var sk: SkeletonViewExtension<Self> {
get { SkeletonViewExtension(self) }
// swiftlint:disable:next unused_setter_value
set {}
}
}
@@ -0,0 +1,150 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// PublicSkeletonView.swift
//
// Created by Juanpe Catalán on 18/8/21.
import UIKit
public extension UIView {
/// Shows the skeleton without animation using the view that calls this method as root view.
///
/// - Parameters:
/// - color: The color of the skeleton. Defaults to `SkeletonAppearance.default.tintColor`.
/// - transition: The style of the transition when the skeleton appears. Defaults to `.crossDissolve(0.25)`.
func showSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor, transition: SkeletonTransitionStyle = .crossDissolve(0.25)) {
_delayedShowSkeletonWorkItem?.cancel()
let config = SkeletonConfig(type: .solid, colors: [color], transition: transition)
showSkeleton(skeletonConfig: config)
}
/// Shows the skeleton using the view that calls this method as root view.
///
/// - Parameters:
/// - color: The color of the skeleton. Defaults to `SkeletonAppearance.default.tintColor`.
/// - animated: If the skeleton is animated or not. Defaults to `true`.
/// - delay: The amount of time (measured in seconds) to wait before show the skeleton.
/// - transition: The style of the transition when the skeleton appears. Defaults to `.crossDissolve(0.25)`.
func showSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor, animated: Bool = true, delay: TimeInterval, transition: SkeletonTransitionStyle = .crossDissolve(0.25)) {
_delayedShowSkeletonWorkItem?.cancel()
_delayedShowSkeletonWorkItem = DispatchWorkItem { [weak self] in
let config = SkeletonConfig(type: .solid, colors: [color], animated: animated, transition: transition)
self?.showSkeleton(skeletonConfig: config)
}
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: _delayedShowSkeletonWorkItem!)
}
/// Shows the gradient skeleton without animation using the view that calls this method as root view.
///
/// - Parameters:
/// - gradient: The gradient of the skeleton. Defaults to `SkeletonAppearance.default.gradient`.
/// - transition: The style of the transition when the skeleton appears. Defaults to `.crossDissolve(0.25)`.
func showGradientSkeleton(usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient, transition: SkeletonTransitionStyle = .crossDissolve(0.25)) {
_delayedShowSkeletonWorkItem?.cancel()
let config = SkeletonConfig(type: .gradient, colors: gradient.colors, transition: transition)
showSkeleton(skeletonConfig: config)
}
/// Shows the gradient skeleton using the view that calls this method as root view.
///
/// - Parameters:
/// - gradient: The gradient of the skeleton. Defaults to `SkeletonAppearance.default.gradient`.
/// - animated: If the skeleton is animated or not. Defaults to `true`.
/// - delay: The amount of time (measured in seconds) to wait before show the skeleton.
/// - transition: The style of the transition when the skeleton appears. Defaults to `.crossDissolve(0.25)`.
func showGradientSkeleton(
usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient,
animated: Bool = true,
delay: TimeInterval,
transition: SkeletonTransitionStyle = .crossDissolve(0.25)
) {
_delayedShowSkeletonWorkItem?.cancel()
_delayedShowSkeletonWorkItem = DispatchWorkItem { [weak self] in
let config = SkeletonConfig(type: .gradient, colors: gradient.colors, animated: animated, transition: transition)
self?.showSkeleton(skeletonConfig: config)
}
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: _delayedShowSkeletonWorkItem!)
}
/// Shows the animated skeleton using the view that calls this method as root view.
///
/// If animation is nil, sliding animation will be used, with direction left to right.
///
/// - Parameters:
/// - color: The color of skeleton. Defaults to `SkeletonAppearance.default.tintColor`.
/// - animation: The animation of the skeleton. Defaults to `nil`.
/// - transition: The style of the transition when the skeleton appears. Defaults to `.crossDissolve(0.25)`.
func showAnimatedSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor, animation: SkeletonLayerAnimation? = nil, transition: SkeletonTransitionStyle = .crossDissolve(0.25)) {
_delayedShowSkeletonWorkItem?.cancel()
let config = SkeletonConfig(type: .solid, colors: [color], animated: true, animation: animation, transition: transition)
showSkeleton(skeletonConfig: config)
}
/// Shows the gradient skeleton without animation using the view that calls this method as root view.
///
/// If animation is nil, sliding animation will be used, with direction left to right.
///
/// - Parameters:
/// - gradient: The gradient of the skeleton. Defaults to `SkeletonAppearance.default.gradient`.
/// - animation: The animation of the skeleton. Defaults to `nil`.
/// - transition: The style of the transition when the skeleton appears. Defaults to `.crossDissolve(0.25)`.
func showAnimatedGradientSkeleton(usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient, animation: SkeletonLayerAnimation? = nil, transition: SkeletonTransitionStyle = .crossDissolve(0.25)) {
_delayedShowSkeletonWorkItem?.cancel()
let config = SkeletonConfig(type: .gradient, colors: gradient.colors, animated: true, animation: animation, transition: transition)
showSkeleton(skeletonConfig: config)
}
func updateSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor) {
let config = SkeletonConfig(type: .solid, colors: [color])
updateSkeleton(skeletonConfig: config)
}
func updateGradientSkeleton(usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient) {
let config = SkeletonConfig(type: .gradient, colors: gradient.colors)
updateSkeleton(skeletonConfig: config)
}
func updateAnimatedSkeleton(usingColor color: UIColor = SkeletonAppearance.default.tintColor, animation: SkeletonLayerAnimation? = nil) {
let config = SkeletonConfig(type: .solid, colors: [color], animated: true, animation: animation)
updateSkeleton(skeletonConfig: config)
}
func updateAnimatedGradientSkeleton(usingGradient gradient: SkeletonGradient = SkeletonAppearance.default.gradient, animation: SkeletonLayerAnimation? = nil) {
let config = SkeletonConfig(type: .gradient, colors: gradient.colors, animated: true, animation: animation)
updateSkeleton(skeletonConfig: config)
}
func layoutSkeletonIfNeeded() {
_flowDelegate?.willBeginLayingSkeletonsIfNeeded(rootView: self)
recursiveLayoutSkeletonIfNeeded(root: self)
}
func hideSkeleton(reloadDataAfter reload: Bool = true, transition: SkeletonTransitionStyle = .crossDissolve(0.25)) {
_delayedShowSkeletonWorkItem?.cancel()
_flowDelegate?.willBeginHidingSkeletons(rootView: self)
recursiveHideSkeleton(reloadDataAfter: reload, transition: transition, root: self)
}
func startSkeletonAnimation(_ anim: SkeletonLayerAnimation? = nil) {
subviewsSkeletonables.recursiveSearch(leafBlock: startSkeletonLayerAnimationBlock(anim)) { subview in
subview.startSkeletonAnimation(anim)
}
}
func stopSkeletonAnimation() {
subviewsSkeletonables.recursiveSearch(leafBlock: stopSkeletonLayerAnimationBlock) { subview in
subview.stopSkeletonAnimation()
}
}
}
@@ -0,0 +1,32 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// CALayer+Animations.swift
//
// Created by Juanpe Catalán on 18/8/21.
import UIKit
public extension CALayer {
var pulse: CAAnimation {
let pulseAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.backgroundColor))
pulseAnimation.fromValue = backgroundColor
// swiftlint:disable:next force_unwrapping
pulseAnimation.toValue = UIColor(cgColor: backgroundColor!).complementaryColor.cgColor
pulseAnimation.duration = 1
pulseAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
pulseAnimation.autoreverses = true
pulseAnimation.repeatCount = .infinity
pulseAnimation.isRemovedOnCompletion = false
return pulseAnimation
}
}
@@ -0,0 +1,34 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// UICollectionView+Extensions.swift
//
// Created by Juanpe Catalán on 19/8/21.
import UIKit
public extension UICollectionView {
static let automaticNumberOfSkeletonItems = -1
func prepareSkeleton(completion: @escaping (Bool) -> Void) {
guard let originalDataSource = self.dataSource as? SkeletonCollectionViewDataSource,
!(originalDataSource is SkeletonCollectionDataSource)
else { return }
let dataSource = SkeletonCollectionDataSource(collectionViewDataSource: originalDataSource, rowHeight: 0.0)
self.skeletonDataSource = dataSource
performBatchUpdates({
self.reloadData()
}) { done in
completion(done)
}
}
}
@@ -0,0 +1,36 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// UILabel+IBInspectable.swift
//
// Created by Juanpe Catalán on 19/8/21.
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 = newValue }
}
@IBInspectable
var skeletonLineSpacing: CGFloat {
get { return multilineSpacing }
set { multilineSpacing = newValue }
}
}
@@ -0,0 +1,36 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// UILabel+SKExtensions.swift
//
// Created by Juanpe Catalán on 23/8/21.
import UIKit
public extension UILabel {
var skeletonPaddingInsets: UIEdgeInsets {
get {
paddingInsets
}
set {
paddingInsets = newValue
}
}
var skeletonTextLineHeight: SkeletonTextLineHeight {
get {
textLineHeight
}
set {
textLineHeight = newValue
}
}
}
@@ -0,0 +1,36 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// UITextView+IBInspectable.swift
//
// Created by Juanpe Catalán on 19/8/21.
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 = newValue }
}
@IBInspectable
var skeletonLineSpacing: CGFloat {
get { return multilineSpacing }
set { multilineSpacing = newValue }
}
}
@@ -0,0 +1,36 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// UITextView+SKExtensions.swift
//
// Created by Juanpe Catalán on 19/8/21.
import UIKit
public extension UITextView {
var skeletonPaddingInsets: UIEdgeInsets {
get {
paddingInsets
}
set {
paddingInsets = newValue
}
}
var skeletonTextLineHeight: SkeletonTextLineHeight {
get {
textLineHeight
}
set {
textLineHeight = newValue
}
}
}
@@ -0,0 +1,42 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// UIView+IBInspectable.swift
//
// Created by Juanpe Catalán on 18/8/21.
import UIKit
public extension UIView {
@IBInspectable
var isSkeletonable: Bool {
get { _skeletonable }
set { _skeletonable = newValue }
}
@IBInspectable
var isHiddenWhenSkeletonIsActive: Bool {
get { _hiddenWhenSkeletonIsActive }
set { _hiddenWhenSkeletonIsActive = newValue }
}
@IBInspectable
var isUserInteractionDisabledWhenSkeletonIsActive: Bool {
get { _disabledWhenSkeletonIsActive }
set { _disabledWhenSkeletonIsActive = newValue }
}
@IBInspectable
var skeletonCornerRadius: Float {
get { _skeletonableCornerRadius }
set { _skeletonableCornerRadius = newValue }
}
}
@@ -0,0 +1,33 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// UIView+SKExtensions.swift
//
// Created by Juanpe Catalán on 18/8/21.
import UIKit
public extension SkeletonViewExtension where ExtendedType: UIView {
/// Returns a string that describes the hierarchy of the skeleton, indicating
/// whether the receiver is skeletonable and all skeletonable children.
var skeletonTreeDescription: String {
guard let theJSONData = try? JSONSerialization.data(withJSONObject: treeNode.dictionaryRepresentation, options: [.prettyPrinted]) else {
skeletonLog("Skeleton tree generation has failed!")
return ""
}
return String(data: theJSONData, encoding: .utf8)!
}
var isSkeletonActive: Bool {
type._status == .on || type.subviewsSkeletonables.contains(where: { $0.sk.isSkeletonActive })
}
}

Some files were not shown because too many files have changed in this diff Show More