Compare commits

..

113 Commits

Author SHA1 Message Date
Juanpe Catalán 6887600a88 Merge branch 'main' into feature/xcframework
# Conflicts:
#	fastlane/README.md
2021-02-22 21:29:33 +01:00
Juanpe Catalán f3baeedc14 Update pod_lib_lint.yml 2021-02-15 15:44:10 +01:00
Juanpe Catalán 29f7d8fd6a create pod lib lint workflow 2021-02-15 15:39:32 +01:00
Juanpe Catalán 83e1600a73 remove useless code from release workflow 2021-02-15 15:34:26 +01:00
Juanpe Catalán 450cecbd9c update release workflow 2021-02-15 15:33:44 +01:00
Juanpe 1676f8720a Bump version 1.13.0 2021-02-15 14:23:42 +00:00
Juanpe Catalán 32ab6d3852 unify jobs 2021-02-15 15:19:09 +01:00
Juanpe Catalán 301ad0c040 update swift version in podspec 2021-02-12 00:26:16 +01:00
Juanpe Catalán 3131dc829d refactor: create XCFramework 2021-02-12 00:17:39 +01:00
Josh Brunner 7ce5e0623a Fixed a deprecation warning where the AssociatedObjects protocol was inheriting from class instead of AnyObject per Xcode's suggestion (#376) 2021-02-08 23:06:32 +01:00
Juanpe Catalán f0c7d2d6a0 modify release workflow steps 2021-02-08 10:11:52 +01:00
Juanpe Catalán 26476fd3ed bump version 1.12.1 2021-02-08 10:07:11 +01:00
Juanpe Catalán f0c2cf4ab4 Update stale.yml 2021-02-08 09:53:37 +01:00
Juanpe Catalán cadf8bb136 Update stale.yml 2021-02-08 09:45:48 +01:00
Juanpe Catalán 91c8f953ca Merge branch 'main' of https://github.com/Juanpe/SkeletonView into main 2021-02-08 09:41:38 +01:00
Juanpe Catalán 0a91aebf2a fix: recover isUserInteractionEnabled value when the skeleton disappears (#375) 2021-02-08 09:41:33 +01:00
Juanpe Catalán 7d8a057b64 fix: recover isUserInteractionEnabled value when the skeleton disappears (#375) 2021-02-08 09:38:34 +01:00
Juanpe Catalán 06f7d240ff update all “develop” references (#374) 2021-02-05 21:51:24 +01:00
Juanpe Catalán c4c725eea3 revert change in "change-template" 2021-02-03 14:21:27 +01:00
Juanpe Catalán cc9dbdb499 update "change-template" in release-drafter.yml 2021-02-03 14:20:16 +01:00
Keshavamurthy GN c6dfcf9c1a Fixed: UITextField placeholder text is visible while skeleton is showing (#356)
* Fixed: UITextField placeholder text is visible while skeleton is showing #345
Setting placeholder to nil on prepareViewForSkeleton() method
Created RecoverableTextFieldState, which has textColor and placeholder properties, Added UITextField extension in Recoverable.swift, setting the values on recoverViewStage 'forced' is true

* Update PrepareForSkeletonProtocol.swift
2021-02-03 14:18:30 +01:00
Juanpe Catalán dd7e5243bd fix syntax in release.yml 2021-02-03 14:04:44 +01:00
Juanpe Catalán 7e002ddce0 update release-drafter config considering a feature as minor 2021-02-03 14:00:43 +01:00
Juanpe Catalán 6dcfb325dc remove SwiftLint's warnings (#372) 2021-02-03 09:21:14 +01:00
Juanpe Catalán 7b5739295a Remove CHANGELOG condition in Dangerfile 2021-02-03 09:04:59 +01:00
Juanpe Catalán 2e1808ea50 fix: remove temp height constraints after hiding the skeleton (#371) 2021-02-03 09:03:40 +01:00
Juanpe Catalán cec3aeb781 refactor release.yml file 2021-02-02 08:59:26 +01:00
Juanpe Catalán b16400294d update commit job 2021-02-01 19:44:05 +01:00
Juanpe Catalán abb8ea55f6 remove scripts folder 2021-02-01 19:39:00 +01:00
Juanpe Catalán c833da20f8 Merge branch 'develop' of https://github.com/Juanpe/SkeletonView into develop 2021-02-01 19:36:17 +01:00
Juanpe Catalán 292fadf5b0 bump version 1.12.0 2021-02-01 19:36:06 +01:00
Juanpe Catalán 2ce041901c remove pod lib lint 2021-02-01 19:35:10 +01:00
Juanpe Catalán 961cc77661 update order release workflow 2021-02-01 19:33:23 +01:00
Juanpe Catalán 11b623fb13 Update release.yml 2021-02-01 19:23:48 +01:00
Juanpe Catalán 4899802b01 Update release.yml 2021-02-01 19:14:29 +01:00
Juanpe Catalán 0dfe1ca43b Update release.yml 2021-02-01 19:11:00 +01:00
Juanpe Catalán 499d01c232 Update release.yml 2021-02-01 19:07:22 +01:00
Juanpe Catalán f8f368ab8a Update release.yml 2021-02-01 19:02:14 +01:00
Juanpe Catalán 023a57a763 Merge branch 'develop' of https://github.com/Juanpe/SkeletonView into develop 2021-02-01 19:00:58 +01:00
Juanpe Catalán d426a0916e create new lane to bump podspec version 2021-02-01 19:00:51 +01:00
Juanpe Catalán 611c248c51 Update release.yml 2021-02-01 18:52:49 +01:00
Juanpe Catalán 6f20c34d56 Update release.yml 2021-02-01 18:40:01 +01:00
Juanpe Catalán be25b572f8 Update release.yml 2021-02-01 18:27:51 +01:00
Juanpe Catalán 3c67812453 Update main.yml 2021-02-01 18:23:39 +01:00
Juanpe Catalán 0431eb2a7d Update release.yml 2021-02-01 18:20:55 +01:00
Juanpe Catalán fa0b95d923 Update release-drafter.yml 2021-02-01 18:18:15 +01:00
Juanpe Catalán 523cd1c657 Create release_notes.yml 2021-02-01 18:14:27 +01:00
Juanpe Catalán 29e65c70d3 Create release-drafter.yml 2021-02-01 18:13:12 +01:00
Juanpe Catalán 4b7360a011 Update release.yml 2021-02-01 18:12:11 +01:00
Juanpe Catalán 2753c54216 feat: add script to update version 2021-02-01 18:10:22 +01:00
Juanpe Catalán c7b3bc67be Update release.yml 2021-02-01 18:08:03 +01:00
Juanpe Catalán 0c8bbf1fed Update release.yml 2021-02-01 17:58:55 +01:00
Juanpe Catalán 2e99bc98bf Update release.yml 2021-02-01 17:57:43 +01:00
Juanpe Catalán d5d52d1416 Update release.yml 2021-02-01 17:41:18 +01:00
Juanpe Catalán 91c7735d0c Create release.yml 2021-02-01 15:27:24 +01:00
Juanpe Catalán 18c5c1deb8 feat: remove useless corner radius constraint (#369)
* remove useless corner radius constraint

* update CHANGELOG
2021-02-01 12:13:48 +01:00
Juanpe Catalán 1ecfa31743 feat: add more templates to create issues (#368) 2021-01-31 17:11:46 +01:00
Juanpe Catalán 82b70ea1ee Update validations.yml 2021-01-31 14:20:25 +01:00
Juanpe Catalán d8ee06f1c5 Update validations.yml 2021-01-31 13:44:08 +01:00
Juanpe Catalán 13ce7426dd Update validations.yml 2021-01-31 13:36:38 +01:00
Juanpe Catalán 7d5039536c Update validations.yml 2021-01-31 13:28:12 +01:00
Juanpe Catalán b7a7731784 Update validations.yml 2021-01-31 13:22:01 +01:00
Juanpe Catalán 07f92d098a Update validations.yml 2021-01-31 13:06:33 +01:00
Juanpe Catalán f45405c9d5 Update validations.yml 2021-01-31 12:58:44 +01:00
Juanpe Catalán 768354ca35 Update validations.yml 2021-01-31 12:27:12 +01:00
Juanpe Catalán d5819763a1 Update validations.yml 2021-01-31 12:26:05 +01:00
Juanpe Catalán a73fc993aa Update validations.yml 2021-01-31 12:07:18 +01:00
Juanpe Catalán 0d027b5927 Update validations.yml 2021-01-31 11:50:44 +01:00
Juanpe Catalán bc482f58b3 Update and rename Validations.yml to validations.yml 2021-01-31 11:11:17 +01:00
Juanpe Catalán 78e941e01c Update and rename PR.yml to Validations.yml 2021-01-30 21:25:25 +01:00
Juanpe Catalán 7282008606 Update PR.yml 2021-01-28 10:40:24 +01:00
Juanpe Catalán 52d657faa0 Update PR.yml 2021-01-28 09:50:52 +01:00
Juanpe Catalán cba096becf Update PR.yml 2021-01-28 09:46:17 +01:00
Juanpe Catalán c095f49028 Update PR.yml 2021-01-28 09:34:44 +01:00
Juanpe Catalán 89e292c11b fix: broken workflow link 2021-01-27 17:29:40 +01:00
Juanpe Catalán 5089295771 feat: update CI badge in README files 2021-01-27 17:27:10 +01:00
Juanpe Catalán 39971af22d feat: update Github actions 2021-01-27 17:25:23 +01:00
Juanpe Catalán 81d182259d feat: refactor CI workflows 2021-01-27 17:24:16 +01:00
Juanpe Catalán 1d82545a3d Merge pull request #360 from Juanpe/test_action 2021-01-26 18:06:59 +01:00
Juanpe Catalán 9086d7e874 use GITHUB TOKEN 2021-01-26 18:02:43 +01:00
Juanpe Catalán 666ebdf472 fix syntax error 2021-01-26 17:56:53 +01:00
Juanpe Catalán 5a5d7b66e7 update action trigger 2021-01-26 17:54:50 +01:00
Juanpe Catalán 78f2bbe9f1 udpate danger action 2021-01-26 16:59:22 +01:00
Juanpe Catalán c7133a6711 Merge pull request #357 from keshavamurthy1/fix/refactored_removed_unused_code
Removed duplicate code in SkeletonCollectionDelegate
2021-01-22 14:26:54 +01:00
Juanpe Catalán aee5cdfd8f Merge pull request #359 from keshavamurthy1/fix/skeletonview_respecting_font_height_than_view_height
Fixed: SkeletonView respecting Font's height, rather than the `UIView…
2021-01-22 14:23:12 +01:00
Juanpe Catalán 638c535767 Update checks.yml 2021-01-22 13:36:26 +01:00
Juanpe Catalán 782dd45b33 Update checks.yml 2021-01-22 13:33:38 +01:00
Keshavamurthy GN 073baa6483 Update UIView+Frame.swift 2021-01-22 17:45:36 +05:30
Keshavamurthy GN a26dbf7c89 Reverted the iOS 10 check as per the review comment 2021-01-22 17:28:32 +05:30
Juanpe Catalán 7ebde2b030 Update checks.yml 2021-01-22 12:51:51 +01:00
Keshavamurthy GN 4009ed2b1e Fixed: SkeletonView respecting Font's height, rather than the UIView actual height #353
Using Label height from the HeightConstraint if there is any instead of the Label Font line height
if no HeightConstraint set, will be using SkeletonAppearance.default.multilineHeight as it was before
2021-01-21 12:52:17 +05:30
Keshavamurthy GN a246c16cfe Removed duplicate code in SkeletonCollectionDelegate
Removed check for older versions in UIView+Frame
Removed return on single lines (Implicit Returns)
2021-01-18 18:41:23 +05:30
Juanpe Catalán ef8e4578d7 Update CHANGELOG.md 2020-10-29 14:27:42 +01:00
Juanpe Catalán 46e2180c4b docs: bump version 1.11.0 and update CHANGELOG file 2020-10-29 14:20:20 +01:00
Juanpe Catalán f32c420165 Merge pull request #344 from Juanpe/feature/resize_labels_based_on_number_of_lines
Feature/resize labels based on number of lines
2020-10-29 14:17:57 +01:00
Juanpe Catalán 0ca38d8ea1 doc: update CHANGELOG file 2020-10-29 14:13:16 +01:00
Juanpe Catalán 9ed337ba53 Merge branch 'develop' of https://github.com/Juanpe/SkeletonView into feature/resize_labels_based_on_number_of_lines 2020-10-29 14:12:09 +01:00
Juanpe Catalán 932a1f6e6e Merge pull request #340 from yzhao198/fixMultiLineAndPadding
Fix incorrect padding and multiline layer frame calculation
2020-10-26 08:11:37 +01:00
Yang Zhao 5cd08fb77c Updated CHANGELOG.md. 2020-10-25 18:40:02 -06:00
Yang Zhao f7cb021a93 Fixed incorrect padding, and incorrect multiline layer frame calculation. 2020-10-25 18:32:31 -06:00
Juanpe Catalán 4fbfbeca55 feat: update layout to desired height 2020-10-22 00:48:23 +02:00
Juanpe Catalán c92461ae5c fix: shows at least one line 2020-10-21 14:35:48 +02:00
Juanpe Catalán efed2e7f32 Merge pull request #341 from Juanpe/feature/animation_autoreverses
Support autoreverses in gradient animations
2020-10-19 11:52:16 +02:00
Juanpe Catalán 52cbd3ae2c doc: Include PR #341 in the CHANGELOG file 2020-10-19 11:49:08 +02:00
Juanpe Catalán a349f7174c feat: support autoreverses animations for gradients 2020-10-19 11:41:57 +02:00
Juanpe Catalán a58c97eb1a Update CHANGELOG.md 2020-10-19 10:36:48 +02:00
Juanpe Catalán 8e6fea2de3 Update CHANGELOG.md 2020-10-19 10:36:33 +02:00
Juanpe Catalán bf417d6bf8 Update CHANGELOG.md 2020-10-19 10:36:16 +02:00
Juanpe Catalán c3295531be Merge pull request #339 from mohn93/develop
Add  hiddenWhenSkeletonIsActive property
2020-10-19 10:34:43 +02:00
Mohanned Binmiskeen a87f7302c0 Documentation for isHiddenWhenSkeletonIsActive 2020-10-16 22:46:20 +02:00
Juanpe Catalán 5e22f38454 Upgrade Danger version 3.5.0 2020-10-07 13:07:29 +02:00
Mohanned Binmiskeen 0dbdb9064d Add hiddenWhenSkeletonIsActive property which will hide the view when the skeleton animation starts 2020-10-06 16:03:55 +02:00
Juanpe Catalán c8efc4ccb1 doc: Update CHANGELOG 2020-10-02 17:33:48 +02:00
87 changed files with 1476 additions and 3423 deletions
@@ -1,3 +1,12 @@
---
name: "\U0001F41B Bug report"
about: Report a bug or unexpected behavior while using SkeletonView
title: ''
labels: bug
assignees: ''
---
### Description
Describe your issue here.
@@ -10,8 +19,8 @@ Describe your issue here.
- [ ] discussion
### Requirements (place an `x` in each of the `[ ]`)
* [ ] I've read and understood the [Contributing guidelines](https://github.com/Juanpe/SkeletonView/blob/develop/CONTRIBUTING.md) and have done my best effort to follow them.
* [ ] I've read and agree to the [Code of Conduct](https://github.com/Juanpe/SkeletonView/blob/develop/CODE_OF_CONDUCT.md).
* [ ] I've read and understood the [Contributing guidelines](https://github.com/Juanpe/SkeletonView/blob/main/CONTRIBUTING.md) and have done my best effort to follow them.
* [ ] I've read and agree to the [Code of Conduct](https://github.com/Juanpe/SkeletonView/blob/main/CODE_OF_CONDUCT.md).
* [ ] I've searched for any related issues and avoided creating a duplicate issue.
---
+28
View File
@@ -0,0 +1,28 @@
---
name: "\U0001F4E3 Feedback"
about: Give us general feedback about the SkeletonView
title: ''
labels: feedback
assignees: ''
---
# SkeletonView Feedback
You can use this template to give us structured feedback or just wipe it and leave us a note. Thank you!
## What have you loved?
_eg "the nice colors"_
## What was confusing or gave you pause?
_eg "it did something unexpected"_
## Are there features you'd like to see added?
_eg "SkeletonView should be compatible with SwiftUI"_
## Anything else?
_eg "have a nice day"_
@@ -0,0 +1,20 @@
---
name: "⭐ Submit a request"
about: Surface a feature or problem that you think should be solved
title: ''
labels: enhancement
assignees: ''
---
### Describe the feature or problem youd like to solve
A clear and concise description of what the feature or problem is.
### Proposed solution
How will it benefit SkeletonView and its users?
### Additional context
Add any other context like screenshots or mockups are helpful, if applicable.
+2 -2
View File
@@ -3,5 +3,5 @@
Describe the goal of this PR. Mention any related Issue numbers.
### Requirements (place an `x` in each of the `[ ]`)
* [ ] I've read and understood the [Contributing guidelines](https://github.com/Juanpe/SkeletonView/blob/develop/CONTRIBUTING.md) and have done my best effort to follow them.
* [ ] I've read and agree to the [Code of Conduct](https://github.com/Juanpe/SkeletonView/blob/develop/CODE_OF_CONDUCT.md).
* [ ] I've read and understood the [Contributing guidelines](https://github.com/Juanpe/SkeletonView/blob/main/CONTRIBUTING.md) and have done my best effort to follow them.
* [ ] I've read and agree to the [Code of Conduct](https://github.com/Juanpe/SkeletonView/blob/main/CODE_OF_CONDUCT.md).
+39
View File
@@ -0,0 +1,39 @@
name-template: '📦 $RESOLVED_VERSION'
tag-template: '$RESOLVED_VERSION'
category-template: '#### $TITLE'
change-template: '- **#$NUMBER**: $TITLE - @$AUTHOR'
template: |
$CHANGES
categories:
- title: '🚨 Breaking'
label: 'breaking'
- title: '🔬Improvements'
label: '💡 enhancement'
- title: '🙌 New'
label: 'feature'
- title: '🩹 Bug fixes'
label: '🐞 bug'
- title: '⚙️ Maintenance'
label: '⚙️ maintenance'
- title: '📚 Documentation'
label: '📚 docs'
- title: '💾 Dependency Updates'
label: 'dependencies'
version-resolver:
major:
labels:
- 'breaking'
minor:
labels:
- '💡 enhancement'
- 'feature'
patch:
labels:
- '🐞 bug'
- '⚙️ maintenance'
- '📚 docs'
- 'dependencies'
exclude-labels:
- 'skip-changelog'
+2 -2
View File
@@ -4,7 +4,7 @@ onlyLabels:
- awaiting user input
staleLabel: given up
markComment: >
This issue has been automatically marked as stale because it has not had
🤖 This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
for your contributions 🙂
closeComment: false
-20
View File
@@ -1,20 +0,0 @@
name: build
on:
push:
branches:
- develop
pull_request:
branches:
- develop
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: xcodebuild
run: |
xcodebuild -project SkeletonView.xcodeproj -target SkeletonView-iOS -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=12'
xcodebuild -project SkeletonView.xcodeproj -target SkeletonView-tvOS -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV,OS=12'
xcodebuild -project SkeletonView.xcodeproj -target SkeletonViewExample -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=12'
-15
View File
@@ -1,15 +0,0 @@
name: CI
on: [pull_request]
jobs:
danger:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Execute danger
uses: danger/swift@3.3.0
with:
args: --failOnErrors --no-publish-check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+19
View File
@@ -0,0 +1,19 @@
name: CI
on:
pull_request:
branches: [main]
jobs:
build:
runs-on: macos-latest
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' }
steps:
- uses: actions/checkout@v2
- name: Build
run: xcodebuild clean -target '${{ matrix.build-config['target'] }}' -sdk '${{ matrix.build-config['sdk'] }}' -destination '${{ matrix.build-config['destination'] }}'
+14
View File
@@ -0,0 +1,14 @@
name: Pod lint
on: [workflow_dispatch]
jobs:
pod_lib_lint:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v2
- env:
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
run: |
set -eo pipefail
pod lib lint --allow-warnings
+38
View File
@@ -0,0 +1,38 @@
name: Release
on: [workflow_dispatch]
jobs:
release_version:
runs-on: macOS-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
+14
View File
@@ -0,0 +1,14 @@
name: Release Notes
on:
push:
branches:
- main
jobs:
update_release_notes:
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-17
View File
@@ -1,17 +0,0 @@
name: SwiftLint
on:
pull_request:
branches: [ develop ]
paths:
- '.github/workflows/swiftlint-macos.yml'
- '.swiftlint.yml'
- '**/*.swift'
jobs:
lint:
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: Run SwiftLint
run: swiftlint lint --reporter github-actions-logging
+34
View File
@@ -0,0 +1,34 @@
name: Validations
on:
pull_request_target:
branches: [main]
types: [opened, reoneped, edited, synchronized]
# workflow_dispatch:
# inputs:
# commit hash:
# description: "Commit hash"
# required: true
# default: ""
jobs:
lint:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Run SwiftLint
run: swiftlint lint --reporter github-actions-logging
danger:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Danger
uses: docker://frmeloni/danger-swift-with-swiftlint:1.3.1
with:
args: --failOnErrors --verbose
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -1 +1 @@
5.0
5.3
+24
View File
@@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file
### Next version
#### 🙌 New
#### 🔬 Improvements
* [**369**](https://github.com/Juanpe/SkeletonView/pull/369): remove useless corner radius constraint - [@Juanpe](https://github.com/Juanpe)
* [**357**](https://github.com/Juanpe/SkeletonView/pull/357): Removed duplicate code in SkeletonCollectionDelegate. - [@keshavamurthy1](https://github.com/keshavamurthy1)
#### 🩹 Bug fixes
* [**359**](https://github.com/Juanpe/SkeletonView/pull/359): SkeletonView respecting Font's height, rather than the `UIView` actual height. - [@keshavamurthy1](https://github.com/keshavamurthy1)
## 📦 [1.11.0](https://github.com/Juanpe/SkeletonView/releases/tag/1.11.0)
#### 🙌 New
* [**339**](https://github.com/Juanpe/SkeletonView/pull/339): Add `hiddenWhenSkeletonIsActive` property - [@mohn93](https://github.com/mohn93)
* [**341**](https://github.com/Juanpe/SkeletonView/pull/341): Support autoreverses in gradient animations - [@Juanpe](https://github.com/Juanpe)
#### 🔬Improvements
* [**344**](https://github.com/Juanpe/SkeletonView/pull/344): Resize labels based on number of lines - [@Juanpe](https://github.com/Juanpe)
#### 🩹 Bug fixes
* [**340**](https://github.com/Juanpe/SkeletonView/pull/340): Fixed incorrect padding, and incorrect multiline layer frame calculation - [@yzhao198](https://github.com/yzhao198)
## 📦 [1.10.0](https://github.com/Juanpe/SkeletonView/releases/tag/1.10.0)
#### 🙌 New
* [**327**](https://github.com/Juanpe/SkeletonView/pull/327): Add SwiftLint - [@Juanpe](https://github.com/Juanpe)
* [**329**](https://github.com/Juanpe/SkeletonView/pull/329): Spanish README 🇪🇸 - [@Juanpe](https://github.com/Juanpe)
+2 -2
View File
@@ -1,7 +1,7 @@
# Contributors Guide
Interested in contributing? Awesome! Before you do though, please read our
[Code of Conduct](https://github.com/Juanpe/SkeletonView/blob/develop/CODE_OF_CONDUCT.md). We take it very seriously, and expect that you will as
[Code of Conduct](https://github.com/Juanpe/SkeletonView/blob/main/CODE_OF_CONDUCT.md). We take it very seriously, and expect that you will as
well.
There are many ways you can contribute! :heart:
@@ -45,7 +45,7 @@ If the contribution doesn't meet the above criteria, you may fail our automated
3. :herb: Create a new branch and check it out.
4. :crystal_ball: Make your changes and commit them locally.
5. :arrow_heading_up: Push your new branch to your fork. (e.g. `git push username fix-issue-300`).
6. :inbox_tray: Open a Pull Request on github.com from your new branch on your fork to `develop` in this
6. :inbox_tray: Open a Pull Request on github.com from your new branch on your fork to `main` in this
repository.
## Developer's Certificate of Origin 1.1
-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>
-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>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
-45
View File
@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.3</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
-10
View File
@@ -3,16 +3,6 @@ import Danger
let danger = Danger()
let github = danger.github
// Changelog entries are required for changes to library files.
let allSourceFiles = danger.git.modifiedFiles + danger.git.createdFiles
let noChangelogEntry = !allSourceFiles.contains("CHANGELOG.md")
let sourceChanges = allSourceFiles.contains { $0.hasPrefix("Sources") }
let isNotTrivial = !danger.github.pullRequest.title.contains("#trivial")
if isNotTrivial && noChangelogEntry && sourceChanges {
fail("Any changes to library code should be reflected in the Changelog.")
}
// Make it more obvious that a PR is a work in progress and shouldn't be merged yet
if danger.github.pullRequest.title.contains("WIP") {
warn("PR is classed as Work in Progress")
-40
View File
@@ -1,40 +0,0 @@
// Copyright © 2018 SkeletonView. All rights reserved.
import UIKit
@UIApplicationMain
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 invalidate graphics rendering callbacks. 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.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
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.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
@@ -1,98 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -1,6 +0,0 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -1,21 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "avatar.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 B

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

Before

Width:  |  Height:  |  Size: 8.0 KiB

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<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="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
@@ -1,55 +0,0 @@
// Copyright © 2018 SkeletonView. All rights reserved.
import UIKit
import SkeletonView
class CollectionViewCell: UICollectionViewCell {
var label: UILabel!
var imageView: UIImageView!
override init(frame: CGRect) {
super.init(frame: frame)
isSkeletonable = true
createLabel()
createImageView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func createImageView() {
imageView = UIImageView(image: UIImage(named: "picture"))
imageView.isSkeletonable = true
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
addSubview(imageView)
NSLayoutConstraint.activate([
imageView.centerXAnchor.constraint(equalTo: centerXAnchor),
imageView.topAnchor.constraint(equalTo: topAnchor),
imageView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.75),
imageView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.75)
])
}
private func createLabel() {
label = UILabel()
label.isSkeletonable = true
label.text = "Lorem ipsum"
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: centerXAnchor),
label.bottomAnchor.constraint(equalTo: bottomAnchor),
label.heightAnchor.constraint(equalToConstant: 40),
label.widthAnchor.constraint(equalToConstant: frame.width)
])
}
}
-212
View File
@@ -1,212 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="irH-dz-xqL">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
<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="qda-qV-vJk">
<objects>
<viewController id="irH-dz-xqL" customClass="ViewController" customModule="SkeletonViewExampleUICollectionView" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Fso-nq-n6t">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eHI-ka-8vS">
<rect key="frame" x="0.0" y="0.0" width="375" height="243"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="obr-b6-dib">
<rect key="frame" x="45" y="142" width="287" height="78"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="78" id="jx6-c1-U0j"/>
</constraints>
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </string>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="lastLineFillPercent">
<integer key="value" value="40"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar" translatesAutoresizingMaskIntoConstraints="NO" id="Ql9-Jy-aWM">
<rect key="frame" x="141" y="20" width="93" height="93"/>
<color key="backgroundColor" red="0.56078431370000004" green="0.59607843140000005" blue="0.7843137255" alpha="0.90709546230000004" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="93" id="jlG-7K-wMd"/>
<constraint firstAttribute="width" constant="93" id="xHX-Y1-dvi"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
</imageView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="243" id="0g6-3g-uII"/>
<constraint firstAttribute="trailing" secondItem="obr-b6-dib" secondAttribute="trailing" constant="43" id="3ms-Wk-qcn"/>
<constraint firstItem="obr-b6-dib" firstAttribute="centerX" secondItem="eHI-ka-8vS" secondAttribute="centerX" constant="1" id="B5s-DM-eR8"/>
<constraint firstAttribute="height" constant="243" id="GX5-3W-tUt"/>
<constraint firstItem="Ql9-Jy-aWM" firstAttribute="centerX" secondItem="eHI-ka-8vS" secondAttribute="centerX" id="HsA-ID-oSK"/>
<constraint firstItem="Ql9-Jy-aWM" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="top" constant="20" id="Hxu-ae-hXQ"/>
<constraint firstItem="obr-b6-dib" firstAttribute="leading" secondItem="eHI-ka-8vS" secondAttribute="leading" constant="45" id="eop-Gq-7mO"/>
<constraint firstItem="obr-b6-dib" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="top" constant="142" id="inJ-75-hGX"/>
</constraints>
<viewLayoutGuide key="safeArea" id="36i-gK-pIa"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
</view>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="HKL-L0-T2w">
<rect key="frame" x="0.0" y="243" width="375" height="264"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="mGU-kn-rfE">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells/>
<connections>
<outlet property="dataSource" destination="irH-dz-xqL" id="wya-hE-ovQ"/>
</connections>
</collectionView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JjA-MK-YzZ">
<rect key="frame" x="0.0" y="507" width="375" height="160"/>
<subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="fMR-vj-7de">
<rect key="frame" x="20" y="21" width="145" height="32"/>
<segments>
<segment title="Solid"/>
<segment title="Gradient"/>
</segments>
<connections>
<action selector="changeSkeletonType:" destination="irH-dz-xqL" eventType="valueChanged" id="lfR-JV-DU4"/>
</connections>
</segmentedControl>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KBe-RM-BG8">
<rect key="frame" x="308" y="21" width="51" height="31"/>
<connections>
<action selector="changeAnimated:" destination="irH-dz-xqL" eventType="valueChanged" id="dlH-KK-iee"/>
</connections>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Animated" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GSj-Ze-UIK">
<rect key="frame" x="229" y="26" width="73" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Color" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4Hm-fj-45V">
<rect key="frame" x="20" y="61" width="41.5" height="52"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HBJ-nh-56V">
<rect key="frame" x="69.5" y="72" width="30" height="30"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="DVW-Tc-XEQ"/>
<constraint firstAttribute="height" constant="30" id="JfP-3b-yqX"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aUR-Qo-gHK">
<rect key="frame" x="20" y="61" width="100" height="52"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="GvX-hq-2Qn"/>
<constraint firstAttribute="height" constant="52" id="UQe-Cf-riE"/>
</constraints>
<connections>
<action selector="btnChangeColorTouchUpInside:" destination="irH-dz-xqL" eventType="touchUpInside" id="Xca-QC-htl"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nPs-17-vfs">
<rect key="frame" x="263" y="72" width="94" height="30"/>
<state key="normal" title="Hide skeleton"/>
<connections>
<action selector="showOrHideSkeleton:" destination="irH-dz-xqL" eventType="touchUpInside" id="lHc-k2-OgV"/>
</connections>
</button>
<stepper opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.25" maximumValue="5" stepValue="0.25" translatesAutoresizingMaskIntoConstraints="NO" id="3mz-9M-e7Q">
<rect key="frame" x="263" y="123" width="94" height="32"/>
<connections>
<action selector="transitionDurationStepperAction:" destination="irH-dz-xqL" eventType="valueChanged" id="Ll0-Pr-d0V"/>
</connections>
</stepper>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Fade Duration: 0.25 sec" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5gN-Jz-44y">
<rect key="frame" x="92.5" y="130" width="162.5" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="3mz-9M-e7Q" firstAttribute="leading" secondItem="5gN-Jz-44y" secondAttribute="trailing" constant="8" id="65e-Nj-bKG"/>
<constraint firstItem="HBJ-nh-56V" firstAttribute="centerY" secondItem="aUR-Qo-gHK" secondAttribute="centerY" id="81M-Wq-Avl"/>
<constraint firstItem="fMR-vj-7de" firstAttribute="leading" secondItem="JjA-MK-YzZ" secondAttribute="leading" constant="20" id="AyG-hI-tte"/>
<constraint firstItem="aUR-Qo-gHK" firstAttribute="leading" secondItem="fMR-vj-7de" secondAttribute="leading" id="C1b-Hl-jEg"/>
<constraint firstItem="3mz-9M-e7Q" firstAttribute="trailing" secondItem="nPs-17-vfs" secondAttribute="trailing" id="KuK-fc-jOQ"/>
<constraint firstItem="nPs-17-vfs" firstAttribute="centerY" secondItem="aUR-Qo-gHK" secondAttribute="centerY" id="MQX-E5-IDE"/>
<constraint firstItem="HBJ-nh-56V" firstAttribute="leading" secondItem="4Hm-fj-45V" secondAttribute="trailing" constant="8" id="MhM-jY-LIA"/>
<constraint firstItem="4Hm-fj-45V" firstAttribute="height" secondItem="aUR-Qo-gHK" secondAttribute="height" id="OSn-RA-wQL"/>
<constraint firstItem="4Hm-fj-45V" firstAttribute="leading" secondItem="aUR-Qo-gHK" secondAttribute="leading" id="PwQ-UR-iMq"/>
<constraint firstAttribute="height" constant="160" id="QDV-wu-e3I"/>
<constraint firstItem="5gN-Jz-44y" firstAttribute="centerY" secondItem="3mz-9M-e7Q" secondAttribute="centerY" id="TGP-Ep-0ob"/>
<constraint firstItem="nPs-17-vfs" firstAttribute="top" secondItem="KBe-RM-BG8" secondAttribute="bottom" constant="20" id="TPg-wY-9bc"/>
<constraint firstItem="4Hm-fj-45V" firstAttribute="centerY" secondItem="aUR-Qo-gHK" secondAttribute="centerY" id="V4i-bF-Jed"/>
<constraint firstItem="KBe-RM-BG8" firstAttribute="leading" secondItem="GSj-Ze-UIK" secondAttribute="trailing" constant="6" id="ehg-tW-7kq"/>
<constraint firstItem="GSj-Ze-UIK" firstAttribute="centerY" secondItem="KBe-RM-BG8" secondAttribute="centerY" id="esk-GV-DBS"/>
<constraint firstAttribute="trailing" secondItem="KBe-RM-BG8" secondAttribute="trailing" constant="18" id="hhE-rV-dV7"/>
<constraint firstItem="KBe-RM-BG8" firstAttribute="top" secondItem="JjA-MK-YzZ" secondAttribute="top" constant="21" id="pBQ-H8-xTK"/>
<constraint firstAttribute="bottom" secondItem="3mz-9M-e7Q" secondAttribute="bottom" constant="5" id="pQ9-a6-hM4"/>
<constraint firstItem="fMR-vj-7de" firstAttribute="centerY" secondItem="GSj-Ze-UIK" secondAttribute="centerY" id="q2v-t1-Zu0"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="160" id="qR5-cz-YAm"/>
<constraint firstItem="nPs-17-vfs" firstAttribute="trailing" secondItem="KBe-RM-BG8" secondAttribute="trailing" id="yls-k6-ZfC"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="eHI-ka-8vS" firstAttribute="trailing" secondItem="2Gq-Y8-1TU" secondAttribute="trailing" id="0dc-Vd-yJY"/>
<constraint firstItem="JjA-MK-YzZ" firstAttribute="leading" secondItem="2Gq-Y8-1TU" secondAttribute="leading" id="57i-UV-Wqd"/>
<constraint firstItem="eHI-ka-8vS" firstAttribute="leading" secondItem="2Gq-Y8-1TU" secondAttribute="leading" id="5tt-Ne-67Y"/>
<constraint firstItem="JjA-MK-YzZ" firstAttribute="bottom" secondItem="2Gq-Y8-1TU" secondAttribute="bottom" id="AAr-ke-R7M"/>
<constraint firstItem="JjA-MK-YzZ" firstAttribute="trailing" secondItem="2Gq-Y8-1TU" secondAttribute="trailing" id="DtS-9c-zBC"/>
<constraint firstItem="HKL-L0-T2w" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="bottom" id="Jgf-jS-PLT"/>
<constraint firstItem="eHI-ka-8vS" firstAttribute="top" secondItem="2Gq-Y8-1TU" secondAttribute="top" id="Ux2-GF-HLK"/>
<constraint firstItem="JjA-MK-YzZ" firstAttribute="top" secondItem="HKL-L0-T2w" secondAttribute="bottom" id="XEd-Gf-KFI"/>
<constraint firstItem="2Gq-Y8-1TU" firstAttribute="trailing" secondItem="HKL-L0-T2w" secondAttribute="trailing" id="bNo-98-pE4"/>
<constraint firstItem="HKL-L0-T2w" firstAttribute="leading" secondItem="2Gq-Y8-1TU" secondAttribute="leading" id="iIq-cx-paX"/>
</constraints>
<viewLayoutGuide key="safeArea" id="2Gq-Y8-1TU"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
</view>
<connections>
<outlet property="avatarImage" destination="Ql9-Jy-aWM" id="VoL-by-ygR"/>
<outlet property="collectionView" destination="HKL-L0-T2w" id="HSe-j0-S5d"/>
<outlet property="colorSelectedView" destination="HBJ-nh-56V" id="Iiq-iY-Glj"/>
<outlet property="showOrHideSkeletonButton" destination="nPs-17-vfs" id="vw4-fW-QoD"/>
<outlet property="skeletonTypeSelector" destination="fMR-vj-7de" id="CgX-3A-weo"/>
<outlet property="switchAnimated" destination="KBe-RM-BG8" id="emU-g9-NHT"/>
<outlet property="transitionDurationLabel" destination="5gN-Jz-44y" id="69y-iR-mbi"/>
<outlet property="transitionDurationStepper" destination="3mz-9M-e7Q" id="tzK-W7-A4D"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="PkM-Y0-M5i" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-972" y="-209.14542728635683"/>
</scene>
</scenes>
<resources>
<image name="avatar" width="215" height="211"/>
</resources>
</document>
-189
View File
@@ -1,189 +0,0 @@
// Copyright © 2018 SkeletonView. All rights reserved.
import UIKit
import SkeletonView
class ViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView! {
didSet {
collectionView.isSkeletonable = true
collectionView.backgroundColor = .clear
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
}
}
@IBOutlet weak var avatarImage: UIImageView! {
didSet {
avatarImage.layer.cornerRadius = avatarImage.frame.width/2
avatarImage.layer.masksToBounds = true
}
}
@IBOutlet weak var colorSelectedView: UIView! {
didSet {
colorSelectedView.layer.cornerRadius = 5
colorSelectedView.layer.masksToBounds = true
colorSelectedView.backgroundColor = SkeletonAppearance.default.tintColor
}
}
@IBOutlet weak var switchAnimated: UISwitch!
@IBOutlet weak var skeletonTypeSelector: UISegmentedControl!
@IBOutlet weak var showOrHideSkeletonButton: UIButton!
@IBOutlet weak var transitionDurationLabel: UILabel!
@IBOutlet weak var transitionDurationStepper: UIStepper!
var type: SkeletonType {
return skeletonTypeSelector.selectedSegmentIndex == 0 ? .solid : .gradient
}
override func viewDidLoad() {
super.viewDidLoad()
transitionDurationStepper.value = 0.25
collectionView.prepareSkeleton(completion: { done in
self.view.showAnimatedSkeleton()
})
}
@IBAction func changeAnimated(_ sender: Any) {
if switchAnimated.isOn {
view.startSkeletonAnimation()
} else {
view.stopSkeletonAnimation()
}
}
@IBAction func changeSkeletonType(_ sender: Any) {
refreshSkeleton()
}
@IBAction func btnChangeColorTouchUpInside(_ sender: Any) {
showAlertPicker()
}
@IBAction func showOrHideSkeleton(_ sender: Any) {
showOrHideSkeletonButton.setTitle((view.isSkeletonActive ? "Show skeleton" : "Hide skeleton"), for: .normal)
view.isSkeletonActive ? hideSkeleton() : showSkeleton()
}
@IBAction func transitionDurationStepperAction(_ sender: Any) {
transitionDurationLabel.text = "transition duration: \(transitionDurationStepper.value) sec"
}
func showSkeleton() {
refreshSkeleton()
}
func hideSkeleton() {
view.hideSkeleton(transition: .crossDissolve(transitionDurationStepper.value))
}
func refreshSkeleton() {
self.view.hideSkeleton()
if type == .gradient { showGradientSkeleton() }
else { showSolidSkeleton() }
}
func showSolidSkeleton() {
if switchAnimated.isOn {
view.showAnimatedSkeleton(usingColor: colorSelectedView.backgroundColor!, transition: .crossDissolve(transitionDurationStepper.value))
} else {
view.showSkeleton(usingColor: colorSelectedView.backgroundColor!, transition: .crossDissolve(transitionDurationStepper.value))
}
}
func showGradientSkeleton() {
let gradient = SkeletonGradient(baseColor: colorSelectedView.backgroundColor!)
if switchAnimated.isOn {
view.showAnimatedGradientSkeleton(usingGradient: gradient, transition: .crossDissolve(transitionDurationStepper.value))
} else {
view.showGradientSkeleton(usingGradient: gradient, transition: .crossDissolve(transitionDurationStepper.value))
}
}
func showAlertPicker() {
let alertView = UIAlertController(title: "Select color", message: "\n\n\n\n\n\n", preferredStyle: .alert)
let pickerView = UIPickerView(frame: CGRect(x: 0, y: 50, width: 260, height: 115))
pickerView.dataSource = self
pickerView.delegate = self
alertView.view.addSubview(pickerView)
let action = UIAlertAction(title: "OK", style: .default) { [unowned pickerView, unowned self] _ in
let row = pickerView.selectedRow(inComponent: 0)
self.colorSelectedView.backgroundColor = colors[row].0
self.refreshSkeleton()
}
alertView.addAction(action)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertView.addAction(cancelAction)
present(alertView, animated: false, completion: {
pickerView.frame.size.width = alertView.view.frame.size.width
})
}
}
// MARK: - UIPickerViewDelegate, UIPickerViewDataSource
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return colors.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return colors[row].1
}
}
// MARK: - UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width/3 - 10, height: view.frame.width/3 - 10)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
}
// MARK: - SkeletonCollectionViewDataSource
extension ViewController: SkeletonCollectionViewDataSource {
func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier {
return "CollectionViewCell"
}
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
// MARK: - UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
return cell
}
}
-46
View File
@@ -1,46 +0,0 @@
//
// AppDelegate.swift
// SkeletonViewExample
//
// Created by Juanpe Catalán on 02/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
@UIApplicationMain
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 invalidate graphics rendering callbacks. 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.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
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.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
@@ -1,98 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -1,6 +0,0 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -1,21 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "avatar.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 B

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<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="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
@@ -1,320 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" 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="16087"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Item-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="SkeletonViewExample" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="F9K-jU-100" userLabel="ContainerView">
<rect key="frame" x="0.0" y="44" width="375" height="243"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="e9V-mk-xH0">
<rect key="frame" x="45" y="142" width="287" height="78"/>
<constraints>
<constraint firstAttribute="height" constant="78" id="gF5-G1-lKI"/>
</constraints>
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </string>
<color key="textColor" systemColor="labelColor" cocoaTouchSystemColor="darkTextColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="lastLineFillPercent">
<integer key="value" value="40"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="linesCornerRadius">
<integer key="value" value="6"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar" translatesAutoresizingMaskIntoConstraints="NO" id="nMj-pU-5wJ">
<rect key="frame" x="45" y="20" width="93" height="93"/>
<color key="backgroundColor" red="0.56078431370000004" green="0.59607843140000005" blue="0.7843137255" alpha="0.90709546230000004" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="93" id="gw9-nu-cKo"/>
<constraint firstAttribute="width" constant="93" id="zB6-Lp-IUt"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ifX-3x-oCb">
<rect key="frame" x="165" y="44.666666666666671" width="125" height="44"/>
<constraints>
<constraint firstAttribute="width" constant="125" id="MuV-52-GiO"/>
<constraint firstAttribute="height" constant="44" id="vIU-os-12z"/>
</constraints>
<state key="normal" title="Button">
<color key="titleColor" systemColor="systemBlueColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="ifX-3x-oCb" firstAttribute="centerY" secondItem="nMj-pU-5wJ" secondAttribute="centerY" id="8sl-4R-4in"/>
<constraint firstItem="e9V-mk-xH0" firstAttribute="leading" secondItem="F9K-jU-100" secondAttribute="leading" constant="45" id="HvQ-HY-zYU"/>
<constraint firstItem="e9V-mk-xH0" firstAttribute="centerX" secondItem="F9K-jU-100" secondAttribute="centerX" constant="1" id="KcB-tG-NXa"/>
<constraint firstItem="ifX-3x-oCb" firstAttribute="leading" secondItem="nMj-pU-5wJ" secondAttribute="trailing" constant="27" id="LQC-s6-w43"/>
<constraint firstAttribute="height" constant="243" id="MIj-xq-gr1"/>
<constraint firstItem="nMj-pU-5wJ" firstAttribute="leading" secondItem="F9K-jU-100" secondAttribute="leading" constant="45" id="TK6-Ws-2xY"/>
<constraint firstItem="e9V-mk-xH0" firstAttribute="top" secondItem="F9K-jU-100" secondAttribute="top" constant="142" id="Wcx-nZ-1lR"/>
<constraint firstAttribute="trailing" secondItem="e9V-mk-xH0" secondAttribute="trailing" constant="43" id="XbU-Og-rht"/>
<constraint firstItem="nMj-pU-5wJ" firstAttribute="top" secondItem="F9K-jU-100" secondAttribute="top" constant="20" id="hQL-cr-MaN"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
</view>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="UCB-SP-lQk">
<rect key="frame" x="0.0" y="287" width="375" height="282"/>
<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"/>
<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"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar" translatesAutoresizingMaskIntoConstraints="NO" id="oiE-tt-nc2">
<rect key="frame" x="15" y="18" width="82" height="82"/>
<color key="backgroundColor" red="0.56078431370000004" green="0.59607843140000005" blue="0.7843137255" alpha="0.90709546230000004" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="82" id="4j0-PU-CmN"/>
<constraint firstAttribute="height" constant="82" id="iqE-Lc-FOj"/>
</constraints>
<userDefinedRuntimeAttributes>
<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="VhU-1t-AaI" userLabel="Label">
<rect key="frame" x="118" y="29" width="237" height="18"/>
<constraints>
<constraint firstAttribute="height" relation="lessThanOrEqual" constant="71" id="HRL-cI-ieC"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="linesCornerRadius">
<integer key="value" value="5"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="lastLineFillPercent">
<integer key="value" value="20"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
</subviews>
<constraints>
<constraint firstItem="oiE-tt-nc2" firstAttribute="leading" secondItem="7IN-F3-Mr6" secondAttribute="leadingMargin" id="1be-ak-AH1"/>
<constraint firstAttribute="bottom" secondItem="oiE-tt-nc2" secondAttribute="bottom" constant="20" id="CKt-oA-eBI"/>
<constraint firstItem="oiE-tt-nc2" firstAttribute="top" secondItem="7IN-F3-Mr6" secondAttribute="topMargin" constant="7" id="EKn-ST-LDX"/>
<constraint firstAttribute="trailingMargin" secondItem="VhU-1t-AaI" secondAttribute="trailing" constant="5" id="I7C-Bq-mfK"/>
<constraint firstItem="VhU-1t-AaI" firstAttribute="leading" secondItem="oiE-tt-nc2" secondAttribute="trailing" constant="21" id="Ojr-Kz-1k6"/>
<constraint firstItem="VhU-1t-AaI" firstAttribute="top" secondItem="7IN-F3-Mr6" secondAttribute="topMargin" constant="18" id="ZW6-JY-S4c"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
</tableViewCellContentView>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="avatar" destination="oiE-tt-nc2" id="Dkh-R5-Qhu"/>
<outlet property="label1" destination="VhU-1t-AaI" id="kUW-HV-KrD"/>
</connections>
</tableViewCell>
</prototypes>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="NO"/>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="dataSource" destination="BYZ-38-t0r" id="Hxi-nC-gbY"/>
<outlet property="delegate" destination="BYZ-38-t0r" id="Z10-Nx-iGb"/>
</connections>
</tableView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XgY-1a-UGc">
<rect key="frame" x="0.0" y="569" width="375" height="160"/>
<subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="xOL-Sq-r4i">
<rect key="frame" x="20" y="23" width="145" height="32"/>
<segments>
<segment title="Solid"/>
<segment title="Gradient"/>
</segments>
<connections>
<action selector="changeSkeletonType:" destination="BYZ-38-t0r" eventType="valueChanged" id="iAS-ab-0jP"/>
</connections>
</segmentedControl>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vz0-qg-GcZ">
<rect key="frame" x="308" y="21" width="51" height="31"/>
<connections>
<action selector="changeAnimated:" destination="BYZ-38-t0r" eventType="valueChanged" id="w1G-gZ-RE0"/>
</connections>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Animated" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WHN-wR-TKt">
<rect key="frame" x="229" y="26" width="73" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Color" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7CF-rV-pK2">
<rect key="frame" x="20" y="73.666666666666629" width="90" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iGp-rp-t1d">
<rect key="frame" x="130" y="69" width="30" height="30"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="Q3k-B1-E88"/>
<constraint firstAttribute="height" constant="30" id="xOD-RY-U4u"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Mde-Cm-CoS">
<rect key="frame" x="20" y="58" width="140" height="52"/>
<constraints>
<constraint firstAttribute="height" constant="52" id="3GX-2y-eQj"/>
<constraint firstAttribute="width" constant="140" id="6cC-Y1-RKs"/>
</constraints>
<connections>
<action selector="btnChangeColorTouchUpInside:" destination="BYZ-38-t0r" eventType="touchUpInside" id="cB8-Ik-LIJ"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Tdu-YQ-saq">
<rect key="frame" x="263" y="69" width="94" height="30"/>
<state key="normal" title="Hide skeleton"/>
<connections>
<action selector="showOrHideSkeleton:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Ma1-WX-Dzy"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Fade Duration: 0.25 sec" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mrw-PM-jJJ">
<rect key="frame" x="92.333333333333329" y="130" width="162.66666666666669" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stepper opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.25" maximumValue="5" stepValue="0.25" translatesAutoresizingMaskIntoConstraints="NO" id="l4N-LL-ZrJ">
<rect key="frame" x="263" y="123" width="94" height="32"/>
<connections>
<action selector="transitionDurationStepperAction:" destination="BYZ-38-t0r" eventType="valueChanged" id="jPN-df-fNs"/>
</connections>
</stepper>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="l4N-LL-ZrJ" firstAttribute="leading" secondItem="mrw-PM-jJJ" secondAttribute="trailing" constant="8" id="5iU-dO-qVc"/>
<constraint firstItem="mrw-PM-jJJ" firstAttribute="centerY" secondItem="l4N-LL-ZrJ" secondAttribute="centerY" id="9OM-mx-4Jo"/>
<constraint firstAttribute="trailing" secondItem="Tdu-YQ-saq" secondAttribute="trailing" constant="18" id="BQ0-S0-YMp"/>
<constraint firstItem="iGp-rp-t1d" firstAttribute="trailing" secondItem="Mde-Cm-CoS" secondAttribute="trailing" id="IJ3-CC-5M7"/>
<constraint firstAttribute="height" constant="160" id="OH5-ja-ZlB"/>
<constraint firstItem="Mde-Cm-CoS" firstAttribute="leading" secondItem="XgY-1a-UGc" secondAttribute="leading" constant="20" id="Rek-hz-pDw"/>
<constraint firstItem="xOL-Sq-r4i" firstAttribute="top" secondItem="XgY-1a-UGc" secondAttribute="top" constant="23" id="Udf-0g-bZm"/>
<constraint firstItem="Tdu-YQ-saq" firstAttribute="top" secondItem="vz0-qg-GcZ" secondAttribute="bottom" constant="17" id="WiR-yP-dyv"/>
<constraint firstItem="Mde-Cm-CoS" firstAttribute="centerY" secondItem="7CF-rV-pK2" secondAttribute="centerY" id="eaN-FA-4mF"/>
<constraint firstItem="iGp-rp-t1d" firstAttribute="centerY" secondItem="7CF-rV-pK2" secondAttribute="centerY" id="hBb-mp-AjF"/>
<constraint firstItem="l4N-LL-ZrJ" firstAttribute="top" secondItem="Tdu-YQ-saq" secondAttribute="bottom" constant="24" id="iA5-RB-pW2"/>
<constraint firstItem="vz0-qg-GcZ" firstAttribute="top" secondItem="XgY-1a-UGc" secondAttribute="top" constant="21" id="iad-6N-wNf"/>
<constraint firstItem="vz0-qg-GcZ" firstAttribute="leading" secondItem="WHN-wR-TKt" secondAttribute="trailing" constant="6" id="jgu-tV-gqO"/>
<constraint firstItem="WHN-wR-TKt" firstAttribute="centerY" secondItem="vz0-qg-GcZ" secondAttribute="centerY" id="kTu-fb-Bc8"/>
<constraint firstAttribute="trailing" secondItem="vz0-qg-GcZ" secondAttribute="trailing" constant="18" id="ktq-JT-uoR"/>
<constraint firstItem="xOL-Sq-r4i" firstAttribute="leading" secondItem="XgY-1a-UGc" secondAttribute="leading" constant="20" id="pY0-qd-xmK"/>
<constraint firstItem="l4N-LL-ZrJ" firstAttribute="trailing" secondItem="Tdu-YQ-saq" secondAttribute="trailing" id="ql2-Z9-dnv"/>
<constraint firstItem="iGp-rp-t1d" firstAttribute="leading" secondItem="7CF-rV-pK2" secondAttribute="trailing" constant="20" id="vWD-0m-dMp"/>
<constraint firstItem="7CF-rV-pK2" firstAttribute="centerY" secondItem="Tdu-YQ-saq" secondAttribute="centerY" id="x0d-LB-A4q"/>
<constraint firstItem="7CF-rV-pK2" firstAttribute="leading" secondItem="xOL-Sq-r4i" secondAttribute="leading" id="yEL-Nv-z76"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="F9K-jU-100" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="1es-nY-bd3"/>
<constraint firstItem="F9K-jU-100" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="A3E-iv-1qp"/>
<constraint firstItem="XgY-1a-UGc" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="Luk-cg-4Ez"/>
<constraint firstItem="UCB-SP-lQk" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="Qbw-Rq-Rhw"/>
<constraint firstItem="F9K-jU-100" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="VLb-cX-ZHC"/>
<constraint firstItem="XgY-1a-UGc" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="Y8A-sq-fmq"/>
<constraint firstItem="XgY-1a-UGc" firstAttribute="top" secondItem="UCB-SP-lQk" secondAttribute="bottom" id="eof-MM-DrW"/>
<constraint firstItem="UCB-SP-lQk" firstAttribute="top" secondItem="F9K-jU-100" secondAttribute="bottom" id="hwL-ec-fKo"/>
<constraint firstItem="UCB-SP-lQk" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="o6z-Dj-ppC"/>
<constraint firstItem="XgY-1a-UGc" firstAttribute="bottom" secondItem="6Tk-OE-BBY" secondAttribute="bottom" id="vnZ-9k-MfI"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
</view>
<tabBarItem key="tabBarItem" title="Item" id="wQY-ap-3n3"/>
<navigationItem key="navigationItem" id="BEI-dU-kr2"/>
<connections>
<outlet property="avatarImage" destination="nMj-pU-5wJ" id="9fa-Z7-vYi"/>
<outlet property="colorSelectedView" destination="iGp-rp-t1d" id="0Zm-9d-jRU"/>
<outlet property="showOrHideSkeletonButton" destination="Tdu-YQ-saq" id="gkm-mB-zYD"/>
<outlet property="skeletonTypeSelector" destination="xOL-Sq-r4i" id="yTr-8L-I4Y"/>
<outlet property="switchAnimated" destination="vz0-qg-GcZ" id="d2R-8x-lRb"/>
<outlet property="tableview" destination="UCB-SP-lQk" id="XV0-KX-lAN"/>
<outlet property="transitionDurationLabel" destination="mrw-PM-jJJ" id="BVK-Kl-5Q3"/>
<outlet property="transitionDurationStepper" destination="l4N-LL-ZrJ" id="OJr-Ul-7XR"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-2682.4000000000001" y="339.90147783251234"/>
</scene>
<!--Item-->
<scene sceneID="Cfc-AT-AS1">
<objects>
<viewController id="dv8-ph-Ehg" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Jwx-gI-Qod">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="Ao1-hk-zrH"/>
</view>
<tabBarItem key="tabBarItem" title="Item" id="iKp-9S-aib"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="M03-a6-GOC" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1644" y="340"/>
</scene>
<!--Tab Bar Controller-->
<scene sceneID="U6k-MC-AHH">
<objects>
<tabBarController automaticallyAdjustsScrollViewInsets="NO" id="Va7-1y-Tel" sceneMemberID="viewController">
<toolbarItems/>
<tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="HSI-2O-RyO">
<rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
<autoresizingMask key="autoresizingMask"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tabBar>
<connections>
<segue destination="BYZ-38-t0r" kind="relationship" relationship="viewControllers" id="dL3-9L-KNU"/>
<segue destination="dv8-ph-Ehg" kind="relationship" relationship="viewControllers" id="8QB-uV-gaF"/>
</connections>
</tabBarController>
<placeholder placeholderIdentifier="IBFirstResponder" id="huq-Fh-0sW" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-2172" y="-555"/>
</scene>
</scenes>
<resources>
<image name="avatar" width="215" height="211"/>
</resources>
</document>
-19
View File
@@ -1,19 +0,0 @@
//
// Cell.swift
// SkeletonViewExample
//
// Created by Juanpe Catalán on 03/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
class Cell: UITableViewCell {
@IBOutlet weak var avatar: UIImageView!
@IBOutlet weak var label1: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
}
-5
View File
@@ -1,5 +0,0 @@
// Copyright © 2018 SkeletonView. All rights reserved.
import UIKit
let colors = [(UIColor.skeletonDefault,"skeletonDefault"),(UIColor.turquoise,"turquoise"), (UIColor.emerald,"emerald"), (UIColor.peterRiver,"peterRiver"), (UIColor.amethyst,"amethyst"),(UIColor.wetAsphalt,"wetAsphalt"), (UIColor.nephritis,"nephritis"), (UIColor.belizeHole,"belizeHole"), (UIColor.wisteria,"wisteria"), (UIColor.midnightBlue,"midnightBlue"), (UIColor.sunFlower,"sunFlower"), (UIColor.carrot,"carrot"), (UIColor.alizarin,"alizarin"),(UIColor.clouds,"clouds"), (UIColor.concrete,"concrete"), (UIColor.flatOrange,"flatOrange"), (UIColor.pumpkin,"pumpkin"), (UIColor.pomegranate,"pomegranate"), (UIColor.silver,"silver"), (UIColor.asbestos,"asbestos")]
@@ -1,44 +0,0 @@
// Copyright © 2020 SkeletonView. All rights reserved.
import UIKit
class HeaderFooterSection: UITableViewHeaderFooterView {
lazy var titleLabel: UILabel = {
let label = UILabel()
label.text = " "
label.isSkeletonable = true
label.linesCornerRadius = 5
return label
}()
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
isSkeletonable = true
contentView.addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10)
])
backgroundView = UIView()
if #available(iOS 13.0, *) {
backgroundView?.backgroundColor = .systemBackground
} else {
backgroundView?.backgroundColor = .white
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
-210
View File
@@ -1,210 +0,0 @@
//
// ViewController.swift
// SkeletonViewExample
//
// Created by Juanpe Catalán on 02/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
import SkeletonView
class ViewController: UIViewController {
@IBOutlet weak var tableview: UITableView! {
didSet {
tableview.rowHeight = UITableView.automaticDimension
tableview.sectionHeaderHeight = UITableView.automaticDimension
tableview.sectionFooterHeight = UITableView.automaticDimension
tableview.estimatedRowHeight = 120.0
tableview.estimatedSectionFooterHeight = 20.0
tableview.estimatedSectionHeaderHeight = 20.0
tableview.register(HeaderFooterSection.self, forHeaderFooterViewReuseIdentifier: "HeaderIdentifier")
tableview.register(HeaderFooterSection.self, forHeaderFooterViewReuseIdentifier: "FooterIdentifier")
}
}
@IBOutlet weak var avatarImage: UIImageView! {
didSet {
avatarImage.layer.cornerRadius = avatarImage.frame.width/2
avatarImage.layer.masksToBounds = true
}
}
@IBOutlet weak var colorSelectedView: UIView! {
didSet {
colorSelectedView.layer.cornerRadius = 5
colorSelectedView.layer.masksToBounds = true
colorSelectedView.backgroundColor = SkeletonAppearance.default.tintColor
}
}
@IBOutlet weak var switchAnimated: UISwitch!
@IBOutlet weak var skeletonTypeSelector: UISegmentedControl!
@IBOutlet weak var showOrHideSkeletonButton: UIButton!
@IBOutlet weak var transitionDurationLabel: UILabel!
@IBOutlet weak var transitionDurationStepper: UIStepper!
var type: SkeletonType {
return skeletonTypeSelector.selectedSegmentIndex == 0 ? .solid : .gradient
}
override func viewDidLoad() {
super.viewDidLoad()
tableview.isSkeletonable = true
transitionDurationStepper.value = 0.25
view.showAnimatedSkeleton()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
@IBAction func changeAnimated(_ sender: Any) {
if switchAnimated.isOn {
view.startSkeletonAnimation()
} else {
view.stopSkeletonAnimation()
}
}
@IBAction func changeSkeletonType(_ sender: Any) {
refreshSkeleton()
}
@IBAction func btnChangeColorTouchUpInside(_ sender: Any) {
showAlertPicker()
}
@IBAction func showOrHideSkeleton(_ sender: Any) {
showOrHideSkeletonButton.setTitle((view.isSkeletonActive ? "Show skeleton" : "Hide skeleton"), for: .normal)
view.isSkeletonActive ? hideSkeleton() : showSkeleton()
}
@IBAction func transitionDurationStepperAction(_ sender: Any) {
transitionDurationLabel.text = "Transition duration: \(transitionDurationStepper.value) sec"
}
func showSkeleton() {
if type == .gradient {
let gradient = SkeletonGradient(baseColor: colorSelectedView.backgroundColor!)
if switchAnimated.isOn {
view.showAnimatedGradientSkeleton(usingGradient: gradient, transition: .crossDissolve(transitionDurationStepper.value))
}
else {
view.showGradientSkeleton(usingGradient: gradient, transition: .crossDissolve(transitionDurationStepper.value))
}
}
else {
if switchAnimated.isOn {
view.showAnimatedSkeleton(transition: .crossDissolve(transitionDurationStepper.value))
}
else {
view.showSkeleton(transition: .crossDissolve(transitionDurationStepper.value))
}
}
}
func hideSkeleton() {
view.hideSkeleton(transition: .crossDissolve(transitionDurationStepper.value))
}
func refreshSkeleton() {
if type == .gradient { showOrUpdateGradientSkeleton() }
else { showOrUpdatepdateSolidSkeleton() }
}
func showOrUpdatepdateSolidSkeleton() {
if switchAnimated.isOn {
view.updateAnimatedSkeleton(usingColor: colorSelectedView.backgroundColor!)
} else {
view.updateSkeleton(usingColor: colorSelectedView.backgroundColor!)
}
}
func showOrUpdateGradientSkeleton() {
let gradient = SkeletonGradient(baseColor: colorSelectedView.backgroundColor!)
if switchAnimated.isOn {
view.updateAnimatedGradientSkeleton(usingGradient: gradient)
} else {
view.updateGradientSkeleton(usingGradient: gradient)
}
}
func showAlertPicker() {
let alertView = UIAlertController(title: "Select color", message: "\n\n\n\n\n\n", preferredStyle: .alert)
let pickerView = UIPickerView(frame: CGRect(x: 0, y: 50, width: 260, height: 115))
pickerView.dataSource = self
pickerView.delegate = self
alertView.view.addSubview(pickerView)
let action = UIAlertAction(title: "OK", style: .default) { [unowned pickerView, unowned self] _ in
let row = pickerView.selectedRow(inComponent: 0)
self.colorSelectedView.backgroundColor = colors[row].0
self.refreshSkeleton()
}
alertView.addAction(action)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertView.addAction(cancelAction)
present(alertView, animated: false, completion: {
pickerView.frame.size.width = alertView.view.frame.size.width
})
}
}
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return colors.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return colors[row].1
}
}
extension ViewController: SkeletonTableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier {
return "CellIdentifier"
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier", for: indexPath) as! Cell
cell.label1.text = "cell => \(indexPath.row)"
return cell
}
}
extension ViewController: SkeletonTableViewDelegate {
func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -> ReusableHeaderFooterIdentifier? {
return "HeaderIdentifier"
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView
.dequeueReusableHeaderFooterView(withIdentifier: "HeaderIdentifier") as! HeaderFooterSection
header.titleLabel.text = "header => \(section)"
return header
}
func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -> ReusableHeaderFooterIdentifier? {
return "FooterIdentifier"
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footer = tableView
.dequeueReusableHeaderFooterView(withIdentifier: "FooterIdentifier") as! HeaderFooterSection
footer.titleLabel.text = "footer => \(section)"
return footer
}
}
+16
View File
@@ -0,0 +1,16 @@
{
"object": {
"pins": [
{
"package": "SnapshotTesting",
"repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing.git",
"state": {
"branch": null,
"revision": "c466812aa2e22898f27557e2e780d3aad7a27203",
"version": "1.8.2"
}
}
]
},
"version": 1
}
+31 -14
View File
@@ -1,23 +1,40 @@
// swift-tools-version:5.0
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "SkeletonView",
platforms: [
.iOS(.v9),
.tvOS(.v9)
],
platforms: [
.iOS(.v11),
.tvOS(.v11)
],
products: [
.library(
name: "SkeletonView",
targets: ["SkeletonView"])
],
targets: [
.target(
name: "SkeletonView",
dependencies: [],
path: "Sources")
],
swiftLanguageVersions: [.v5]
targets: ["SkeletonView"]
)
],
dependencies: [
.package(name: "SnapshotTesting", url: "https://github.com/pointfreeco/swift-snapshot-testing.git", .exact("1.8.2"))
],
targets: [
.target(
name: "SkeletonView",
path: "Sources",
exclude: [
"*.md"
]
),
.testTarget(
name: "SkeletonViewTests",
dependencies: [
"SkeletonView",
"SnapshotTesting"
],
path: "Tests/SkeletonViewTests",
exclude: [
"UI/__Snapshots__"
]
)
]
)
+19 -8
View File
@@ -1,13 +1,13 @@
![](Assets/header2.jpg)
<p align="center">
<a href="https://github.com/Juanpe/SkeletonView/workflows/build">
<img src="https://github.com/Juanpe/SkeletonView/workflows/build/badge.svg">
<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>
<a href="https://codebeat.co/projects/github-com-juanpe-skeletonview-main"><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://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/main/badges/nef-playgrounds-badge.svg" alt="SkeletonView Playground" style="height:20px"></a>
</p>
<p align="center">
@@ -19,7 +19,7 @@
• <a href="#-contributing">Contributing</a>
</p>
**🌎 README is available in other languages: [🇪🇸](https://github.com/Juanpe/SkeletonView/blob/develop/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: [🇪🇸](https://github.com/Juanpe/SkeletonView/blob/main/README_es.md) . [🇨🇳](https://github.com/Juanpe/SkeletonView/blob/main/README_zh.md) . [🇧🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_pt-br.md) . [🇰🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_ko.md) . [🇫🇷](https://github.com/Juanpe/SkeletonView/blob/main/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.
@@ -28,7 +28,7 @@ Today almost all apps have async processes, such as API requests, long running p
Enjoy it! 🙂
##
##
- [🌟 Features](#-features)
- [🎬 Guides](#-guides)
- [📲 Installation](#-installation)
@@ -37,10 +37,14 @@ Enjoy it! 🙂
- [🔠 Texts](#-texts)
- [🦋 Appearance](#-appearance)
- [🎨 Custom colors](#-custom-colors)
- [ 🏃‍♀️ Animations](#%EF%B8%8F-animations)
- [Image captured from website https://flatuicolors.com](#image-captured-from-website-httpsflatuicolorscom)
- [🏃‍♀️ Animations](#-animations)
- [🏄 Transitions](#-transitions)
- [✨ Miscellaneous](#-miscellaneous)
- [❤️ Contributing](#-contributing)
- [📢 Mentions](#-mentions)
- [👨🏻‍💻 Author](#-author)
- [👮🏻 License](#-license)
@@ -479,6 +483,13 @@ You can change the skeleton configuration at any time like its colour, animation
(4) view.updateAnimatedGradientSkeleton() // Gradient animated
```
**Hiding views when the animation starts**
Sometimes you wanna hide some view when the animation starts, so there is a quick property that you can use to make this happen:
```swift
view.isHiddenWhenSkeletonIsActive = true // This works only when isSkeletonable = true
```
**Debug**
@@ -520,7 +531,7 @@ This is an open source project, so feel free to contribute. How?
See [all contributors](https://github.com/Juanpe/SkeletonView/graphs/contributors)
For more information, please read the [contributing guidelines](https://github.com/Juanpe/SkeletonView/blob/develop/CONTRIBUTING.md).
For more information, please read the [contributing guidelines](https://github.com/Juanpe/SkeletonView/blob/main/CONTRIBUTING.md).
## 📢 Mentions
+2 -2
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SkeletonView"
s.version = "1.10.0"
s.version = "1.13.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.
@@ -12,7 +12,7 @@ Pod::Spec.new do |s|
s.social_media_url = "https://twitter.com/JuanpeCatalan"
s.ios.deployment_target = "9.0"
s.tvos.deployment_target = "9.0"
s.swift_version = "5.0"
s.swift_version = "5.3"
s.source = { :git => "https://github.com/Juanpe/SkeletonView.git", :tag => s.version.to_s }
s.source_files = "Sources/**/*"
end
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
File diff suppressed because it is too large Load Diff
@@ -4,4 +4,4 @@
<FileRef
location = "self:">
</FileRef>
</Workspace>
</Workspace>
@@ -2,7 +2,7 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FILEHEADER</key>
<string> ___COPYRIGHT___</string>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
</plist>
</plist>
@@ -1,89 +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 = "52D6D97B1BEFF229002C0205"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-iOS"
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 = "52D6D97B1BEFF229002C0205"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-iOS"
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">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "52D6D97B1BEFF229002C0205"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-iOS"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "52D6D97B1BEFF229002C0205"
BuildableName = "SkeletonView.framework"
BlueprintName = "SkeletonView-iOS"
ReferencedContainer = "container:SkeletonView.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "9999"
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"
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 = "SkeletonViewTests"
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,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>
@@ -29,6 +29,14 @@ extension CollectionSkeleton where Self: UIScrollView {
var estimatedNumberOfRows: Int { return 0 }
func addDummyDataSource() {}
func removeDummyDataSource(reloadAfter: Bool) {}
func disableUserInteraction() { isUserInteractionEnabled = false; isScrollEnabled = false }
func enableUserInteraction() { isUserInteractionEnabled = true; isScrollEnabled = true }
func disableUserInteraction() {
isUserInteractionEnabled = false
isScrollEnabled = false
}
func enableUserInteraction() {
isUserInteractionEnabled = true
isScrollEnabled = true
}
}
@@ -28,11 +28,11 @@ class SkeletonCollectionDataSource: NSObject {
// MARK: - UITableViewDataSource
extension SkeletonCollectionDataSource: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return originalTableViewDataSource?.numSections(in: tableView) ?? 0
originalTableViewDataSource?.numSections(in: tableView) ?? 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return originalTableViewDataSource?.collectionSkeletonView(tableView, numberOfRowsInSection: section) ?? 0
originalTableViewDataSource?.collectionSkeletonView(tableView, numberOfRowsInSection: section) ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
@@ -46,11 +46,11 @@ extension SkeletonCollectionDataSource: UITableViewDataSource {
// MARK: - UICollectionViewDataSource
extension SkeletonCollectionDataSource: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return originalCollectionViewDataSource?.numSections(in: collectionView) ?? 0
originalCollectionViewDataSource?.numSections(in: collectionView) ?? 0
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return originalCollectionViewDataSource?.collectionSkeletonView(collectionView, numberOfItemsInSection: section) ?? 0
originalCollectionViewDataSource?.collectionSkeletonView(collectionView, numberOfItemsInSection: section) ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
@@ -21,23 +21,11 @@ class SkeletonCollectionDelegate: NSObject {
// MARK: - UITableViewDelegate
extension SkeletonCollectionDelegate: UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if let viewIdentifier = originalTableViewDelegate?.collectionSkeletonView(tableView, identifierForHeaderInSection: section),
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: viewIdentifier) {
skeletonViewIfContainerSkeletonIsActive(container: tableView, view: header)
return header
}
return nil
headerOrFooterView(tableView, for: originalTableViewDelegate?.collectionSkeletonView(tableView, identifierForHeaderInSection: section))
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
if let viewIdentifier = originalTableViewDelegate?.collectionSkeletonView(tableView, identifierForFooterInSection: section),
let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: viewIdentifier) {
skeletonViewIfContainerSkeletonIsActive(container: tableView, view: footer)
return footer
}
return nil
headerOrFooterView(tableView, for: originalTableViewDelegate?.collectionSkeletonView(tableView, identifierForHeaderInSection: section))
}
func tableView(_ tableView: UITableView, didEndDisplayingHeaderView view: UIView, forSection section: Int) {
@@ -54,6 +42,12 @@ extension SkeletonCollectionDelegate: UITableViewDelegate {
cell.hideSkeleton()
originalTableViewDelegate?.tableView?(tableView, didEndDisplaying: cell, forRowAt: indexPath)
}
private func headerOrFooterView(_ tableView: UITableView, for viewIdentifier: String? ) -> UIView? {
guard let viewIdentifier = viewIdentifier, let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: viewIdentifier) else { return nil }
skeletonViewIfContainerSkeletonIsActive(container: tableView, view: header)
return header
}
}
// MARK: - UICollectionViewDelegate
+25 -34
View File
@@ -30,7 +30,7 @@ extension CAGradientLayer {
struct SkeletonMultilinesLayerConfig {
var lines: Int
var lineHeight: CGFloat?
var lineHeight: CGFloat
var type: SkeletonType
var lastLineFillPercent: Int
var multilineCornerRadius: Int
@@ -41,9 +41,9 @@ struct SkeletonMultilinesLayerConfig {
/// Returns padding insets taking into account if the RTL is activated
var calculatedPaddingInsets: UIEdgeInsets {
UIEdgeInsets(top: paddingInsets.top,
left: paddingInsets.right,
left: isRTL ? paddingInsets.right : paddingInsets.left,
bottom: paddingInsets.bottom,
right: paddingInsets.left)
right: isRTL ? paddingInsets.left : paddingInsets.right)
}
}
@@ -56,8 +56,8 @@ extension CALayer {
}
func addMultilinesLayers(for config: SkeletonMultilinesLayerConfig) {
let numberOfSublayers = config.lines == 1 ? 1 : calculateNumLines(for: config)
var height = config.lineHeight ?? SkeletonAppearance.default.multilineHeight
let numberOfSublayers = config.lines > 0 ? config.lines : calculateNumLines(for: config)
var height = config.lineHeight
if numberOfSublayers == 1 && SkeletonAppearance.default.renderSingleLineAsView {
height = bounds.height
@@ -88,7 +88,7 @@ extension CALayer {
let lastLineFillPercent = config.lastLineFillPercent
let paddingInsets = config.calculatedPaddingInsets
let multilineSpacing = config.multilineSpacing
var height = config.lineHeight ?? SkeletonAppearance.default.multilineHeight
var height = config.lineHeight
if numberOfSublayers == 1 && SkeletonAppearance.default.renderSingleLineAsView {
height = bounds.height
@@ -113,20 +113,29 @@ extension CALayer {
}
func updateLayerFrame(for index: Int, size: CGSize, multilineSpacing: CGFloat, paddingInsets: UIEdgeInsets, isRTL: Bool) {
let spaceRequiredForEachLine = SkeletonAppearance.default.multilineHeight + multilineSpacing
let spaceRequiredForEachLine = size.height + multilineSpacing
let newFrame = CGRect(x: paddingInsets.left,
y: CGFloat(index) * spaceRequiredForEachLine + paddingInsets.top,
width: size.width,
height: size.height - paddingInsets.bottom - paddingInsets.top)
height: size.height)
frame = flipRectForRTLIfNeeded(newFrame, isRTL: isRTL)
}
private func calculateNumLines(for config: SkeletonMultilinesLayerConfig) -> Int {
let requiredSpaceForEachLine = (config.lineHeight ?? SkeletonAppearance.default.multilineHeight) + config.multilineSpacing
var numberOfSublayers = Int(round(CGFloat(bounds.height - config.paddingInsets.top - config.paddingInsets.bottom) / CGFloat(requiredSpaceForEachLine)))
if config.lines != 0, config.lines <= numberOfSublayers { numberOfSublayers = config.lines }
return numberOfSublayers
private func calculateNumLines(for config: SkeletonMultilinesLayerConfig) -> Int {
let definedNumberOfLines = config.lines
let requiredSpaceForEachLine = config.lineHeight + config.multilineSpacing
let calculatedNumberOfLines = Int(round(CGFloat(bounds.height - config.paddingInsets.top - config.paddingInsets.bottom) / CGFloat(requiredSpaceForEachLine)))
guard calculatedNumberOfLines > 0 else {
return 1
}
if definedNumberOfLines > 0, definedNumberOfLines <= calculatedNumberOfLines {
return definedNumberOfLines
}
return calculatedNumberOfLines
}
private func flipRectForRTLIfNeeded(_ rect: CGRect, isRTL: Bool) -> CGRect {
@@ -143,7 +152,8 @@ public extension CALayer {
var pulse: CAAnimation {
let pulseAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.backgroundColor))
pulseAnimation.fromValue = backgroundColor
//swiftlint:disable:next force_unwrapping
// swiftlint:disable:next force_unwrapping
pulseAnimation.toValue = UIColor(cgColor: backgroundColor!).complementaryColor.cgColor
pulseAnimation.duration = 1
pulseAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
@@ -153,25 +163,6 @@ public extension CALayer {
return pulseAnimation
}
// var sliding: CAAnimation {
// let startPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.startPoint))
// startPointAnim.fromValue = CGPoint(x: -1, y: 0.5)
// startPointAnim.toValue = CGPoint(x: 1, y: 0.5)
//
// let endPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.endPoint))
// endPointAnim.fromValue = CGPoint(x: 0, y: 0.5)
// endPointAnim.toValue = CGPoint(x: 2, y: 0.5)
//
// let animGroup = CAAnimationGroup()
// animGroup.animations = [startPointAnim, endPointAnim]
// animGroup.duration = 1.5
// animGroup.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
// animGroup.repeatCount = .infinity
// animGroup.isRemovedOnCompletion = false
//
// return animGroup
// }
func playAnimation(_ anim: SkeletonLayerAnimation, key: String, completion: (() -> Void)? = nil) {
skeletonSublayers.recursiveSearch(leafBlock: {
DispatchQueue.main.async { CATransaction.begin() }
+2 -2
View File
@@ -4,10 +4,10 @@ import Foundation
extension Int {
var whitespace: String {
return whitespaces
whitespaces
}
var whitespaces: String {
return String(repeating: " ", count: self)
String(repeating: " ", count: self)
}
}
+3 -3
View File
@@ -31,11 +31,11 @@ extension UIColor {
}
public var lighter: UIColor {
return adjust(by: 1.35)
adjust(by: 1.35)
}
public var darker: UIColor {
return adjust(by: 0.94)
adjust(by: 0.94)
}
func adjust(by percent: CGFloat) -> UIColor {
@@ -45,7 +45,7 @@ extension UIColor {
}
func makeGradient() -> [UIColor] {
return [self, self.complementaryColor, self]
[self, self.complementaryColor, self]
}
}
@@ -0,0 +1,25 @@
// Copyright © 2020 SkeletonView. All rights reserved.
import UIKit
// MARK: Frame
extension UIView {
var widthConstraints: [NSLayoutConstraint] {
nonContentSizeLayoutConstraints.filter { $0.firstAttribute == NSLayoutConstraint.Attribute.width }
}
var heightConstraints: [NSLayoutConstraint] {
nonContentSizeLayoutConstraints.filter { $0.firstAttribute == NSLayoutConstraint.Attribute.height }
}
@discardableResult
func setHeight(equalToConstant constant: CGFloat) -> NSLayoutConstraint {
let heightConstraint = heightAnchor.constraint(equalToConstant: constant)
NSLayoutConstraint.activate([heightConstraint])
return heightConstraint
}
var nonContentSizeLayoutConstraints: [NSLayoutConstraint] {
constraints.filter({ "\(type(of: $0))" != "NSContentSizeLayoutConstraint" })
}
}
@@ -5,6 +5,7 @@ import UIKit
// codebeat:disable[TOO_MANY_IVARS]
enum ViewAssociatedKeys {
static var skeletonable = "skeletonable"
static var hiddenWhenSkeletonIsActive = "hiddenWhenSkeletonIsActive"
static var status = "status"
static var skeletonLayer = "layer"
static var flowDelegate = "flowDelegate"
+18 -24
View File
@@ -10,32 +10,38 @@ import UIKit
// MARK: Frame
extension UIView {
var maxBoundsEstimated: CGRect {
var definedMaxBounds: CGRect {
if let parentStackView = (superview as? UIStackView) {
var origin: CGPoint = .zero
switch parentStackView.alignment {
case .trailing:
origin.x = maxWidthEstimated
origin.x = definedMaxWidth
default:
break
}
return CGRect(origin: origin, size: maxSizeEstimated)
return CGRect(origin: origin, size: definedMaxSize)
}
return CGRect(origin: .zero, size: maxSizeEstimated)
return CGRect(origin: .zero, size: definedMaxSize)
}
var maxSizeEstimated: CGSize {
return CGSize(width: maxWidthEstimated, height: maxHeightEstimated)
var definedMaxSize: CGSize {
CGSize(width: definedMaxWidth, height: definedMaxHeight)
}
var maxWidthEstimated: CGFloat {
let constraintsWidth = nonContentSizeLayoutConstraints.filter({ $0.firstAttribute == NSLayoutConstraint.Attribute.width })
return max(between: frame.size.width, andContantsOf: constraintsWidth)
var definedMaxWidth: CGFloat {
max(between: frame.size.width, andContantsOf: widthConstraints)
}
var maxHeightEstimated: CGFloat {
let constraintsHeight = nonContentSizeLayoutConstraints.filter({ $0.firstAttribute == NSLayoutConstraint.Attribute.height })
return max(between: frame.size.height, andContantsOf: constraintsHeight)
var definedMaxHeight: CGFloat {
max(between: frame.size.height, andContantsOf: heightConstraints)
}
var isRTL: Bool {
if #available(iOS 10.0, *), #available(tvOS 10.0, *) {
return effectiveUserInterfaceLayoutDirection == .rightToLeft
} else {
return false
}
}
private func max(between value: CGFloat, andContantsOf constraints: [NSLayoutConstraint]) -> CGFloat {
@@ -46,16 +52,4 @@ extension UIView {
})
return max
}
var nonContentSizeLayoutConstraints: [NSLayoutConstraint] {
return constraints.filter({ "\(type(of: $0))" != "NSContentSizeLayoutConstraint" })
}
var isRTL: Bool {
if #available(iOS 10.0, *), #available(tvOS 10.0, *) {
return effectiveUserInterfaceLayoutDirection == .rightToLeft
} else {
return false
}
}
}
@@ -8,6 +8,12 @@ public extension UIView {
get { return skeletonable }
set { skeletonable = newValue }
}
@IBInspectable
var isHiddenWhenSkeletonIsActive: Bool {
get { return hiddenWhenSkeletonIsActive }
set { hiddenWhenSkeletonIsActive = newValue }
}
@IBInspectable
var skeletonCornerRadius: Float {
@@ -23,6 +29,11 @@ public extension UIView {
get { return ao_get(pkey: &ViewAssociatedKeys.skeletonable) as? Bool ?? false }
set { ao_set(newValue, pkey: &ViewAssociatedKeys.skeletonable) }
}
private var hiddenWhenSkeletonIsActive: Bool {
get { return ao_get(pkey: &ViewAssociatedKeys.hiddenWhenSkeletonIsActive) as? Bool ?? false }
set { ao_set(newValue, pkey: &ViewAssociatedKeys.hiddenWhenSkeletonIsActive) }
}
private var skeletonableCornerRadius: Float {
get { return ao_get(pkey: &ViewAssociatedKeys.skeletonCornerRadius) as? Float ?? 0.0 }
+2 -2
View File
@@ -2,7 +2,7 @@
import Foundation
//Partially copy/pasted from https://github.com/jameslintaylor/AssociatedObjects/blob/master/AssociatedObjects/AssociatedObjects.swift
// Partially copy/pasted from https://github.com/jameslintaylor/AssociatedObjects/blob/master/AssociatedObjects/AssociatedObjects.swift
enum AssociationPolicy: UInt {
// raw values map to objc_AssociationPolicy's raw values
case assign = 0
@@ -17,7 +17,7 @@ enum AssociationPolicy: UInt {
}
}
protocol AssociatedObjects: class { }
protocol AssociatedObjects: AnyObject { }
// transparent wrappers
extension AssociatedObjects {
@@ -10,18 +10,49 @@ import UIKit
extension UIView {
@objc func prepareViewForSkeleton() {
isUserInteractionEnabled = false
startTransition { [weak self] in
self?.backgroundColor = .clear
self?.isUserInteractionEnabled = false
}
}
}
extension UILabel {
var desiredHeightBasedOnNumberOfLines: CGFloat {
let lineHeight = constraintHeight ?? SkeletonAppearance.default.multilineHeight
let spaceNeededForEachLine = lineHeight * CGFloat(numberOfLines)
let spaceNeededForSpaces = skeletonLineSpacing * CGFloat(numberOfLines - 1)
let padding = paddingInsets.top + paddingInsets.bottom
return spaceNeededForEachLine + spaceNeededForSpaces + padding
}
func updateHeightConstraintsIfNeeded() {
guard numberOfLines > 1 else { return }
let desiredHeight = desiredHeightBasedOnNumberOfLines
if desiredHeight > definedMaxHeight {
backupHeightConstraints = heightConstraints
NSLayoutConstraint.deactivate(heightConstraints)
setHeight(equalToConstant: desiredHeight)
}
}
func restoreBackupHeightConstraints() {
heightConstraints.forEach {
removeConstraint($0)
}
guard !backupHeightConstraints.isEmpty else { return }
NSLayoutConstraint.activate(backupHeightConstraints)
backupHeightConstraints.removeAll()
}
override func prepareViewForSkeleton() {
backgroundColor = .clear
isUserInteractionEnabled = false
resignFirstResponder()
startTransition { [weak self] in
self?.updateHeightConstraintsIfNeeded()
self?.textColor = .clear
}
}
@@ -30,6 +61,7 @@ extension UILabel {
extension UITextView {
override func prepareViewForSkeleton() {
backgroundColor = .clear
isUserInteractionEnabled = false
resignFirstResponder()
startTransition { [weak self] in
self?.textColor = .clear
@@ -37,9 +69,22 @@ extension UITextView {
}
}
extension UITextField {
override func prepareViewForSkeleton() {
backgroundColor = .clear
resignFirstResponder()
startTransition { [weak self] in
self?.textColor = .clear
self?.placeholder = nil
}
}
}
extension UIImageView {
override func prepareViewForSkeleton() {
backgroundColor = .clear
isUserInteractionEnabled = false
startTransition { [weak self] in
self?.image = nil
}
@@ -49,6 +94,7 @@ extension UIImageView {
extension UIButton {
override func prepareViewForSkeleton() {
backgroundColor = .clear
isUserInteractionEnabled = false
startTransition { [weak self] in
self?.setTitle(nil, for: .normal)
}
@@ -7,17 +7,14 @@ enum MultilineAssociatedKeys {
static var multilineCornerRadius = "multilineCornerRadius"
static var multilineSpacing = "multilineSpacing"
static var paddingInsets = "paddingInsets"
static var backupHeightConstraints = "backupHeightConstraints"
}
protocol ContainsMultilineText {
var multilineTextFont: UIFont? { get }
var constraintHeight: CGFloat? { get }
var numLines: Int { get }
var lastLineFillingPercent: Int { get }
var multilineCornerRadius: Int { get }
var multilineSpacing: CGFloat { get }
var paddingInsets: UIEdgeInsets { get }
}
extension ContainsMultilineText {
var numLines: Int { return 0 }
}
+11 -6
View File
@@ -12,13 +12,13 @@ public extension UILabel {
@IBInspectable
var linesCornerRadius: Int {
get { return multilineCornerRadius }
set { multilineCornerRadius = min(newValue, 10) }
set { multilineCornerRadius = newValue }
}
@IBInspectable
var skeletonLineSpacing: CGFloat {
get { return multilineSpacing }
set { multilineSpacing = min(newValue, 10) }
set { multilineSpacing = newValue }
}
var skeletonPaddingInsets: UIEdgeInsets {
@@ -28,10 +28,10 @@ public extension UILabel {
}
extension UILabel: ContainsMultilineText {
var multilineTextFont: UIFont? {
return font
}
var constraintHeight: CGFloat? {
backupHeightConstraints.first?.constant
}
var numLines: Int {
return numberOfLines
}
@@ -55,4 +55,9 @@ extension UILabel: ContainsMultilineText {
get { return ao_get(pkey: &MultilineAssociatedKeys.paddingInsets) as? UIEdgeInsets ?? .zero }
set { ao_set(newValue, pkey: &MultilineAssociatedKeys.paddingInsets) }
}
var backupHeightConstraints: [NSLayoutConstraint] {
get { return ao_get(pkey: &MultilineAssociatedKeys.backupHeightConstraints) as? [NSLayoutConstraint] ?? [] }
set { ao_set(newValue, pkey: &MultilineAssociatedKeys.backupHeightConstraints) }
}
}
@@ -12,13 +12,13 @@ public extension UITextView {
@IBInspectable
var linesCornerRadius: Int {
get { return multilineCornerRadius }
set { multilineCornerRadius = min(newValue, 10) }
set { multilineCornerRadius = newValue }
}
@IBInspectable
var skeletonLineSpacing: CGFloat {
get { return multilineSpacing }
set { multilineSpacing = min(newValue, 10) }
set { multilineSpacing = newValue }
}
var skeletonPaddingInsets: UIEdgeInsets {
@@ -28,9 +28,13 @@ public extension UITextView {
}
extension UITextView: ContainsMultilineText {
var multilineTextFont: UIFont? {
return font
}
var constraintHeight: CGFloat? {
heightConstraints.first?.constant
}
var numLines: Int {
-1
}
var lastLineFillingPercent: Int {
get {
+29
View File
@@ -54,6 +54,8 @@ extension UILabel {
startTransition { [weak self] in
guard let storedLabelState = self?.labelState else { return }
self?.restoreBackupHeightConstraints()
if self?.textColor == .clear || forced {
self?.textColor = storedLabelState.textColor
}
@@ -84,6 +86,33 @@ extension UITextView {
}
}
extension UITextField {
var textState: RecoverableTextFieldState? {
get { return ao_get(pkey: &ViewAssociatedKeys.labelViewState) as? RecoverableTextFieldState }
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.labelViewState) }
}
override func saveViewState() {
super.saveViewState()
textState = RecoverableTextFieldState(view: self)
}
override func recoverViewState(forced: Bool) {
super.recoverViewState(forced: forced)
startTransition { [weak self] in
guard let storedLabelState = self?.textState else { return }
if self?.textColor == .clear || forced {
self?.textColor = storedLabelState.textColor
}
if self?.placeholder == nil || forced {
self?.placeholder = storedLabelState.placeholder
}
}
}
}
extension UIImageView {
var imageState: RecoverableImageViewState? {
get { return ao_get(pkey: &ViewAssociatedKeys.imageViewState) as? RecoverableImageViewState }
@@ -34,6 +34,16 @@ struct RecoverableTextViewState {
}
}
struct RecoverableTextFieldState {
var textColor: UIColor?
var placeholder: String?
init(view: UITextField) {
self.textColor = view.textColor
self.placeholder = view.placeholder
}
}
struct RecoverableImageViewState {
var image: UIImage?
+5 -4
View File
@@ -18,8 +18,8 @@ public enum GradientDirection {
case topLeftBottomRight
case bottomRightTopLeft
public func slidingAnimation(duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation {
return SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: self, duration: duration)
public func slidingAnimation(duration: CFTimeInterval = 1.5, autoreverses: Bool = false) -> SkeletonLayerAnimation {
return SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: self, duration: duration, autoreverses: autoreverses)
}
// codebeat:disable[ABC]
@@ -62,8 +62,8 @@ public enum GradientDirection {
public class SkeletonAnimationBuilder {
public init() { }
public func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation {
return { layer in
public func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5, autoreverses: Bool = false) -> SkeletonLayerAnimation {
return { _ in
let startPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.startPoint))
startPointAnim.fromValue = direction.startPoint.from
startPointAnim.toValue = direction.startPoint.to
@@ -77,6 +77,7 @@ public class SkeletonAnimationBuilder {
animGroup.duration = duration
animGroup.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
animGroup.repeatCount = .infinity
animGroup.autoreverses = autoreverses
animGroup.isRemovedOnCompletion = false
return animGroup
+7 -6
View File
@@ -49,7 +49,7 @@ struct SkeletonLayer {
self.holder = holder
self.maskLayer = type.layer
self.maskLayer.anchorPoint = .zero
self.maskLayer.bounds = holder.maxBoundsEstimated
self.maskLayer.bounds = holder.definedMaxBounds
self.maskLayer.cornerRadius = CGFloat(holder.skeletonCornerRadius)
addTextLinesIfNeeded()
self.maskLayer.tint(withColors: colors)
@@ -61,7 +61,7 @@ struct SkeletonLayer {
}
func layoutIfNeeded() {
if let bounds = holder?.maxBoundsEstimated {
if let bounds = holder?.definedMaxBounds {
maskLayer.bounds = bounds
}
updateLinesIfNeeded()
@@ -83,9 +83,9 @@ struct SkeletonLayer {
/// If there is more than one line, or custom preferences have been set for a single line, draw custom layers
func addTextLinesIfNeeded() {
guard let textView = holderAsTextView else { return }
let lineHeight = textView.constraintHeight ?? SkeletonAppearance.default.multilineHeight
let config = SkeletonMultilinesLayerConfig(lines: textView.numLines,
lineHeight: textView.multilineTextFont?.lineHeight,
lineHeight: lineHeight,
type: type,
lastLineFillPercent: textView.lastLineFillingPercent,
multilineCornerRadius: textView.multilineCornerRadius,
@@ -98,8 +98,9 @@ struct SkeletonLayer {
func updateLinesIfNeeded() {
guard let textView = holderAsTextView else { return }
let lineHeight = textView.constraintHeight ?? SkeletonAppearance.default.multilineHeight
let config = SkeletonMultilinesLayerConfig(lines: textView.numLines,
lineHeight: textView.multilineTextFont?.lineHeight,
lineHeight: lineHeight,
type: type,
lastLineFillPercent: textView.lastLineFillingPercent,
multilineCornerRadius: textView.multilineCornerRadius,
@@ -112,7 +113,7 @@ struct SkeletonLayer {
var holderAsTextView: ContainsMultilineText? {
guard let textView = holder as? ContainsMultilineText,
(textView.numLines == 0 || textView.numLines > 1 || textView.numLines == 1 && !SkeletonAppearance.default.renderSingleLineAsView) else {
(textView.numLines == -1 || textView.numLines == 0 || textView.numLines > 1 || textView.numLines == 1 && !SkeletonAppearance.default.renderSingleLineAsView) else {
return nil
}
return textView
+7 -2
View File
@@ -114,6 +114,9 @@ extension UIView {
}
private func recursiveShowSkeleton(skeletonConfig config: SkeletonConfig, root: UIView? = nil) {
if isHiddenWhenSkeletonIsActive {
isHidden = true
}
guard isSkeletonable && !isSkeletonActive else { return }
currentSkeletonConfig = config
swizzleLayoutSubviews()
@@ -133,7 +136,7 @@ extension UIView {
private func showSkeletonIfNotActive(skeletonConfig config: SkeletonConfig) {
guard !isSkeletonActive else { return }
saveViewState()
isUserInteractionEnabled = false
prepareViewForSkeleton()
addSkeletonLayer(skeletonConfig: config)
}
@@ -183,8 +186,10 @@ extension UIView {
private func recursiveHideSkeleton(reloadDataAfter reload: Bool, transition: SkeletonTransitionStyle, root: UIView? = nil) {
guard isSkeletonActive else { return }
if isHiddenWhenSkeletonIsActive {
isHidden = false
}
currentSkeletonConfig?.transition = transition
isUserInteractionEnabled = true
removeDummyDataSourceIfNeeded(reloadAfter: reload)
subviewsSkeletonables.recursiveSearch(leafBlock: {
recoverViewState(forced: false)
+8 -8
View File
@@ -4,46 +4,46 @@ import UIKit
extension UIView {
@objc var subviewsSkeletonables: [UIView] {
return subviewsToSkeleton.filter { $0.isSkeletonable }
subviewsToSkeleton.filter { $0.isSkeletonable }
}
@objc var subviewsToSkeleton: [UIView] {
return subviews
subviews
}
}
extension UITableView {
override var subviewsToSkeleton: [UIView] {
return visibleCells + visibleSectionHeaders + visibleSectionFooters
visibleCells + visibleSectionHeaders + visibleSectionFooters
}
}
extension UITableViewCell {
override var subviewsToSkeleton: [UIView] {
return contentView.subviews
contentView.subviews
}
}
extension UITableViewHeaderFooterView {
override var subviewsToSkeleton: [UIView] {
return contentView.subviews
contentView.subviews
}
}
extension UICollectionView {
override var subviewsToSkeleton: [UIView] {
return subviews
subviews
}
}
extension UICollectionViewCell {
override var subviewsToSkeleton: [UIView] {
return contentView.subviews
contentView.subviews
}
}
extension UIStackView {
override var subviewsToSkeleton: [UIView] {
return arrangedSubviews
arrangedSubviews
}
}
@@ -0,0 +1,6 @@
import XCTest
@testable import SkeletonView
final class SkeletonViewTests: XCTestCase {
}
+38 -35
View File
@@ -1,8 +1,8 @@
![](Assets/header2.jpg)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/header2.jpg)
<p align="center">
<a href="https://github.com/Juanpe/SkeletonView/workflows/build">
<img src="https://github.com/Juanpe/SkeletonView/workflows/build/badge.svg">
<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" />
@@ -27,18 +27,21 @@ Hoy en día, La mayoría de las apps tiene procesos asíncronos, como peticiones
Enjoy it! 🙂
##
- [](#)
- [🌟 Destacado](#-destacado)
- [🎬 Videotutoriales](#-videotutoriales)
- [📲 Instalación](#-instalación)
- [🐒 ¿Cómo funciona?](#-cómo-funciona)
- [](#-1)
- [🌿 Colecciones](#-colecciones)
- [🔠 Textos](#-textos)
- [🦋 Apariencia](#-apariencia)
- [🎨 Colores](#-colors)
- [🎨 Colores](#-colores)
- [Imagen extraída de la web https://flatuicolors.com](#imagen-extraída-de-la-web-httpsflatuicolorscom)
- [🏃‍♀️ Animaciones](#-animaciones)
- [🏄 Transiciones](#-transiciones)
- [✨ Miscelánea](#-miscelánea)
- [❤️ Contribuir](#-contribuir)
- [❤️ Contributing](#-contributing)
- [📢 Menciones](#-menciones)
- [👨🏻‍💻 Autor](#-autor)
- [👮🏻 Licencia](#-licencia)
@@ -101,7 +104,7 @@ avatarImageView.isSkeletonable = true
```
**Con IB/Storyboards:**
![](Assets/storyboard.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/storyboard.png)
3️⃣ Una vez indicado, solo tienes que mostrar el **skeleton**. Tienes **4** opciones:
@@ -131,16 +134,16 @@ avatarImageView.isSkeletonable = true
</tr>
<tr>
<td width="25%">
<img src="Assets/solid.png"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/solid.png"></img>
</td>
<td width="25%">
<img src="Assets/gradient.png"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/gradient.png"></img>
</td>
<td width="25%">
<img src="Assets/solid_animated.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/solid_animated.gif"></img>
</td>
<td width="25%">
<img src="Assets/gradient_animated.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/gradient_animated.gif"></img>
</td>
</tr>
</table>
@@ -222,7 +225,7 @@ El resto del proceso es exactamente igual que con las `UITableView`.
### 🔠 Textos
![](Assets/multilines2.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multilines2.png)
Cuando usas elementos que contienen texto,`SkeletonView` dibujo líneas para simular el texto.
@@ -233,8 +236,8 @@ Puedes especificar algunos atributos para estos elementos:
| Atributo | Valores | Por defecto | Vista previa
| ------- | ------- |------- | -------
| **Porcentaje de relleno** de la última línea. | `0...100` | `70%` | ![](Assets/multiline_lastline.png)
| **Radio de las esquinas** de las líneas. | `0...10` | `0` | ![](Assets/multiline_corner.png)
| **Porcentaje de relleno** de la última línea. | `0...100` | `70%` | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_lastline.png)
| **Radio de las esquinas** de las líneas. | `0...10` | `0` | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_corner.png)
Para modificar alguno de los valores lo puedes hacer **con código**::
```swift
@@ -244,7 +247,7 @@ descriptionTextView.linesCornerRadius = 5
O usando **IB/Storyboards**:
![](Assets/multiline_customize.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_customize.png)
### 🦋 Apariencia
@@ -294,7 +297,7 @@ Además, **SkeletonView** añade 20 colores flat 🤙🏼
```UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...```
![](Assets/flatcolors.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/flatcolors.png)
###### Imagen extraída de la web [https://flatuicolors.com](https://flatuicolors.com)
@@ -335,12 +338,12 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
| Dirección | Vista previa
|------- | -------
| .leftRight | ![](Assets/sliding_left_to_right.gif)
| .rightLeft | ![](Assets/sliding_right_to_left.gif)
| .topBottom | ![](Assets/sliding_top_to_bottom.gif)
| .bottomTop | ![](Assets/sliding_bottom_to_top.gif)
| .topLeftBottomRight | ![](Assets/sliding_topLeft_to_bottomRight.gif)
| .bottomRightTopLeft | ![](Assets/sliding_bottomRight_to_topLeft.gif)
| .leftRight | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_left_to_right.gif)
| .rightLeft | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_right_to_left.gif)
| .topBottom | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_top_to_bottom.gif)
| .bottomTop | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_bottom_to_top.gif)
| .topLeftBottomRight | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_topLeft_to_bottomRight.gif)
| .bottomRightTopLeft | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_bottomRight_to_topLeft.gif)
> **😉 ¡Truco!**
>
@@ -376,10 +379,10 @@ La transición por defecto es `crossDissolve(0.25)`
</tr>
<tr>
<td width="50%">
<img src="Assets/skeleton_transition_nofade.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/skeleton_transition_nofade.gif"></img>
</td>
<td width="50%">
<img src="Assets/skeleton_transition_fade.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/skeleton_transition_fade.gif"></img>
</td>
</tr>
</table>
@@ -405,12 +408,12 @@ view.showSkeleton()
| Configuración | Resultado|
|:-------:|:-------:|
|<img src="Assets/no_skeletonable.jpg" width="350"/> | <img src="Assets/no_skeletonables_result.png" width="350"/>|
|<img src="Assets/container_no_skeletonable.jpg" width="350"/> | <img src="Assets/no_skeletonables_result.png" width="350"/>|
|<img src="Assets/container_skeletonable.jpg" width="350"/> | <img src="Assets/container_skeletonable_result.png" width="350"/>|
|<img src="Assets/all_skeletonables.jpg" width="350"/>| <img src="Assets/all_skeletonables_result.png" width="350"/>|
|<img src="Assets/tableview_no_skeletonable.jpg" width="350"/> | <img src="Assets/tableview_no_skeletonable_result.png" height="350"/>|
|<img src="Assets/tableview_skeletonable.jpg" width="350"/> | <img src="Assets/tableview_skeletonable_result.png" height="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonable.jpg" width="350"/> | <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonables_result.png" width="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_no_skeletonable.jpg" width="350"/> | <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonables_result.png" width="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_skeletonable.jpg" width="350"/> | <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_skeletonable_result.png" width="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/all_skeletonables.jpg" width="350"/>| <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/all_skeletonables_result.png" width="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_no_skeletonable.jpg" width="350"/> | <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_no_skeletonable_result.png" height="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_skeletonable.jpg" width="350"/> | <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_skeletonable_result.png" height="350"/>|
@@ -418,7 +421,7 @@ view.showSkeleton()
Esta ilustración muestra como deberías específicar qué elementos son skeletonables cuando estás usando una `UITableView`:
<img src="Assets/tableview_scheme.png" width="700px">
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_scheme.png" width="700px">
**Actualiza el skeleton**
@@ -444,17 +447,17 @@ var skeletonDescription: String
```
Y es representada de la siguiente manera:
![](Assets/debug_description.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/debug_description.png)
Para activar el **modo debug**. Solo tienes que añadir una variable de entorno con esta clave `SKELETON_DEBUG` y activarla.
![](Assets/debug_mode.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/debug_mode.png)
Entonces, cuando el skeleton aparece, tu podrás ver la jerarquía de vistas en la consola de Xcode.
<details>
<summary>Abre para ver un ejemplo </summary>
<img src="Assets/hierarchy_output.png" />
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/hierarchy_output.png" />
</details>
@@ -474,7 +477,7 @@ Esto es un proyecto open source, siéntete libre de contribuir. ¿Cómo?
Échale un vistazo a [los que ya han contribuído](https://github.com/Juanpe/SkeletonView/graphs/contributors)
Para más información, por favor, lee la [guía de contribución](https://github.com/Juanpe/SkeletonView/blob/develop/CONTRIBUTING.md).
Para más información, por favor, lee la [guía de contribución](https://github.com/Juanpe/SkeletonView/blob/main/CONTRIBUTING.md).
## 📢 Menciones
@@ -499,7 +502,7 @@ Para más información, por favor, lee la [guía de contribución](https://githu
[Juanpe Catalán](http://www.twitter.com/JuanpeCatalan)
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/https://github.com/Juanpe/SkeletonView/blob/main/Assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
## 👮🏻 Licencia
+67 -59
View File
@@ -1,8 +1,8 @@
![](Assets/header2.jpg)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/header2.jpg)
<p align="center">
<a href="https://github.com/Juanpe/SkeletonView/workflows/build">
<img src="https://github.com/Juanpe/SkeletonView/workflows/build/badge.svg">
<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="https://img.shields.io/badge/Swift-5-orange.svg" />
@@ -26,10 +26,10 @@
🌎 Traductions : </br>
[Original](https://github.com/Juanpe/SkeletonView) </br>
[🇨🇳](https://github.com/Juanpe/SkeletonView/blob/master/README_zh.md) [@WhatsXie](https://twitter.com/WhatsXie) </br>
[🇧🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_pt-br.md) [@brunomunizaf](https://twitter.com/brunomuniz_af) </br>
[🇰🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_ko.md) [@techinpark](https://twitter.com/techinpark) </br>
[🇫🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_fr.md) [@OmarJalil](https://github.com/OmarJalil)
[🇨🇳](https://github.com/Juanpe/SkeletonView/blob/main/README_zh.md) [@WhatsXie](https://twitter.com/WhatsXie) </br>
[🇧🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_pt-br.md) [@brunomunizaf](https://twitter.com/brunomuniz_af) </br>
[🇰🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_ko.md) [@techinpark](https://twitter.com/techinpark) </br>
[🇫🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_fr.md) [@OmarJalil](https://github.com/OmarJalil)
Aujourd'hui, presque toutes les applications ont des processus asynchrones, tels que les requêtes Api, les processus de longue durée, etc. Et pendant que les processus fonctionnent, les développeurs affichent généralement une vue de chargement pour montrer aux utilisateurs que quelque chose se passe.
@@ -37,28 +37,36 @@ Aujourd'hui, presque toutes les applications ont des processus asynchrones, tels
Profitez-en! 🙂
* [Caractéristiques](#-caractéristiques)
* [Guides](#-guides)
* [Installation](#-installation)
* [Cocoapods](#utilisation-de-cocoapods)
* [Carthage](#utilisation-de-carthage)
* [SPM](#utilisation-du-gestionnaire-de-paquets-Swift)
* [Comment utiliser](#-mode-d'emploi)
* [Collections](#-collections)
* [Texte Multiligne](#-texte-multiligne)
* [Couleurs personnalisées](#-couleurs-personnalisées)
* [Présentation](#-présentation)
* [Animations personnalisées](#-animations-personnalisées)
* [Transitions](#-transitions)
* [Hiérarchie](#-hiérarchie)
* [Débugger](#-débugger)
* [Documentation](#-documentation)
* [Versions OS & SDK supportées](#-versions-os-et-sdk-supportées)
* [Prochaines étapes](#-prochaines-étapes)
* [Contribuer](#-contribuer)
* [Mentions](#-mentions)
* [Auteur](#-auteur)
* [Licence](#-licence)
- [🌟 Caractéristiques](#-caractéristiques)
- [🎬 Guides](#-guides)
- [📲 Installation](#-installation)
- [Utilisation de CocoaPods](#utilisation-de-cocoapods)
- [Utilisation de Carthage](#utilisation-de-carthage)
- [Utilisation du gestionnaire de paquets Swift](#utilisation-du-gestionnaire-de-paquets-swift)
- [🐒 Mode d'emploi](#-mode-demploi)
- [Extra](#extra)
- [Mise en page des vues squelettes](#mise-en-page-des-vues-squelettes)
- [Mise à jour de la configuration du squelette](#mise-à-jour-de-la-configuration-du-squelette)
- [🌿 Collections](#-collections)
- [UITableView](#uitableview)
- [UICollectionView](#uicollectionview)
- [📰 Texte multiligne](#-texte-multiligne)
- [🎛 Personnaliser](#-personnaliser)
- [🎨 Couleurs personnalisées](#-couleurs-personnalisées)
- [Image tirée du site web https://flatuicolors.com](#image-tirée-du-site-web-httpsflatuicolorscom)
- [🦋 Présentation](#-présentation)
- [🤓 Animations personnalisées](#-animations-personnalisées)
- [🏄 Transitions](#-transitions)
- [👨👧👦 Hiérarchie](#-hiérarchie)
- [🔬 Débugger](#-débugger)
- [📚 Documentation](#-documentation)
- [📋 Versions OS et SDK supportées](#-versions-os-et-sdk-supportées)
- [📬 Prochaines étapes](#-prochaines-étapes)
- [❤️ Contribuer](#-contribuer)
- [Projet généré avec SwiftPlate](#projet-généré-avec-swiftplate)
- [📢 Mentions](#-mentions)
- [👨🏻‍💻 Auteur](#-auteur)
- [👮🏻 Licence](#-licence)
## 🌟 Caractéristiques
@@ -72,7 +80,7 @@ Profitez-en! 🙂
## 🎬 Guides
[<img src="Assets/thumb_getting_started.png">](https://youtu.be/75kgOhWsPNA)
[<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/thumb_getting_started.png">](https://youtu.be/75kgOhWsPNA)
## 📲 Installation
@@ -119,7 +127,7 @@ avatarImageView.isSkeletonable = true
```
**Utilisation des IB/Storyboards:**
![](Assets/storyboard.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/storyboard.png)
**Une fois que vous avez défini les vues, vous pouvez montrer le **squelette**. Pour le faire, vous avez quatre choix :
@@ -149,16 +157,16 @@ avatarImageView.isSkeletonable = true
</tr>
<tr>
<td width="25%">
<img src="Assets/solid.png"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/solid.png"></img>
</td>
<td width="25%">
<img src="Assets/gradient.png"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/gradient.png"></img>
</td>
<td width="25%">
<img src="Assets/solid_animated.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/solid_animated.gif"></img>
</td>
<td width="25%">
<img src="Assets/gradient_animated.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/gradient_animated.gif"></img>
</td>
</tr>
</table>
@@ -255,7 +263,7 @@ Il n'y a qu'une seule méthode à mettre en œuvre pour faire connaître au Sque
Voici une illustration qui montre comment vous devez spécifier quels éléments sont squelettisables lorsque vous utilisez une `UITableView` :
![](Assets/tableview_scheme.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_scheme.png)
Comme vous pouvez le voir, nous devons faire `skeletonable` la tableview, la cellule et les éléments de l'interface visuelle, mais nous n'avons pas besoin de faire `skeletonable` le `contentView`.
@@ -275,7 +283,7 @@ Le reste du processus ressemble à une `UITableView`.
### 📰 Texte multiligne
![](Assets/multilines2.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multilines2.png)
Lorsqu'on utilise des éléments avec du texte, `SkeletonView` dessine des lignes pour simuler le texte.
En outre, vous pouvez décider combien de lignes vous voulez. Si `numberOfLines` est réglé à zéro, il calculera le combien de lignes sont nécessaires pour remplir tout le squelette et il sera dessiné. Au contraire, si vous le réglez sur un, deux ou tout autre nombre supérieur à zéro, il ne dessinera que ce nombre de lignes.
@@ -286,8 +294,8 @@ Vous pouvez définir certaines propriétés pour les éléments multilignes.
| Propriété | Valeurs | Par défaut | Aperçu
| ------- | ------- |------- | -------
| **Pourcentage de remplissage** de la dernière ligne. | `0...100` | `70%` | ![](Assets/multiline_lastline.png)
| **Corner radius** des lignes. (**NEW**) | `0...10` | `0` | ![](Assets/multiline_corner.png)
| **Pourcentage de remplissage** de la dernière ligne. | `0...100` | `70%` | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_lastline.png)
| **Corner radius** des lignes. (**NEW**) | `0...10` | `0` | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_corner.png)
Pour modifier le pourcentage ou le rayon **à l'aide du code**, définissez les propriétés :
@@ -298,7 +306,7 @@ descriptionTextView.linesCornerRadius = 5
Ou, si vous préférez, utilisez l'**IB/Storyboard** :
![](Assets/multiline_customize.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_customize.png)
### 🎨 Couleurs personnalisées
@@ -320,7 +328,7 @@ En outre, `SkeletonView` dispose de 20 couleurs unies 🤙🏼
`UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...`
![](Assets/flatcolors.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/flatcolors.png)
###### Image tirée du site web [https://flatuicolors.com](https://flatuicolors.com)
### 🦋 Présentation
@@ -388,12 +396,12 @@ view.showAnimatedGradientSkeleton(usingGradient : gradient, animation : animatio
| Direction | Aperçu
|------- | -------
| .leftRight | ![](Assets/sliding_left_to_right.gif)
| .rightLeft | ![](Assets/sliding_right_to_left.gif)
| .topBottom | ![](Assets/sliding_top_to_bottom.gif)
| .bottomTop | ![](Assets/sliding_bottom_to_top.gif)
| .topLeftBottomRight | ![](Assets/sliding_topLeft_to_bottomRight.gif)
| .bottomRightTopLeft | ![](Assets/sliding_bottomRight_to_topLeft.gif)
| .leftRight | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_left_to_right.gif)
| .rightLeft | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_right_to_left.gif)
| .topBottom | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_top_to_bottom.gif)
| .bottomTop | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_bottom_to_top.gif)
| .topLeftBottomRight | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_topLeft_to_bottomRight.gif)
| .bottomRightTopLeft | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_bottomRight_to_topLeft.gif)
> **😉 TRICK!**
Il existe une autre façon de créer des animations de glissement, en utilisant simplement ce raccourci :
@@ -425,10 +433,10 @@ La valeur par défaut est `crossDissolve(0.25)`.
</tr>
<tr>
<td width="50%">
<img src="Assets/skeleton_transition_nofade.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/skeleton_transition_nofade.gif"></img>
</td>
<td width="50%">
<img src="Assets/skeleton_transition_fade.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/skeleton_transition_fade.gif"></img>
</td>
</tr>
</table>
@@ -448,12 +456,12 @@ view.showSkeleton()
| Configuration | Résultat|
|:-------:|:-------:|
|<img src="Assets/no_skeletonable.jpg" width="350"/> | <img src="Assets/no_skeletonables_result.png" width="350"/>|
|<img src="Assets/container_no_skeletonable.jpg" width="350"/> | <img src="Assets/no_skeletonables_result.png" width="350"/>|
|<img src="Assets/container_skeletonable.jpg" width="350"/> | <img src="Assets/container_skeletonable_result.png" width="350"/>|
|<img src="Assets/all_skeletonables.jpg" width="350"/>| <img src="Assets/all_skeletonables_result.png" width="350"/>|
|<img src="Assets/tableview_no_skeletonable.jpg" width="350"/> | <img src="Assets/tableview_no_skeletonable_result.png" height="350"/>|
|<img src="Assets/tableview_skeletonable.jpg" width="350"/> | <img src="Assets/tableview_skeletonable_result.png" height="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonable.jpg" width="350"/> | <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonables_result.png" width="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_no_skeletonable.jpg" width="350"/> | <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonables_result.png" width="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_skeletonable.jpg" width="350"/> | <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_skeletonable_result.png" width="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/all_skeletonables.jpg" width="350"/>| <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/all_skeletonables_result.png" width="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_no_skeletonable.jpg" width="350"/> | <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_no_skeletonable_result.png" height="350"/>|
|<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_skeletonable.jpg" width="350"/> | <img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_skeletonable_result.png" height="350"/>|
### 🔬 Débugger
@@ -465,17 +473,17 @@ var skeletonDescription : String
```
La représentation du squelette ressemble à ceci :
![](Assets/debug_description.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/debug_description.png)
En outre, vous pouvez activer le nouveau mode **debug**. Il suffit d'ajouter la variable d'environnement `SKELETON_DEBUG` et de l'activer.
![](Assets/debug_mode.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/debug_mode.png)
Ensuite, lorsque le squelette apparaît, vous pouvez voir la hiérarchie des vues dans la console Xcode.
<details>
<summary>Ouvrez pour voir un exemple de sortie</summary>
<img src="Assets/hierarchy_output.png" />
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/hierarchy_output.png" />
</details>
### 📚 Documentation
@@ -533,7 +541,7 @@ Voir [tous les contributeurs](https://github.com/Juanpe/SkeletonView/graphs/cont
* Juanpe Catalán [![alt text][1.1]][1]
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/https://github.com/Juanpe/SkeletonView/blob/main/Assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
## 👮🏻 Licence
+33 -33
View File
@@ -1,8 +1,8 @@
![](Assets/header2.jpg)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/header2.jpg)
<p align="center">
<a href="https://github.com/Juanpe/SkeletonView/workflows/build">
<img src="https://github.com/Juanpe/SkeletonView/workflows/build/badge.svg">
<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="https://img.shields.io/badge/Swift-5-orange.svg" />
@@ -25,10 +25,10 @@
🌎 번역에 도움을 주신분들: </br>
[Original](https://github.com/Juanpe/SkeletonView) </br>
[🇨🇳](https://github.com/Juanpe/SkeletonView/blob/master/README_zh.md) [@WhatsXie](https://twitter.com/WhatsXie) </br>
[🇧🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_pt-br.md) [@brunomunizaf](https://twitter.com/brunomuniz_af) </br>
[🇰🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_ko.md) [@techinpark](https://twitter.com/techinpark) </br>
[🇫🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_fr.md) [@OmarJalil](https://github.com/OmarJalil)
[🇨🇳](https://github.com/Juanpe/SkeletonView/blob/main/README_zh.md) [@WhatsXie](https://twitter.com/WhatsXie) </br>
[🇧🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_pt-br.md) [@brunomunizaf](https://twitter.com/brunomuniz_af) </br>
[🇰🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_ko.md) [@techinpark](https://twitter.com/techinpark) </br>
[🇫🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_fr.md) [@OmarJalil](https://github.com/OmarJalil)
오늘날 거의 대부분의 앱들은 비동기 방식의 API 호출을 사용하는 프로세스를 가지고 있습니다.
프로세스가 작동하는동안 개발자들은 작업이 실행되고 있다는것을 사용자들에게 보여주기 위해서 로딩 뷰를 배치합니다.
@@ -72,7 +72,7 @@
## 🎬 사용가이드
[<img src="Assets/thumb_getting_started.png">](https://youtu.be/75kgOhWsPNA)
[<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/thumb_getting_started.png">](https://youtu.be/75kgOhWsPNA)
## 📲 설치 방법
@@ -123,7 +123,7 @@ avatarImageView.isSkeletonable = true
```
**인터페이스빌더 / 스토리보드를 이용하는 방법:**
![](Assets/storyboard.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/storyboard.png)
**3.** 당신이 뷰를 세팅할때, **skeleton** 옵션을 사용 할 수 있습니다. 총 **4** 가지 옵션을 지원합니다:
@@ -153,16 +153,16 @@ avatarImageView.isSkeletonable = true
</tr>
<tr>
<td width="25%">
<img src="Assets/solid.png"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/solid.png"></img>
</td>
<td width="25%">
<img src="Assets/gradient.png"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/gradient.png"></img>
</td>
<td width="25%">
<img src="Assets/solid_animated.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/solid_animated.gif"></img>
</td>
<td width="25%">
<img src="Assets/gradient_animated.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/gradient_animated.gif"></img>
</td>
</tr>
</table>
@@ -224,7 +224,7 @@ func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection s
아래의 그림은 `UITableView` 에서 특정한 요소에 skeleton 을 지정하는 방법을 보여주는 이미지 입니다:
![](Assets/tableview_scheme.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/tableview_scheme.png)
위의 이미지에서 보이듯, 테이블 뷰와 셀에 들어가는 UI 요소들에는 적용을 해야하지만, `contentView`에 skeleton을 적용할 필요는 없습니다.
@@ -245,7 +245,7 @@ public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
### 📰 Multiline text
![](Assets/multilines2.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multilines2.png)
텍스트가 들어있는 요소를 사용한다면, ```SkeletonView``` 에서 텍스트의 라인을 그려줍니다.
그리고, 원하는 라인 수를 설정할 수 있습니다. 만약 ```numberOfLines``` 을 0으로 설정한다면, 자동으로 필요한 라인수를 계산해서 그려줍니다. 대신 값이 설정되어있다면 설정된 수만큼의 라인이 그려집니다.
@@ -257,8 +257,8 @@ public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
| 속성 | 값 | 기본값 | 미리보기 |
| ----------------------------------------------- | --------- | ----- | ---------------------------------- |
| 마지막 라인의 **퍼센트** 를 지정 할 수 있습니다. | `0...100` | `70%` | ![](Assets/multiline_lastline.png) |
| 라인의 **Corner radius** 를 지정할 수 있습니다. (**새로운기능**) | `0...10` | `0` | ![](Assets/multiline_corner.png) |
| 마지막 라인의 **퍼센트** 를 지정 할 수 있습니다. | `0...100` | `70%` | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_lastline.png) |
| 라인의 **Corner radius** 를 지정할 수 있습니다. (**새로운기능**) | `0...10` | `0` | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_corner.png) |
@@ -270,7 +270,7 @@ descriptionTextView.linesCornerRadius = 5
혹은 **IB/Storyboard** 를 이용하실 수 있습니다:
![](Assets/multiline_customize.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_customize.png)
### 🎨 Custom colors
@@ -292,7 +292,7 @@ view.showGradientSkeleton(usingGradient: gradient) // Gradient
```UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...```
![](Assets/flatcolors.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/flatcolors.png)
###### 위 이미지는 [https://flatuicolors.com](https://flatuicolors.com) 사이트에서 발췌했습니다.
### 🦋 Appearance
@@ -360,12 +360,12 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
| 방향 | 미리보기 |
| ------------------- | ---------------------------------------------- |
| .leftRight | ![](Assets/sliding_left_to_right.gif) |
| .rightLeft | ![](Assets/sliding_right_to_left.gif) |
| .topBottom | ![](Assets/sliding_top_to_bottom.gif) |
| .bottomTop | ![](Assets/sliding_bottom_to_top.gif) |
| .topLeftBottomRight | ![](Assets/sliding_topLeft_to_bottomRight.gif) |
| .bottomRightTopLeft | ![](Assets/sliding_bottomRight_to_topLeft.gif) |
| .leftRight | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_left_to_right.gif) |
| .rightLeft | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_right_to_left.gif) |
| .topBottom | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_top_to_bottom.gif) |
| .bottomTop | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_bottom_to_top.gif) |
| .topLeftBottomRight | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_topLeft_to_bottomRight.gif) |
| .bottomRightTopLeft | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_bottomRight_to_topLeft.gif) |
> **😉 꿀팁!**
슬라이딩 애니메이션을 만들기 위한 또다른 방법이 있습니다, 아래의 코드를 참조하세요:
@@ -381,10 +381,10 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
| 설정값 | 결과 |
| ----------------------------------------- | --------------------------------------------- |
| ![](Assets/no_skeletonable.png) | ![](Assets/no_skeletonables_result.png) |
| ![](Assets/container_no_skeletonable.png) | ![](Assets/no_skeletonables_result.png) |
| ![](Assets/container_skeletonable.png) | ![](Assets/container_skeletonable_result.png) |
| ![](Assets/all_skeletonables.png) | ![](Assets/all_skeletonables_result.png) |
| ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonable.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonables_result.png) |
| ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_no_skeletonable.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonables_result.png) |
| ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_skeletonable.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_skeletonable_result.png) |
| ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/all_skeletonables.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/all_skeletonables_result.png) |
### 🔬 디버그
@@ -398,17 +398,17 @@ var skeletonDescription: String
```
skeleton은 이렇게 생겼습니다:
![](Assets/debug_description.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/debug_description.png)
그리고, 새로운 **디버그 모드**를 활성화 시킬 수 있습니다. 간단하게 `SKELETON_DEBUG` 이라는 환경 변수를 추가해 활성화 하면 됩니다.
![](Assets/debug_mode.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/debug_mode.png)
그런 이후 skeleton이 나오면 Xcode 콘솔창에서 계층 구조를 볼 수 있습니다.
<details>
<summary>예제를 확인해보세요. </summary>
<img src="Assets/hierarchy_output.png" />
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/hierarchy_output.png" />
</details>
@@ -469,7 +469,7 @@ skeleton은 이렇게 생겼습니다:
* Juanpe Catalán [![alt text][1.1]][1]
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/https://github.com/Juanpe/SkeletonView/blob/main/Assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
## 👮🏻 라이센스
@@ -1,8 +1,8 @@
![](Assets/header2.jpg)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/header2.jpg)
<p align="center">
<a href="https://github.com/Juanpe/SkeletonView/workflows/build">
<img src="https://github.com/Juanpe/SkeletonView/workflows/build/badge.svg">
<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="https://img.shields.io/badge/Swift-5-orange.svg" />
@@ -25,10 +25,10 @@
🌎 Traduções: </br>
[Original](https://github.com/Juanpe/SkeletonView) </br>
[🇨🇳](https://github.com/Juanpe/SkeletonView/blob/master/README_zh.md) [@WhatsXie](https://twitter.com/WhatsXie) </br>
[🇧🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_pt-br.md) [@brunomunizaf](https://twitter.com/brunomuniz_af) </br>
[🇰🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_ko.md) [@techinpark](https://twitter.com/techinpark) </br>
[🇫🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_fr.md) [@OmarJalil](https://github.com/OmarJalil)
[🇨🇳](https://github.com/Juanpe/SkeletonView/blob/main/README_zh.md) [@WhatsXie](https://twitter.com/WhatsXie) </br>
[🇧🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_pt-br.md) [@brunomunizaf](https://twitter.com/brunomuniz_af) </br>
[🇰🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_ko.md) [@techinpark](https://twitter.com/techinpark) </br>
[🇫🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_fr.md) [@OmarJalil](https://github.com/OmarJalil)
Hoje, quase todos os apps têm processos assíncronos, como requisições de API, processos longos, etc. E enquanto os processos estão ocorrendo, normalmente os desenvolvedores usam uma view que mostra os usuarios que algo está ocorrendo.
@@ -36,25 +36,30 @@ Hoje, quase todos os apps têm processos assíncronos, como requisições de API
Aproveite! 🙂
* [Features](#-features)
* [Requerimentos](#-supported-os--sdk-versions)
* [Projeto de exemplo](#-example)
* [Instalação](#-installation)
* [Cocoapods](#using-cocoapods)
* [Carthage](#using-carthage)
* [Como usar](#-how-to-use)
* [Coleções](#-collections)
* [Texto em várias linhas](#-multiline-text)
* [Cores customizadas](#-custom-colors)
* [Aparência](#-appearance)
* [Animaçōes customizadas](#-custom-animations)
* [Hierarquia](#-hierarchy)
* [Documentação](#-documentation)
* [Próximos passos](#-next-steps)
* [Contribuindo](#-contributing)
* [Menções](#-mentions)
* [Autor](#-author)
* [Licença](#-license)
- [🌟 Features](#-features)
- [📋 Versões do SDK e OS suportados](#-versões-do-sdk-e-os-suportados)
- [🔮 Exemplo](#-exemplo)
- [📲 Instalação](#-instalação)
- [Usando CocoaPods](#usando-cocoapods)
- [Usando Carthage](#usando-carthage)
- [🐒 Como usar](#-como-usar)
- [🌿 Coleções](#-coleções)
- [UITableView](#uitableview)
- [UICollectionView](#uicollectionview)
- [📰 Texto de várias linhas](#-texto-de-várias-linhas)
- [🎛 Customização](#-customização)
- [🎨 Cores customizadas](#-cores-customizadas)
- [Imagem capturada do site https://flatuicolors.com](#imagem-capturada-do-site-httpsflatuicolorscom)
- [🦋 Aparência](#-aparência)
- [🤓 Animações customizadas](#-animações-customizadas)
- [👨‍👧‍👦 Hierarquia](#-hierarquia)
- [📚 Documentação](#-documentação)
- [📬 Próximos passos](#-próximos-passos)
- [❤️ Contribuindo](#-contribuindo)
- [Projeto gerado com SwiftPlate](#projeto-gerado-com-swiftplate)
- [📢 Menções](#-menções)
- [👨🏻‍💻 Autor](#-autor)
- [👮🏻 Licença](#-licença)
## 🌟 Features
@@ -112,7 +117,7 @@ avatarImageView.isSkeletonable = true
```
**Usando IB/Storyboards:**
![](Assets/storyboard.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/storyboard.png)
**3.** Uma vez que você setou as views, você pode mostrar o **skeleton**. Para fazê-lo, você tem **4** escolhas:
@@ -142,16 +147,16 @@ avatarImageView.isSkeletonable = true
</tr>
<tr>
<td width="25%">
<img src="Assets/solid.png"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/solid.png"></img>
</td>
<td width="25%">
<img src="Assets/gradient.png"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/gradient.png"></img>
</td>
<td width="25%">
<img src="Assets/solid_animated.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/solid_animated.gif"></img>
</td>
<td width="25%">
<img src="Assets/gradient_animated.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/gradient_animated.gif"></img>
</td>
</tr>
</table>
@@ -221,7 +226,7 @@ O resto do processo é o mesmo da ```UITableView```
### 📰 Texto de várias linhas
![](Assets/multilines2.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multilines2.png)
Quando você usar elementos com texto, ```SkeletonView``` desenha linhas para simular o texto.
Além disso, você pode decidir quantas linhas você quer. Se ```numberOfLines``` está setado para zero (0), haverá um cálculo para saber quantas linhas são necessárias para preencher o skeleton inteiro e será desenhado. Caso contrário, se você setar para um (1) ou qualquer outro número maior que zero, só serão desenhadas aquele número de linhas.
@@ -233,8 +238,8 @@ Você pode setar algumas propriedades para elementos de várias linhas.
| Property | Values | Default | Preview
| ------- | ------- |------- | -------
| **Filling percent** of the last line. | `0...100` | `70%` | ![](Assets/multiline_lastline.png)
| **Corner radius** of lines. (**NEW**) | `0...10` | `0` | ![](Assets/multiline_corner.png)
| **Filling percent** of the last line. | `0...100` | `70%` | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_lastline.png)
| **Corner radius** of lines. (**NEW**) | `0...10` | `0` | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_corner.png)
@@ -246,7 +251,7 @@ descriptionTextView.linesCornerRadius = 5
Ou, se você preferir use **IB/Storyboard**:
![](Assets/multiline_customize.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_customize.png)
### 🎨 Cores customizadas
@@ -268,7 +273,7 @@ Além do mais, ```SkeletonView``` tem 20 cores flat 🤙🏼
```UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...```
![](Assets/flatcolors.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/flatcolors.png)
###### Imagem capturada do site [https://flatuicolors.com](https://flatuicolors.com)
### 🦋 Aparência
@@ -336,12 +341,12 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
| Direction | Preview
|------- | -------
| .leftRight | ![](Assets/sliding_left_to_right.gif)
| .rightLeft | ![](Assets/sliding_right_to_left.gif)
| .topBottom | ![](Assets/sliding_top_to_bottom.gif)
| .bottomTop | ![](Assets/sliding_bottom_to_top.gif)
| .topLeftBottomRight | ![](Assets/sliding_topLeft_to_bottomRight.gif)
| .bottomRightTopLeft | ![](Assets/sliding_bottomRight_to_topLeft.gif)
| .leftRight | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_left_to_right.gif)
| .rightLeft | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_right_to_left.gif)
| .topBottom | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_top_to_bottom.gif)
| .bottomTop | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_bottom_to_top.gif)
| .topLeftBottomRight | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_topLeft_to_bottomRight.gif)
| .bottomRightTopLeft | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_bottomRight_to_topLeft.gif)
> **😉 TRUQUE!**
Existe outra forma de criar sliding animations, apenas usando este atalho:
@@ -357,10 +362,10 @@ Porque uma imagem vale mais que mil palavras:
| Configuration | Result
|------- | -------
|![](Assets/no_skeletonable.png) | ![](Assets/no_skeletonables_result.png)
|![](Assets/container_no_skeletonable.png) | ![](Assets/no_skeletonables_result.png)
|![](Assets/container_skeletonable.png) | ![](Assets/container_skeletonable_result.png)
|![](Assets/all_skeletonables.png) | ![](Assets/all_skeletonables_result.png)
|![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonable.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonables_result.png)
|![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_no_skeletonable.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonables_result.png)
|![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_skeletonable.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_skeletonable_result.png)
|![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/all_skeletonables.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/all_skeletonables_result.png)
@@ -412,7 +417,7 @@ Ver [todos os contribuidores](https://github.com/Juanpe/SkeletonView/graphs/cont
* Juanpe Catalán [![alt text][1.1]][1]
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/https://github.com/Juanpe/SkeletonView/blob/main/Assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
## 👮🏻 Licença
+51 -46
View File
@@ -1,8 +1,8 @@
![](Assets/header2.jpg)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/header2.jpg)
<p align="center">
<a href="https://github.com/Juanpe/SkeletonView/workflows/build">
<img src="https://github.com/Juanpe/SkeletonView/workflows/build/badge.svg">
<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="https://img.shields.io/badge/Swift-5-orange.svg" />
@@ -25,10 +25,10 @@
🌎 翻译: [ [原版的](https://github.com/Juanpe/SkeletonView) ] </br>
[Original](https://github.com/Juanpe/SkeletonView) </br>
[🇨🇳](https://github.com/Juanpe/SkeletonView/blob/master/README_zh.md) [@WhatsXie](https://twitter.com/WhatsXie) </br>
[🇧🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_pt-br.md) [@brunomunizaf](https://twitter.com/brunomuniz_af) </br>
[🇰🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_ko.md) [@techinpark](https://twitter.com/techinpark) </br>
[🇫🇷](https://github.com/Juanpe/SkeletonView/blob/master/README_fr.md) [@OmarJalil](https://github.com/OmarJalil)
[🇨🇳](https://github.com/Juanpe/SkeletonView/blob/main/README_zh.md) [@WhatsXie](https://twitter.com/WhatsXie) </br>
[🇧🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_pt-br.md) [@brunomunizaf](https://twitter.com/brunomuniz_af) </br>
[🇰🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_ko.md) [@techinpark](https://twitter.com/techinpark) </br>
[🇫🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_fr.md) [@OmarJalil](https://github.com/OmarJalil)
今天,几乎所有的应用程序都有异步流程,例如:Api请求、长时间运行的流程等。虽然流程正在运行,但通常开发人员会设置一个加载视图来向用户显示正在发生的事情。
@@ -36,24 +36,29 @@
好好享受! 🙂
* [特征](#-特征)
* [版本要求](#-版本要求)
* [示例项目](#-示例)
* [安装](#-安装)
* [Cocoapods](#使用-cocoapods)
* [Carthage](#使用-carthage)
* [如何使用](#-如何使用)
* [集合](#-集合)
* [多行文字](#-多行文字)
* [自定义颜色](#-自定义颜色)
* [自定义动画](#-自定义动画)
* [等级制度](#-等级制度)
* [文档](#-文档)
* [下一步](#-下一步)
* [特约](#-特约)
* [提及](#-提及)
* [作者](#-作者)
* [许可证](#-许可证)
- [🌟 特征](#-特征)
- [📋 版本要求](#-版本要求)
- [🔮 示例](#-示例)
- [📲 安装](#-安装)
- [使用 CocoaPods](#使用-cocoapods)
- [使用 Carthage](#使用-carthage)
- [🐒 如何使用](#-如何使用)
- [🌿 集合](#-集合)
- [UITableView](#uitableview)
- [UICollectionView](#uicollectionview)
- [📰 多行文字](#-多行文字)
- [🎛 定制](#-定制)
- [🎨 自定义颜色](#-自定义颜色)
- [从网站 https://flatuicolors.com捕获的图像](#从网站-httpsflatuicolorscom捕获的图像)
- [🤓 自定义动画](#-自定义动画)
- [👨‍👧‍👦 等级制度](#-等级制度)
- [📚 文档](#-文档)
- [📬 下一步](#-下一步)
- [❤️ 特约](#-特约)
- [使用 SwiftPlate 生成的项目](#使用-swiftplate-生成的项目)
- [📢 提及](#-提及)
- [👨🏻‍💻 作者](#-作者)
- [👮🏻 许可证](#-许可证)
## 🌟 特征
@@ -111,7 +116,7 @@ avatarImageView.isSkeletonable = true
```
**使用 IB/Storyboards**
![](Assets/storyboard.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/storyboard.png)
**3.** 设置视图后,可以显示 **skeleton**. 并且您有 **4** 种效果可供选择:
@@ -141,16 +146,16 @@ avatarImageView.isSkeletonable = true
</tr>
<tr>
<td width="25%">
<img src="Assets/solid.png"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/solid.png"></img>
</td>
<td width="25%">
<img src="Assets/gradient.png"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/gradient.png"></img>
</td>
<td width="25%">
<img src="Assets/solid_animated.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/solid_animated.gif"></img>
</td>
<td width="25%">
<img src="Assets/gradient_animated.gif"></img>
<img src="https://github.com/Juanpe/SkeletonView/blob/main/Assets/gradient_animated.gif"></img>
</td>
</tr>
</table>
@@ -221,7 +226,7 @@ public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
### 📰 多行文字
![](Assets/multilines2.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multilines2.png)
使用带有文本的元素时, ```SkeletonView``` 绘制线条以模拟文本。此外,您可以决定您想要多少行。如果 ```numberOfLines``` 设置为零,它将计算填充整个骨架所需的行数,并将绘制它。相反,如果将其设置为一,二或任何大于零的数字,它将只绘制此行数。
@@ -232,8 +237,8 @@ public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
| 属性 | 值范围 | 默认 | 延时
| ------- | ------- |------- | -------
| **Filling percent** 最后一行的长度百分比 | `0...100` | `70%` | ![](Assets/multiline_lastline.png)
| **Corner radius** 条目圆角半径. (**新**) | `0...10` | `0` | ![](Assets/multiline_corner.png)
| **Filling percent** 最后一行的长度百分比 | `0...100` | `70%` | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_lastline.png)
| **Corner radius** 条目圆角半径. (**新**) | `0...10` | `0` | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_corner.png)
@@ -246,7 +251,7 @@ descriptionTextView.linesCornerRadius = 5
或者,如果您更喜欢使用 **IB/Storyboard**:
![](Assets/multiline_customize.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/multiline_customize.png)
### 🎨 自定义颜色
@@ -268,7 +273,7 @@ view.showGradientSkeleton(usingGradient: gradient) // 梯度效果
```UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...```
![](Assets/flatcolors.png)
![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/flatcolors.png)
###### 从网站 [https://flatuicolors.com](https://flatuicolors.com)捕获的图像
### 🤓 自定义动画
@@ -311,12 +316,12 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
| 方向 | 效果
|------- | -------
| .leftRight | ![](Assets/sliding_left_to_right.gif)
| .rightLeft | ![](Assets/sliding_right_to_left.gif)
| .topBottom | ![](Assets/sliding_top_to_bottom.gif)
| .bottomTop | ![](Assets/sliding_bottom_to_top.gif)
| .topLeftBottomRight | ![](Assets/sliding_topLeft_to_bottomRight.gif)
| .bottomRightTopLeft | ![](Assets/sliding_bottomRight_to_topLeft.gif)
| .leftRight | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_left_to_right.gif)
| .rightLeft | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_right_to_left.gif)
| .topBottom | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_top_to_bottom.gif)
| .bottomTop | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_bottom_to_top.gif)
| .topLeftBottomRight | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_topLeft_to_bottomRight.gif)
| .bottomRightTopLeft | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/sliding_bottomRight_to_topLeft.gif)
> **😉 技巧!**
存在另一种创建滑动动画的方法,只需使用此快捷方式:
@@ -332,10 +337,10 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
| 分组 | 结果
|------- | -------
|![](Assets/no_skeletonable.png) | ![](Assets/no_skeletonables_result.png)
|![](Assets/container_no_skeletonable.png) | ![](Assets/no_skeletonables_result.png)
|![](Assets/container_skeletonable.png) | ![](Assets/container_skeletonable_result.png)
|![](Assets/all_skeletonables.png) | ![](Assets/all_skeletonables_result.png)
|![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonable.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonables_result.png)
|![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_no_skeletonable.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/no_skeletonables_result.png)
|![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_skeletonable.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/container_skeletonable_result.png)
|![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/all_skeletonables.png) | ![](https://github.com/Juanpe/SkeletonView/blob/main/Assets/all_skeletonables_result.png)
@@ -387,7 +392,7 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
* Juanpe Catalán [![alt text][1.1]][1]
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/CDou4xtIK"><img src="https://www.buymeacoffee.com/https://github.com/Juanpe/SkeletonView/blob/main/Assets/img/custom_images/orange_img.png" alt="Buy me a coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;"><span style="margin-left:5px"></span></a>
## 👮🏻 许可证
-13
View File
@@ -1,13 +0,0 @@
default_platform(:ios)
podspec_name = "SkeletonView.podspec"
lane :release_current do
version = version_get_podspec(path: @podspec_name)
if git_tag_exists(tag: version)
UI.user_error!("The tag #{version} already exists on the repo. To release a new version of the library bump the version on #{@podspec_name}")
end
pod_lib_lint
add_git_tag(tag: "#{version}")
push_git_tags
pod_push
end
+6 -1
View File
@@ -12,9 +12,14 @@ Install _fastlane_ using
```
[sudo] gem install fastlane -NV
```
or alternatively using `brew cask install fastlane`
or alternatively using `brew install fastlane`
# Available Actions
### bump_version
```
fastlane bump_version
```
### release_current
```
fastlane release_current