Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a2cc5d51d | |||
| c50547ef5f | |||
| 0a7f80e6d0 | |||
| 29f0726397 | |||
| 6db57ee5fb | |||
| 709dec5fa0 | |||
| 3796d96039 | |||
| fab5e2e36b | |||
| a6a6dc2440 | |||
| 58e9ace96d | |||
| 030da2437c | |||
| 95b1b7d512 | |||
| 2060d1a4a5 | |||
| 4874e7c95c | |||
| f42ce31a7d | |||
| 805d3bc12a | |||
| a8c61c8ed2 | |||
| 90bb2cb22a | |||
| 8fddc20ed3 | |||
| a7137ac29d | |||
| a72acbae5b | |||
| bb5bdf2d0d | |||
| beeb303db8 | |||
| 4ea81526b6 | |||
| 3b8c0114de | |||
| e1a74ad0b8 | |||
| 39d7af9980 | |||
| 796702671b | |||
| df5fbb4faa | |||
| 072f085da4 | |||
| 88521db1a1 | |||
| ffac0dd0e4 | |||
| d8ccc8ec7a | |||
| 3dcfebda82 | |||
| e2afb6aba7 | |||
| b267a2c675 | |||
| ced07a1ca1 | |||
| 8d09e6646a | |||
| 7d710bbd74 | |||
| 4970073190 | |||
| 4ecfa226b6 | |||
| a256001f61 | |||
| 8b3b8c1d71 | |||
| 4e605d2fd4 | |||
| 6feffdb41b | |||
| 0adc9683ee | |||
| 0521be6d6e | |||
| 4167579d8a | |||
| 1bd4d3d960 | |||
| b79219ac88 | |||
| 39ad7aa264 | |||
| 997c62b7d1 | |||
| d4aa1743e6 | |||
| 770be4fc06 | |||
| cdd30bd623 | |||
| 0c500a943c | |||
| 8258b73b35 | |||
| 3d9e9063c5 | |||
| b443dcc17c | |||
| 13b07d9edd | |||
| 5a27b37e81 |
+36
-14
@@ -1,25 +1,47 @@
|
||||
⚠️ Please fill out this template when filing an issue.
|
||||
### Description
|
||||
|
||||
#### 🙏🏼 *Please check if it already exists other issue related with yours.*
|
||||
Describe your issue here.
|
||||
|
||||
### What did you do?
|
||||
### What type of issue is this? (place an `x` in one of the `[ ]`)
|
||||
- [ ] bug
|
||||
- [ ] enhancement (feature request)
|
||||
- [ ] question
|
||||
- [ ] documentation related
|
||||
- [ ] discussion
|
||||
|
||||
*Please replace this with what you did.*
|
||||
### 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 searched for any related issues and avoided creating a duplicate issue.
|
||||
|
||||
### What did you expect to happen?
|
||||
---
|
||||
|
||||
*Please replace this with what you expected to happen.*
|
||||
### Bug Report
|
||||
|
||||
### What happened instead?
|
||||
Filling out the following details about bugs will help us solve your issue sooner.
|
||||
|
||||
*Please replace this with of what happened instead.*
|
||||
|
||||
### Steps to reproduce the behavior
|
||||
|
||||
*Please replace this with the steps to reproduce the behavior.*
|
||||
|
||||
### SkeletonView Environment
|
||||
### SkeletonView Environment:
|
||||
|
||||
**SkeletonView version:**
|
||||
**Xcode version:**
|
||||
**Swift version:**
|
||||
|
||||
#### Steps to reproduce:
|
||||
|
||||
*Please replace this with the steps to reproduce the behavior.*
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
#### Expected result:
|
||||
|
||||
*Please replace this with what you expected to happen.*
|
||||
|
||||
#### Actual result:
|
||||
|
||||
*Please replace this with of what happened instead.*
|
||||
|
||||
#### Attachments:
|
||||
|
||||
Logs, screenshots, sample project, funny gif, etc.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
### Summary
|
||||
|
||||
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).
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
daysUntilStale: 20
|
||||
daysUntilStale: 7
|
||||
daysUntilClose: 7
|
||||
onlyLabels:
|
||||
- awaiting user input
|
||||
|
||||
@@ -6,8 +6,10 @@ jobs:
|
||||
danger:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v1
|
||||
- name: Execute danger
|
||||
uses: danger/swift@2.0.3
|
||||
uses: danger/swift@3.3.0
|
||||
with:
|
||||
args: --failOnErrors --no-publish-check
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
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
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
included:
|
||||
- Sources
|
||||
disabled_rules:
|
||||
- trailing_whitespace
|
||||
- line_length
|
||||
- type_body_length
|
||||
- identifier_name
|
||||
- multiple_closures_with_trailing_closure
|
||||
- class_delegate_protocol
|
||||
opt_in_rules:
|
||||
- multiline_arguments
|
||||
- multiline_parameters
|
||||
- closure_spacing
|
||||
- closure_end_indentation
|
||||
- closure_body_length
|
||||
- collection_alignment
|
||||
- contains_over_filter_is_empty
|
||||
- contains_over_filter_count
|
||||
- contains_over_first_not_nil
|
||||
- contains_over_range_nil_comparison
|
||||
- convenience_type
|
||||
- discouraged_object_literal
|
||||
- discouraged_optional_boolean
|
||||
- empty_count
|
||||
- empty_string
|
||||
- fallthrough
|
||||
- file_name_no_space
|
||||
- first_where
|
||||
- flatmap_over_map_reduce
|
||||
- force_unwrapping
|
||||
- function_default_parameter_at_end
|
||||
- implicitly_unwrapped_optional
|
||||
- joined_default_parameter
|
||||
- last_where
|
||||
- literal_expression_end_indentation
|
||||
- multiline_function_chains
|
||||
- operator_usage_whitespace
|
||||
- private_action
|
||||
- private_outlet
|
||||
- redundant_optional_initialization
|
||||
- redundant_set_access_control
|
||||
- redundant_type_annotation
|
||||
- sorted_first_last
|
||||
- switch_case_on_newline
|
||||
- unneeded_parentheses_in_closure_argument
|
||||
- unowned_variable_capture
|
||||
- unused_declaration
|
||||
- unused_import
|
||||
- vertical_whitespace_opening_braces
|
||||
- discouraged_optional_collection
|
||||
- enum_case_associated_values_counts
|
||||
- legacy_multiple
|
||||
- legacy_random
|
||||
force_cast: error
|
||||
force_unwrapping: error
|
||||
indentation: 2
|
||||
file_length:
|
||||
- 2500
|
||||
- 3000
|
||||
large_tuple:
|
||||
- 5
|
||||
- 6
|
||||
+33
-22
@@ -3,7 +3,18 @@ All notable changes to this project will be documented in this file
|
||||
|
||||
### Next version
|
||||
|
||||
### 📦 [1.8.8](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.8)
|
||||
#### 🙌 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)
|
||||
|
||||
## 📦 [1.9](https://github.com/Juanpe/SkeletonView/releases/tag/1.9)
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
* [**319**](https://github.com/Juanpe/SkeletonView/pull/319): Fix to consider the top and bottom edge insets when updating the skeleton layer height - [@xpereta](https://github.com/xpereta)
|
||||
* [**320**](https://github.com/Juanpe/SkeletonView/pull/320): Fix Single line customisation - [@Juanpe](https://github.com/juanpe)
|
||||
* [**323**](https://github.com/Juanpe/SkeletonView/pull/323): Save and restore view state for UIButton - [@Juanpe](https://github.com/juanpe)
|
||||
|
||||
## 📦 [1.8.8](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.8)
|
||||
|
||||
#### 🙌 New
|
||||
* [**304**](https://github.com/Juanpe/SkeletonView/pull/304): French README 🇫🇷 - [@OmarJalil](https://github.com/OmarJalil)
|
||||
@@ -17,7 +28,7 @@ All notable changes to this project will be documented in this file
|
||||
* [**308**](https://github.com/Juanpe/SkeletonView/pull/308): Fix example backgroundColor in DarkMode - [@toshi0383](https://github.com/toshi0383)
|
||||
* [**307**](https://github.com/Juanpe/SkeletonView/pull/307): Prevent incorrect skeletonLayer to be added when updating skeleton - [@wsalim1610](https://github.com/wsalim1610)
|
||||
|
||||
### 📦 [1.8.7](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.7)
|
||||
## 📦 [1.8.7](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.7)
|
||||
|
||||
#### 🔬Improvements
|
||||
* [**271**](https://github.com/Juanpe/SkeletonView/pull/271): Add corner radius for skeletonView as IBInspectable (CGFloat) default is 0.0 - [@paulanatoleclaudot-betclic](https://github.com/paulanatoleclaudot-betclic)
|
||||
@@ -27,7 +38,7 @@ All notable changes to this project will be documented in this file
|
||||
* [**274**](https://github.com/Juanpe/SkeletonView/pull/274): Fix: hiding skeleton when header and footer views of section would not hide it - [@darkside999](https://github.com/darkside999)
|
||||
* [**273**](https://github.com/Juanpe/SkeletonView/pull/273): Fix: in vertical stack view with center alignment show incorrect position - [@koooootake](https://github.com/koooootake)
|
||||
|
||||
### 📦 [1.8.6](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.6)
|
||||
## 📦 [1.8.6](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.6)
|
||||
|
||||
#### 🔬Improvements
|
||||
* [**242**](https://github.com/Juanpe/SkeletonView/pull/242): Offscreen table view layout issue fixed - [@Cacodemon](https://github.com/Cacodemon)
|
||||
@@ -41,16 +52,16 @@ All notable changes to this project will be documented in this file
|
||||
* [**257**](https://github.com/Juanpe/SkeletonView/issues/257): Unit test problem when using SkeletonView
|
||||
|
||||
|
||||
### 📦 [1.8.3](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.3)
|
||||
## 📦 [1.8.3](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.3)
|
||||
|
||||
- Support for iOS 13 dark mode. (thanks @Wilsonator5000)
|
||||
|
||||
### 📦 [1.8.2](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.2)
|
||||
## 📦 [1.8.2](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.2)
|
||||
|
||||
#### 🙌 New
|
||||
- Add ability to customize line spacing per label. (thanks @gshahbazian)
|
||||
|
||||
### 📦 [LayoutSkeleton (1.8.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.1)
|
||||
## 📦 [LayoutSkeleton (1.8.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.8.1)
|
||||
|
||||
#### 🔬Improvements
|
||||
- Fix completion call in .none transition style while hide skeletons. (thanks @aadudyrev)
|
||||
@@ -66,7 +77,7 @@ All notable changes to this project will be documented in this file
|
||||
- Update layout subviews when the original method is called.
|
||||
- Issues: [#88, #149]
|
||||
|
||||
### 📦 [Transitions (1.8)](https://github.com/Juanpe/SkeletonView/releases/tag/1.8)
|
||||
## 📦 [Transitions (1.8)](https://github.com/Juanpe/SkeletonView/releases/tag/1.8)
|
||||
|
||||
#### 🙌 New
|
||||
|
||||
@@ -80,7 +91,7 @@ All notable changes to this project will be documented in this file
|
||||
- Solved issues.
|
||||
[#175](https://github.com/Juanpe/SkeletonView/issues/175) Swift Package Manager version format
|
||||
|
||||
### 📦 [Layout update (1.7)](https://github.com/Juanpe/SkeletonView/releases/tag/1.7)
|
||||
## 📦 [Layout update (1.7)](https://github.com/Juanpe/SkeletonView/releases/tag/1.7)
|
||||
|
||||
#### 🙌 New
|
||||
|
||||
@@ -90,7 +101,7 @@ All notable changes to this project will be documented in this file
|
||||
|
||||
- Allow updating skeleton layers without recreating them: `updateSkeleton`, `updateGradientSkeleton`, `updateAnimatedSkeleton`, `updateAnimatedGradientSkeleton`. (thanks @eduardbosch)
|
||||
|
||||
### 📦 [Debug (1.4)](https://github.com/Juanpe/SkeletonView/releases/tag/1.4)
|
||||
## 📦 [Debug (1.4)](https://github.com/Juanpe/SkeletonView/releases/tag/1.4)
|
||||
|
||||
#### 🙌 New
|
||||
|
||||
@@ -104,7 +115,7 @@ All notable changes to this project will be documented in this file
|
||||
#### 🩹 Bug fixes
|
||||
- Solved issue [#86](https://github.com/Juanpe/SkeletonView/issues/86) (thanks @reececomo)
|
||||
|
||||
### 📦 [Custom defaults (1.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.3)
|
||||
## 📦 [Custom defaults (1.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.3)
|
||||
|
||||
#### 🙌 New
|
||||
|
||||
@@ -114,7 +125,7 @@ All notable changes to this project will be documented in this file
|
||||
#### 🩹 Bug fixes
|
||||
- Solved issue [#41](https://github.com/Juanpe/SkeletonView/issues/41). Now, Skeleton works if UICollectionView cell's Nib is registered in code. (thanks @kjoneandrei)
|
||||
|
||||
### 📦 [Typo (1.2.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.2.3)
|
||||
## 📦 [Typo (1.2.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.2.3)
|
||||
|
||||
#### Fixes
|
||||
|
||||
@@ -124,7 +135,7 @@ All notable changes to this project will be documented in this file
|
||||
|
||||
- Now it takes in account the `UIStackView` to calculate the `SkeletonLayer` bounds (thanks @giantramen)
|
||||
|
||||
### 📦 [New face (1.2.2)](https://github.com/Juanpe/SkeletonView/releases/tag/1.2.2)
|
||||
## 📦 [New face (1.2.2)](https://github.com/Juanpe/SkeletonView/releases/tag/1.2.2)
|
||||
|
||||
#### 🙌 New
|
||||
|
||||
@@ -133,7 +144,7 @@ All notable changes to this project will be documented in this file
|
||||
#### 🩹 Bug fixes
|
||||
- Solved issue [#23](https://github.com/Juanpe/SkeletonView/issues/23). Problem with UIStackView. (thanks @giantramen)
|
||||
|
||||
### 📦 [State (1.2.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.2.1)
|
||||
## 📦 [State (1.2.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.2.1)
|
||||
|
||||
#### 🙌 New
|
||||
|
||||
@@ -143,7 +154,7 @@ All notable changes to this project will be documented in this file
|
||||
#### 🩹 Bug fixes
|
||||
- Solved issue [#51](https://github.com/Juanpe/SkeletonView/issues/51). Support inspectable properties when using Carthage. (thanks @eduardbosch)
|
||||
|
||||
### 📦 [On TV (1.2)](https://github.com/Juanpe/SkeletonView/releases/tag/1.2)
|
||||
## 📦 [On TV (1.2)](https://github.com/Juanpe/SkeletonView/releases/tag/1.2)
|
||||
|
||||
#### 🙌 New
|
||||
- Now ```SkeletonView``` is **tvOS** compatible! 🎉. (thanks @mihai8804858)
|
||||
@@ -152,12 +163,12 @@ All notable changes to this project will be documented in this file
|
||||
- Solved issue [#46](https://github.com/Juanpe/SkeletonView/issues/46). It crashes the application when tap on it, didSelect called and crash.
|
||||
|
||||
|
||||
### 📦 [Hotfix (1.1.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.1.1)
|
||||
## 📦 [Hotfix (1.1.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.1.1)
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
- Now yes, solved issue [#39](https://github.com/Juanpe/SkeletonView/issues/39)
|
||||
|
||||
### 📦 [Needed (1.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.1)
|
||||
## 📦 [Needed (1.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.1)
|
||||
|
||||
#### 🙌 New
|
||||
- Now ```SkeletonView```supports **UICollectionViews**! 🎉. (thanks @Renatdz)
|
||||
@@ -166,7 +177,7 @@ All notable changes to this project will be documented in this file
|
||||
- Solved issue [#39](https://github.com/Juanpe/SkeletonView/issues/39). Gradient animation did not work when app becomes active.
|
||||
|
||||
|
||||
### 📦 [Resizable (1.0.5)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.5)
|
||||
## 📦 [Resizable (1.0.5)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.5)
|
||||
|
||||
#### 🙌 New
|
||||
- Now you can use table views with resizable cells.
|
||||
@@ -177,7 +188,7 @@ All notable changes to this project will be documented in this file
|
||||
[#30](https://github.com/Juanpe/SkeletonView/issues/30),
|
||||
[#34](https://github.com/Juanpe/SkeletonView/issues/34).
|
||||
|
||||
### 📦 [Filled or not (1.0.4)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.4)
|
||||
## 📦 [Filled or not (1.0.4)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.4)
|
||||
|
||||
#### 🙌 New
|
||||
- You can set the filling percent of the last line in multiline elements (thanks @jontelang!)
|
||||
@@ -185,22 +196,22 @@ All notable changes to this project will be documented in this file
|
||||
#### 🩹 Bug fixes
|
||||
- Solved issue [#14](https://github.com/Juanpe/SkeletonView/issues/14). You could edit text views with skeleton active.
|
||||
|
||||
### 📦 [In all directions (1.0.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.3)
|
||||
## 📦 [In all directions (1.0.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.3)
|
||||
|
||||
#### 🙌 New
|
||||
- Create ```SkeletonAnimationBuilder```, to facilitate the creation of layer animations.
|
||||
```GradientDirection``` enum.
|
||||
|
||||
### 📦 [Retro (1.0.2)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.2)
|
||||
## 📦 [Retro (1.0.2)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.2)
|
||||
|
||||
#### 🙌 New
|
||||
- Change some private keywords, to be Swift 3 compatible
|
||||
|
||||
### 📦 [Early bird bug (1.0.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.2)
|
||||
## 📦 [Early bird bug (1.0.1)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0.2)
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
- It was not removing the skeleton layer
|
||||
|
||||
### 📦 [Starter (1.0)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0)
|
||||
## 📦 [Starter (1.0)](https://github.com/Juanpe/SkeletonView/releases/tag/1.0)
|
||||
|
||||
- First release
|
||||
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
# Code of Conduct
|
||||
|
||||
The Code of Conduct governs how we behave in public or in private
|
||||
whenever the project will be judged by our actions.
|
||||
We expect it to be honored by everyone who represents the project
|
||||
officially or informally,
|
||||
claims affiliation with the project,
|
||||
or participates directly.
|
||||
|
||||
We strive to:
|
||||
|
||||
* **Be open**: We invite anybody to participate in any aspect of our projects.
|
||||
Our community is open, and any responsibility can be carried
|
||||
by any contributor who demonstrates the required capacity and competence.
|
||||
* **Be empathetic**: We work together to resolve conflict,
|
||||
assume good intentions,
|
||||
and do our best to act in an empathic fashion.
|
||||
By understanding that humanity drops a few packets in online interactions,
|
||||
and adjusting accordingly,
|
||||
we can create a comfortable environment for everyone to share their ideas.
|
||||
* **Be collaborative**: We prefer to work transparently
|
||||
and to involve interested parties early on in the process.
|
||||
Wherever possible, we work closely with others in the open source community
|
||||
to coordinate our efforts.
|
||||
* **Be decisive**: We expect participants in the project to resolve disagreements constructively.
|
||||
When they cannot, we escalate the matter to structures
|
||||
with designated leaders to arbitrate and provide clarity and direction.
|
||||
* **Be responsible**: We hold ourselves accountable for our actions.
|
||||
When we make mistakes, we take responsibility for them.
|
||||
When we need help, we reach out to others.
|
||||
When it comes time to move on from a project,
|
||||
we take the proper steps to ensure that others can pick up where we left off.
|
||||
|
||||
This code is not exhaustive or complete.
|
||||
It serves to distill our common understanding of a
|
||||
collaborative, shared environment and goals.
|
||||
We expect it to be followed in spirit as much as in the letter.
|
||||
|
||||
---
|
||||
|
||||
The **SkeletonView** Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
# 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
|
||||
well.
|
||||
|
||||
There are many ways you can contribute! :heart:
|
||||
|
||||
### Bug Reports and Fixes :bug:
|
||||
- If you find a bug, please search for it in the [Issues](https://github.com/Juanpe/SkeletonView/issues), and if it isn't already tracked,
|
||||
[create a new issue](https://github.com/slackhq/PanModal/issues/new). Fill out the "Bug Report" section of the issue template. Even if an Issue is closed, feel free to comment and add details, it will still
|
||||
be reviewed.
|
||||
- Issues that have already been identified as a bug (note: able to reproduce) will be labelled `🐞 Bug`.
|
||||
- If you'd like to submit a fix for a bug, [send a Pull Request](#creating_a_pull_request) and mention the Issue number.
|
||||
|
||||
### New Features :bulb:
|
||||
- If you'd like to add new functionality to this project, describe the problem you want to solve in a [new Issue](https://github.com/Juanpe/SkeletonView/issues/new).
|
||||
- Issues that have been identified as a feature request will be labelled `💡 Enhancement`.
|
||||
- If you'd like to implement the new feature, please wait for feedback from the project
|
||||
maintainers before spending too much time writing the code. In some cases, `💡 Enhancement`s may
|
||||
not align well with the project objectives at the time.
|
||||
|
||||
### Miscellaneous :sparkles:
|
||||
- If you have an alternative implementation of something that may have advantages over the way its currently
|
||||
done, or you have any other change, we would be happy to hear about it!
|
||||
- If its a trivial change, go ahead and [send a Pull Request](#creating_a_pull_request) with the changes you have in mind.
|
||||
- If not, [open an Issue](https://github.com/Juanpe/SkeletonView/issues/new) to discuss the idea first.
|
||||
|
||||
If you're new to our project and looking for some way to make your first contribution, look for
|
||||
Issues labelled `good first issue`.
|
||||
|
||||
## Requirements
|
||||
|
||||
For your contribution to be accepted:
|
||||
|
||||
- [x] The changes must be approved by code review.
|
||||
- [x] Commits should be atomic and messages must be descriptive. Related issues should be mentioned by Issue number.
|
||||
|
||||
If the contribution doesn't meet the above criteria, you may fail our automated checks or a maintainer will discuss it with you. You can continue to improve a Pull Request by adding commits to the branch from which the PR was created.
|
||||
|
||||
## Creating a Pull Request
|
||||
|
||||
1. :fork_and_knife: Fork the repository on GitHub.
|
||||
2. :runner: Clone/fetch your fork to your local development machine.
|
||||
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
|
||||
repository.
|
||||
|
||||
## Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
- (a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
- (b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
- (c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
- (d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
|
||||
*Wording of statement copied from [elinux.org](http://elinux.org/Developer_Certificate_Of_Origin)*
|
||||
+1
-1
@@ -10,7 +10,7 @@ let sourceChanges = allSourceFiles.contains { $0.hasPrefix("Sources") }
|
||||
let isNotTrivial = !danger.github.pullRequest.title.contains("#trivial")
|
||||
|
||||
if isNotTrivial && noChangelogEntry && sourceChanges {
|
||||
warn("Any changes to library code should be reflected in the Changelog.")
|
||||
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
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Va7-1y-Tel">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="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="15510"/>
|
||||
<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>
|
||||
@@ -39,7 +39,7 @@
|
||||
</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="141" y="20" width="93" height="93"/>
|
||||
<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"/>
|
||||
@@ -49,13 +49,28 @@
|
||||
<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="nMj-pU-5wJ" firstAttribute="centerX" secondItem="F9K-jU-100" secondAttribute="centerX" id="9X4-2r-AKx"/>
|
||||
<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"/>
|
||||
|
||||
@@ -8,106 +8,93 @@
|
||||
<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>
|
||||
<br/>
|
||||
<a href="https://twitter.com/JuanpeCatalan">
|
||||
<img src="https://img.shields.io/badge/contact-@JuanpeCatalan-blue.svg?style=flat" alt="Twitter: @JuanpeCatalan" />
|
||||
</a>
|
||||
<a href="https://twitter.com/intent/tweet?text=Wow%20This%20library%20is%20awesome:&url=https%3A%2F%2Fgithub.com%2FJuanpe%2FSkeletonView">
|
||||
<img src="https://img.shields.io/twitter/url/https/github.com/Juanpe/SkeletonView.svg?style=social" alt="License" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<p align="center">
|
||||
<a href="#-features">Features</a>
|
||||
• <a href="#-guides">Guides</a>
|
||||
• <a href="#-installation">Installation</a>
|
||||
• <a href="#-usage">Usage</a>
|
||||
• <a href="#-miscellaneous">Miscellaneous</a>
|
||||
• <a href="#️-contributing">Contributing</a>
|
||||
</p>
|
||||
|
||||
**🌎 README is available in other languages: [🇨🇳](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/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)**
|
||||
|
||||
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.
|
||||
|
||||
```SkeletonView``` has been conceived to address this need, an elegant way to show users that something is happening and also prepare them for which contents are waiting.
|
||||
**SkeletonView** has been conceived to address this need, an elegant way to show users that something is happening and also prepare them for which contents are waiting.
|
||||
|
||||
Enjoy it! 🙂
|
||||
|
||||
* [Features](#-features)
|
||||
* [Guides](#-guides)
|
||||
* [Installation](#-installation)
|
||||
* [Cocoapods](#using-cocoapods)
|
||||
* [Carthage](#using-carthage)
|
||||
* [SPM](#using-swift-package-manager)
|
||||
* [How to use](#-how-to-use)
|
||||
* [Collections](#-collections)
|
||||
* [Multiline text](#-multiline-text)
|
||||
* [Custom colors](#-custom-colors)
|
||||
* [Appearance](#-appearance)
|
||||
* [Custom animations](#-custom-animations)
|
||||
* [Transitions](#-transitions)
|
||||
* [Hierarchy](#-hierarchy)
|
||||
* [Debug](#-debug)
|
||||
* [Documentation](#-documentation)
|
||||
* [Supported OS & SDK Versions](#-supported-os--sdk-versions)
|
||||
* [Next steps](#-next-steps)
|
||||
* [Contributing](#%EF%B8%8F-contributing)
|
||||
* [Mentions](#-mentions)
|
||||
* [Author](#-author)
|
||||
* [License](#-license)
|
||||
|
||||
##
|
||||
- [🌟 Features](#-features)
|
||||
- [🎬 Guides](#-guides)
|
||||
- [📲 Installation](#-installation)
|
||||
- [🐒 Usage](#-usage)
|
||||
- [🌿 Collections](#-collections)
|
||||
- [🔠 Texts](#-texts)
|
||||
- [🦋 Appearance](#-appearance)
|
||||
- [🎨 Custom colors](#-custom-colors)
|
||||
- [ 🏃♀️ Animations](#%EF%B8%8F-animations)
|
||||
- [🏄 Transitions](#-transitions)
|
||||
- [✨ Miscellaneous](#-miscellaneous)
|
||||
- [❤️ Contributing](#️-contributing)
|
||||
|
||||
|
||||
|
||||
## 🌟 Features
|
||||
|
||||
- [x] Easy to use
|
||||
- [x] All UIViews are skeletonables
|
||||
- [x] Fully customizable
|
||||
- [x] Universal (iPhone & iPad)
|
||||
- [x] Interface Builder friendly
|
||||
- [x] Simple Swift syntax
|
||||
- [x] Lightweight readable codebase
|
||||
* Easy to use
|
||||
* All UIViews are skeletonables
|
||||
* Fully customizable
|
||||
* Universal (iPhone & iPad)
|
||||
* Interface Builder friendly
|
||||
* Simple Swift syntax
|
||||
* Lightweight readable codebase
|
||||
|
||||
|
||||
## 🎬 Guides
|
||||
|
||||
| [](https://youtu.be/75kgOhWsPNA)|[](https://youtu.be/MVCiM_VdxVA)|[](https://youtu.be/Qq3Evspeea8)|[](https://youtu.be/ZOoPtBwDRT0)
|
||||
|:---: | :---: |:---: | :---:
|
||||
|[**SkeletonView Guides - Getting started**](https://youtu.be/75kgOhWsPNA)|[**How to Create Loading View with Skeleton View in Swift 5.2**](https://youtu.be/MVCiM_VdxVA) <br/> by iKh4ever Studio|[**Create Skeleton Loading View in App (Swift 5) - Xcode 11, 2020**](https://youtu.be/Qq3Evspeea8) <br/> by iOS Academy| [**Add An Elegant Loading Animation in Swift***](https://youtu.be/ZOoPtBwDRT0) <br/> by Gary Tokman
|
||||
| [](https://youtu.be/75kgOhWsPNA)|[](https://youtu.be/MVCiM_VdxVA)|[](https://youtu.be/Qq3Evspeea8)|[](https://youtu.be/ZOoPtBwDRT0)|[](https://www.youtube.com/watch?v=Zx1Pg1gPfxA)
|
||||
|:---: | :---: |:---: | :---: | :---:
|
||||
|[**SkeletonView Guides - Getting started**](https://youtu.be/75kgOhWsPNA)|[**How to Create Loading View with Skeleton View in Swift 5.2**](https://youtu.be/MVCiM_VdxVA) by iKh4ever Studio|[**Create Skeleton Loading View in App (Swift 5) - Xcode 11, 2020**](https://youtu.be/Qq3Evspeea8) by iOS Academy| [**Add An Elegant Loading Animation in Swift***](https://youtu.be/ZOoPtBwDRT0) by Gary Tokman| [**Cómo crear una ANIMACIÓN de CARGA de DATOS en iOS**](https://www.youtube.com/watch?v=Zx1Pg1gPfxA) by MoureDev
|
||||
|
||||
|
||||
## 📲 Installation
|
||||
|
||||
#### Using [CocoaPods](https://cocoapods.org)
|
||||
|
||||
Edit your `Podfile` and specify the dependency:
|
||||
* [CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html):
|
||||
|
||||
```ruby
|
||||
pod "SkeletonView"
|
||||
pod 'SkeletonView'
|
||||
```
|
||||
|
||||
#### Using [Carthage](https://github.com/carthage)
|
||||
* [Carthage](https://github.com/Carthage/Carthage):
|
||||
|
||||
Edit your `Cartfile` and specify the dependency:
|
||||
|
||||
```bash
|
||||
```ruby
|
||||
github "Juanpe/SkeletonView"
|
||||
```
|
||||
|
||||
#### Using [Swift Package Manager](https://github.com/apple/swift-package-manager)
|
||||
|
||||
Once you have your Swift package set up, adding `SkeletonView` as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.
|
||||
* [Swift Package Manager](https://swift.org/package-manager/):
|
||||
|
||||
```swift
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/Juanpe/SkeletonView.git", from: "1.7.0")
|
||||
]
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/Juanpe/SkeletonView.git", from: "1.7.0")
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 🐒 How to use
|
||||
## 🐒 Usage
|
||||
|
||||
Only **3** steps needed to use `SkeletonView`:
|
||||
|
||||
**1.** Import SkeletonView in proper place.
|
||||
1️⃣ Import SkeletonView in proper place.
|
||||
```swift
|
||||
import SkeletonView
|
||||
```
|
||||
|
||||
**2.** Now, set which views will be `skeletonables`. You achieve this in two ways:
|
||||
2️⃣ Now, set which views will be `skeletonables`. You achieve this in two ways:
|
||||
|
||||
**Using code:**
|
||||
```swift
|
||||
@@ -117,7 +104,7 @@ avatarImageView.isSkeletonable = true
|
||||
|
||||

|
||||
|
||||
**3.** Once you've set the views, you can show the **skeleton**. To do so, you have **4** choices:
|
||||
3️⃣ Once you've set the views, you can show the **skeleton**. To do so, you have **4** choices:
|
||||
|
||||
```swift
|
||||
(1) view.showSkeleton() // Solid
|
||||
@@ -159,41 +146,20 @@ avatarImageView.isSkeletonable = true
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
> **IMPORTANT!**
|
||||
>>```SkeletonView``` is recursive, so if you want show the skeleton in all skeletonable views, you only need to call the show method in the main container view. For example, with UIViewControllers
|
||||
|
||||
### Extra
|
||||
> 📣 **IMPORTANT!**
|
||||
>
|
||||
> `SkeletonView` is recursive, so if you want show the skeleton in all skeletonable views, you only need to call the show method in the main container view. For example, with `UIViewControllers`.
|
||||
|
||||
#### Skeleton views layout
|
||||
|
||||
|
||||
Sometimes skeleton layout may not fit your layout because the parent view bounds have changed. ~For example, rotating the device.~
|
||||
|
||||
You can relayout the skeleton views like so:
|
||||
|
||||
```swift
|
||||
override func viewDidLayoutSubviews() {
|
||||
view.layoutSkeletonIfNeeded()
|
||||
}
|
||||
```
|
||||
|
||||
⚠️⚠️ You shouldn't call this method. From *version 1.8.1* you don't need to call this method, the library does automatically. So, you can use this method *ONLY* in the cases when you need to update the layout of the skeleton manually.
|
||||
|
||||
#### Update skeleton configuration
|
||||
|
||||
You can change the skeleton configuration at any time like its colour, animation, etc. with the following methods:
|
||||
|
||||
```swift
|
||||
(1) view.updateSkeleton() // Solid
|
||||
(2) view.updateGradientSkeleton() // Gradient
|
||||
(3) view.updateAnimatedSkeleton() // Solid animated
|
||||
(4) view.updateAnimatedGradientSkeleton() // Gradient animated
|
||||
```
|
||||
|
||||
### 🌿 Collections
|
||||
|
||||
```SkeletonView``` is compatible with ```UITableView``` and ```UICollectionView```.
|
||||
|
||||
#### UITableView
|
||||
|
||||
**UITableView**
|
||||
|
||||
If you want to show the skeleton in a ```UITableView```, you need to conform to ```SkeletonTableViewDataSource``` protocol.
|
||||
|
||||
@@ -202,8 +168,6 @@ public protocol SkeletonTableViewDataSource: UITableViewDataSource {
|
||||
func numSections(in collectionSkeletonView: UITableView) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -> ReusableHeaderFooterIdentifier?
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -> ReusableHeaderFooterIdentifier?
|
||||
}
|
||||
```
|
||||
As you can see, this protocol inherits from ```UITableViewDataSource```, so you can replace this protocol with the skeleton protocol.
|
||||
@@ -221,16 +185,6 @@ func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection s
|
||||
// It calculates how many cells need to populate whole tableview
|
||||
```
|
||||
|
||||
``` swift
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -> ReusableHeaderFooterIdentifier?
|
||||
// Default: nil
|
||||
```
|
||||
|
||||
``` swift
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -> ReusableHeaderFooterIdentifier?
|
||||
// Default: nil
|
||||
```
|
||||
|
||||
There is only one method you need to implement to let Skeleton know the cell identifier. This method doesn't have default implementation:
|
||||
``` swift
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
|
||||
@@ -242,42 +196,51 @@ There is only one method you need to implement to let Skeleton know the cell ide
|
||||
return "CellIdentifier"
|
||||
}
|
||||
```
|
||||
|
||||
Besides, you can skeletonize both the headers and footers. You need to conform to `SkeletonTableViewDelegate` protocol.
|
||||
|
||||
> **IMPORTANT!**
|
||||
> If you are using resizable cells (`tableView.rowHeight = UITableViewAutomaticDimension` ), it's mandatory define the `estimatedRowHeight`.
|
||||
```swift
|
||||
public protocol SkeletonTableViewDelegate: UITableViewDelegate {
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -> ReusableHeaderFooterIdentifier? // default: nil
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -> ReusableHeaderFooterIdentifier? // default: nil
|
||||
}
|
||||
```
|
||||
|
||||
👩🏼🏫 **How specify which elements are skeletonables?**
|
||||
> 📣 **IMPORTANT!**
|
||||
>
|
||||
> 1️⃣ If you are using resizable cells (**`tableView.rowHeight = UITableViewAutomaticDimension`**), it's mandatory define the **`estimatedRowHeight`**.
|
||||
>
|
||||
> 2️⃣ When you add elements in a **`UITableViewCell`** you should add it to **`contentView`** and not to the cell directly.
|
||||
> ```swift
|
||||
> self.contentView.addSubview(titleLabel) ✅
|
||||
> self.addSubview(titleLabel) ❌
|
||||
> ```
|
||||
|
||||
Here is an illustration that shows how you should specify which elements are skeletonables when you are using an `UITableView`:
|
||||
|
||||
|
||||

|
||||
**UICollectionView**
|
||||
|
||||
As you can see, we have to make skeletonable the tableview, the cell and the UI elements, but we don't need to set as skeletonable the `contentView`
|
||||
|
||||
#### UICollectionView
|
||||
|
||||
For ```UICollectionView```, you need to conform to ```SkeletonCollectionViewDataSource``` protocol.
|
||||
For `UICollectionView`, you need to conform to `SkeletonCollectionViewDataSource` protocol.
|
||||
|
||||
``` swift
|
||||
public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
|
||||
func numSections(in collectionSkeletonView: UICollectionView) -> Int
|
||||
func numSections(in collectionSkeletonView: UICollectionView) -> Int // default: 1
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -> ReusableCellIdentifier? // default: nil
|
||||
}
|
||||
```
|
||||
|
||||
The rest of the process is the same as ```UITableView```
|
||||
|
||||
### 📰 Multiline text
|
||||
|
||||
### 🔠 Texts
|
||||
|
||||

|
||||
|
||||
When using elements with text, ```SkeletonView``` draws lines to simulate text.
|
||||
Besides, you can decide how many lines you want. If ```numberOfLines``` is set to zero, it will calculate how many lines needed to populate the whole skeleton and it will be drawn. Instead, if you set it to one, two or any number greater than zero, it will only draw this number of lines.
|
||||
|
||||
##### 🎛 Customize
|
||||
|
||||
You can set some properties for multilines elements.
|
||||
|
||||
|
||||
@@ -298,32 +261,10 @@ Or, if you prefer use **IB/Storyboard**:
|
||||
|
||||

|
||||
|
||||
### 🎨 Custom colors
|
||||
|
||||
You can decide which color the skeleton is tinted with. You only need to pass as a parameter the color or gradient you want.
|
||||
|
||||
**Using solid colors**
|
||||
``` swift
|
||||
view.showSkeleton(usingColor: UIColor.gray) // Solid
|
||||
// or
|
||||
view.showSkeleton(usingColor: UIColor(red: 25.0, green: 30.0, blue: 255.0, alpha: 1.0))
|
||||
```
|
||||
**Using gradients**
|
||||
``` swift
|
||||
let gradient = SkeletonGradient(baseColor: UIColor.midnightBlue)
|
||||
view.showGradientSkeleton(usingGradient: gradient) // Gradient
|
||||
```
|
||||
|
||||
Besides, ```SkeletonView``` features 20 flat colors 🤙🏼
|
||||
|
||||
```UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...```
|
||||
|
||||

|
||||
###### Image captured from website [https://flatuicolors.com](https://flatuicolors.com)
|
||||
|
||||
### 🦋 Appearance
|
||||
|
||||
**NEW** The skeletons have a default appearance. So, when you don't specify the color, gradient or multilines properties, `SkeletonView` uses the default values.
|
||||
The skeletons have a default appearance. So, when you don't specify the color, gradient or multilines properties, `SkeletonView` uses the default values.
|
||||
|
||||
Default values:
|
||||
- **tintColor**: UIColor
|
||||
@@ -342,7 +283,7 @@ Default values:
|
||||
- *default: 0*
|
||||
|
||||
To get these default values you can use `SkeletonAppearance.default`. Using this property you can set the values as well:
|
||||
```Swift
|
||||
```swift
|
||||
SkeletonAppearance.default.multilineHeight = 20
|
||||
SkeletonAppearance.default.tintColor = .green
|
||||
```
|
||||
@@ -354,9 +295,33 @@ You can also specifiy these line appearance properties on a per-label basis:
|
||||
- **skeletonPaddingInsets**: UIEdgeInsets
|
||||
|
||||
|
||||
### 🤓 Custom animations
|
||||
### 🎨 Custom colors
|
||||
|
||||
```SkeletonView``` has two built-in animations, *pulse* for solid skeletons and *sliding* for gradients.
|
||||
You can decide which color the skeleton is tinted with. You only need to pass as a parameter the color or gradient you want.
|
||||
|
||||
**Using solid colors**
|
||||
```swift
|
||||
view.showSkeleton(usingColor: UIColor.gray) // Solid
|
||||
// or
|
||||
view.showSkeleton(usingColor: UIColor(red: 25.0, green: 30.0, blue: 255.0, alpha: 1.0))
|
||||
```
|
||||
**Using gradients**
|
||||
``` swift
|
||||
let gradient = SkeletonGradient(baseColor: UIColor.midnightBlue)
|
||||
view.showGradientSkeleton(usingGradient: gradient) // Gradient
|
||||
```
|
||||
|
||||
Besides, **SkeletonView** features 20 flat colors 🤙🏼
|
||||
|
||||
```UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...```
|
||||
|
||||

|
||||
###### Image captured from website [https://flatuicolors.com](https://flatuicolors.com)
|
||||
|
||||
|
||||
### 🏃♀️ Animations
|
||||
|
||||
**SkeletonView** has two built-in animations, *pulse* for solid skeletons and *sliding* for gradients.
|
||||
|
||||
Besides, if you want to do your own skeleton animation, it's really easy.
|
||||
|
||||
@@ -390,7 +355,7 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
|
||||
|
||||
```
|
||||
|
||||
```GradientDirection``` is an enum, with this cases:
|
||||
```GradientDirection``` is an enum, with theses cases:
|
||||
|
||||
| Direction | Preview
|
||||
|------- | -------
|
||||
@@ -402,14 +367,17 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
|
||||
| .bottomRightTopLeft | 
|
||||
|
||||
> **😉 TRICK!**
|
||||
Exist another way to create sliding animations, just using this shortcut:
|
||||
>>```let animation = GradientDirection.leftToRight.slidingAnimation()```
|
||||
|
||||
>
|
||||
> Exist another way to create sliding animations, just using this shortcut:
|
||||
> ```swift
|
||||
> let animation = GradientDirection.leftToRight.slidingAnimation()
|
||||
> ```
|
||||
|
||||
|
||||
|
||||
### 🏄 Transitions
|
||||
|
||||
```SkeletonView``` has build-in transitions to **show** or **hide** the skeletons in a *smoother* way 🤙
|
||||
**SkeletonView** has built-in transitions to **show** or **hide** the skeletons in a *smoother* way 🤙
|
||||
|
||||
To use the transition, simply add the ```transition``` parameter to your ```showSkeleton()``` or ```hideSkeleton()``` function with the transition time, like this:
|
||||
|
||||
@@ -443,7 +411,11 @@ The default value is `crossDissolve(0.25)`
|
||||
</table>
|
||||
|
||||
|
||||
### 👨👧👦 Hierarchy
|
||||
## ✨ Miscellaneous
|
||||
|
||||
|
||||
|
||||
**Hierarchy**
|
||||
|
||||
Since ```SkeletonView``` is recursive, and we want skeleton to be very efficient, we want to stop recursion as soon as possible. For this reason, you must set the container view as `Skeletonable`, because Skeleton will stop looking for `skeletonable` subviews as soon as a view is not Skeletonable, breaking then the recursion.
|
||||
|
||||
@@ -454,7 +426,7 @@ In this example we have a `UIViewController` with a `ContainerView` and a `UITab
|
||||
view.showSkeleton()
|
||||
```
|
||||
|
||||
> ```ìsSkeletonable```= ☠️
|
||||
> ```isSkeletonable```= ☠️
|
||||
|
||||
| Configuration | Result|
|
||||
|:-------:|:-------:|
|
||||
@@ -465,10 +437,52 @@ view.showSkeleton()
|
||||
|<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"/>|
|
||||
|
||||
|
||||
|
||||
### 🔬 Debug
|
||||
**Hierarchy in collections**
|
||||
|
||||
**NEW** In order to facilitate the debug tasks when something is not working fine. `SkeletonView` has some new tools.
|
||||
Here is an illustration that shows how you should specify which elements are skeletonables when you are using an `UITableView`:
|
||||
|
||||
<img src="Assets/tableview_scheme.png" width="700px">
|
||||
|
||||
As you can see, we have to make skeletonable the tableview, the cell and the UI elements, but we don't need to set as skeletonable the `contentView`
|
||||
|
||||
|
||||
|
||||
**Skeleton views layout**
|
||||
|
||||
Sometimes skeleton layout may not fit your layout because the parent view bounds have changed. ~For example, rotating the device.~
|
||||
|
||||
You can relayout the skeleton views like so:
|
||||
|
||||
```swift
|
||||
override func viewDidLayoutSubviews() {
|
||||
view.layoutSkeletonIfNeeded()
|
||||
}
|
||||
```
|
||||
|
||||
> 📣 **IMPORTANT!**
|
||||
>
|
||||
> You shouldn't call this method. From **version 1.8.1** you don't need to call this method, the library does automatically. So, you can use this method **ONLY** in the cases when you need to update the layout of the skeleton manually.
|
||||
|
||||
|
||||
|
||||
|
||||
**Update skeleton**
|
||||
|
||||
You can change the skeleton configuration at any time like its colour, animation, etc. with the following methods:
|
||||
|
||||
```swift
|
||||
(1) view.updateSkeleton() // Solid
|
||||
(2) view.updateGradientSkeleton() // Gradient
|
||||
(3) view.updateAnimatedSkeleton() // Solid animated
|
||||
(4) view.updateAnimatedGradientSkeleton() // Gradient animated
|
||||
```
|
||||
|
||||
|
||||
**Debug**
|
||||
|
||||
To facilitate the debug tasks when something is not working fine. **`SkeletonView`** has some new tools.
|
||||
|
||||
First, `UIView` has available a new property with his skeleton info:
|
||||
```swift
|
||||
@@ -490,30 +504,13 @@ Then, when the skeleton appears, you can see the view hierarchy in the Xcode con
|
||||
<img src="Assets/hierarchy_output.png" />
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
### 📚 Documentation
|
||||
Coming soon...😅
|
||||
|
||||
### 📋 Supported OS & SDK Versions
|
||||
|
||||
**Supported OS & SDK Versions**
|
||||
|
||||
* iOS 9.0+
|
||||
* tvOS 9.0+
|
||||
* Swift 5
|
||||
|
||||
## 📬 Next steps
|
||||
|
||||
* [x] Set the filling percent of the last line in multiline elements
|
||||
* [x] Add more gradient animations
|
||||
* [x] Supported resizable cells
|
||||
* [x] CollectionView compatible
|
||||
* [x] tvOS compatible
|
||||
* [x] Add recovery state
|
||||
* [x] Custom default appearance
|
||||
* [x] Debug mode
|
||||
* [x] Add animations when it shows/hides the skeletons
|
||||
* [ ] Custom collections compatible
|
||||
* [ ] MacOS and WatchOS compatible
|
||||
|
||||
## ❤️ Contributing
|
||||
This is an open source project, so feel free to contribute. How?
|
||||
@@ -523,7 +520,8 @@ This is an open source project, so feel free to contribute. How?
|
||||
|
||||
See [all contributors](https://github.com/Juanpe/SkeletonView/graphs/contributors)
|
||||
|
||||
###### Project generated with [SwiftPlate](https://github.com/JohnSundell/SwiftPlate)
|
||||
For more information, please read the [contributing guidelines](https://github.com/Juanpe/SkeletonView/blob/develop/CONTRIBUTING.md).
|
||||
|
||||
|
||||
## 📢 Mentions
|
||||
|
||||
@@ -544,13 +542,12 @@ See [all contributors](https://github.com/Juanpe/SkeletonView/graphs/contributor
|
||||
|
||||
|
||||
## 👨🏻💻 Author
|
||||
[1.1]: http://i.imgur.com/tXSoThF.png
|
||||
[1]: http://www.twitter.com/JuanpeCatalan
|
||||
|
||||
* Juanpe Catalán [![alt text][1.1]][1]
|
||||
[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>
|
||||
|
||||
|
||||
## 👮🏻 License
|
||||
|
||||
```
|
||||
|
||||
+529
@@ -0,0 +1,529 @@
|
||||

|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Juanpe/SkeletonView/workflows/build">
|
||||
<img src="https://github.com/Juanpe/SkeletonView/workflows/build/badge.svg">
|
||||
</a>
|
||||
<a href="https://codebeat.co/projects/github-com-juanpe-skeletonview-master"><img alt="codebeat badge" src="https://codebeat.co/badges/f854fdfd-31e5-4689-ba04-075d83653e60" /></a>
|
||||
<img src="http://img.shields.io/badge/dependency%20manager-swiftpm%2Bcocoapods%2Bcarthage-green" />
|
||||
<img src="https://img.shields.io/badge/platforms-ios%2Btvos-green" />
|
||||
<a href="https://badge.bow-swift.io/recipe?name=SkeletonView&description=An%20elegant%20way%20to%20show%20users%20that%20something%20is%20happening%20and%20also%20prepare%20them%20to%20which%20contents%20he%20is%20waiting&url=https://github.com/juanpe/skeletonview&owner=Juanpe&avatar=https://avatars0.githubusercontent.com/u/1409041?v=4&tag=1.8.7"><img src="https://raw.githubusercontent.com/bow-swift/bow-art/master/badges/nef-playgrounds-badge.svg" alt="SkeletonView Playground" style="height:20px"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#-destacado">Destacado</a>
|
||||
• <a href="#-instalación">Instalación</a>
|
||||
• <a href="#-cómo-funciona">¿Cómo funciona?</a>
|
||||
• <a href="#-miscelánea">Miscelánea</a>
|
||||
• <a href="#️-contribuir">Contribuir</a>
|
||||
</p>
|
||||
|
||||
**🌎 README está disponible en estos idiomas: [🇬🇧](https://github.com/Juanpe/SkeletonView/blob/master/README.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)**
|
||||
|
||||
Hoy en día, La mayoría de las apps tiene procesos asíncronos, como peticiones a una API, procesos que tardan mucho tiempo, etc. Mientras estos procesos se están ejecutando, se suele mostrar un aburrido spinner indicando que algo está pasando.
|
||||
|
||||
**SkeletonView** ha sido desarrollada para cubrir esta necesidad, un elegante manera de decirle a los usarios que algo se está procesando y además prepararlos, visualmente, para el contenido que están esperando.
|
||||
|
||||
Enjoy it! 🙂
|
||||
|
||||
##
|
||||
- [🌟 Destacado](#-destacado)
|
||||
- [🎬 Videotutoriales](#-videotutoriales)
|
||||
- [📲 Instalación](#-instalación)
|
||||
- [🐒 ¿Cómo funciona?](#-cómo-funciona)
|
||||
- [🌿 Colecciones](#-colecciones)
|
||||
- [🔠 Textos](#-textos)
|
||||
- [🦋 Apariencia](#-apariencia)
|
||||
- [🎨 Colores](#-colors)
|
||||
- [🏃♀️ Animaciones](#️-animaciones)
|
||||
- [🏄 Transiciones](#-transiciones)
|
||||
- [✨ Miscelánea](#-miscelánea)
|
||||
- [❤️ Contribuir](#️-contribuir)
|
||||
- [📢 Menciones](#-menciones)
|
||||
- [👨🏻💻 Autor](#-autor)
|
||||
- [👮🏻 Licencia](#-licencia)
|
||||
|
||||
|
||||
|
||||
## 🌟 Destacado
|
||||
|
||||
* Fácil de usar
|
||||
* Todas las UIViews son skeletonables
|
||||
* Personalizable
|
||||
* Universal (iPhone & iPad)
|
||||
* Interface Builder friendly
|
||||
|
||||
|
||||
## 🎬 Videotutoriales
|
||||
|
||||
| [](https://youtu.be/75kgOhWsPNA)|[](https://youtu.be/MVCiM_VdxVA)|[](https://youtu.be/Qq3Evspeea8)|[](https://youtu.be/ZOoPtBwDRT0)
|
||||
|:---: | :---: |:---: | :---:
|
||||
|[**SkeletonView Guides - Getting started**](https://youtu.be/75kgOhWsPNA)|[**How to Create Loading View with Skeleton View in Swift 5.2**](https://youtu.be/MVCiM_VdxVA) by iKh4ever Studio|[**Create Skeleton Loading View in App (Swift 5) - Xcode 11, 2020**](https://youtu.be/Qq3Evspeea8) by iOS Academy| [**Add An Elegant Loading Animation in Swift***](https://youtu.be/ZOoPtBwDRT0) by Gary Tokman
|
||||
|
||||
|
||||
## 📲 Instalación
|
||||
|
||||
* [CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html):
|
||||
|
||||
```ruby
|
||||
pod 'SkeletonView'
|
||||
```
|
||||
|
||||
* [Carthage](https://github.com/Carthage/Carthage):
|
||||
|
||||
```ruby
|
||||
github "Juanpe/SkeletonView"
|
||||
```
|
||||
|
||||
* [Swift Package Manager](https://swift.org/package-manager/):
|
||||
|
||||
```swift
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/Juanpe/SkeletonView.git", from: "1.7.0")
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
## 🐒 ¿Cómo funciona?
|
||||
|
||||
Solo necesitas **3** pasos para usar `SkeletonView`:
|
||||
|
||||
1️⃣ Importa SkeletonView en el archivo donde vayas a utilizarlo.
|
||||
```swift
|
||||
import SkeletonView
|
||||
```
|
||||
|
||||
2️⃣ Ahora, debes indicar qué elementos de tu vista son `skeletonables`
|
||||
|
||||
**Con código:**
|
||||
```swift
|
||||
avatarImageView.isSkeletonable = true
|
||||
```
|
||||
**Con IB/Storyboards:**
|
||||
|
||||

|
||||
|
||||
3️⃣ Una vez indicado, solo tienes que mostrar el **skeleton**. Tienes **4** opciones:
|
||||
|
||||
```swift
|
||||
(1) view.showSkeleton() // Sólido
|
||||
(2) view.showGradientSkeleton() // Degradado
|
||||
(3) view.showAnimatedSkeleton() // Sólido animado
|
||||
(4) view.showAnimatedGradientSkeleton() // Degradado animado
|
||||
```
|
||||
|
||||
**Vista previa**
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="25%">
|
||||
<center>Sólido</center>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<center>Degradado</center>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<center>Sólido Animado</center>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<center>Degradado Animado</center>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="25%">
|
||||
<img src="Assets/solid.png"></img>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<img src="Assets/gradient.png"></img>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<img src="Assets/solid_animated.gif"></img>
|
||||
</td>
|
||||
<td width="25%">
|
||||
<img src="Assets/gradient_animated.gif"></img>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
> 📣 **¡IMPORTANTE!**
|
||||
>
|
||||
> `SkeletonView` es recursivo. Por lo que si tienes una vsita que contiene varios elementos skeletonables, solo tienes queenecu For example, with `UIViewControllers`.
|
||||
|
||||
|
||||
##
|
||||
### 🌿 Colecciones
|
||||
|
||||
`SkeletonView` es compatible con `UITableView` and `UICollectionView`.
|
||||
|
||||
|
||||
**UITableView**
|
||||
|
||||
Si quieres mostrar el skeleton en un `UITableView`, necesitas conformar el protocolo `SkeletonTableViewDataSource`.
|
||||
|
||||
``` swift
|
||||
public protocol SkeletonTableViewDataSource: UITableViewDataSource {
|
||||
// Por defecto: 1
|
||||
func numSections(in collectionSkeletonView: UITableView) -> Int
|
||||
|
||||
// Por defecto:
|
||||
// Calcula cuantas celdas necesita para rellenar todo el frame.
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int
|
||||
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
|
||||
}
|
||||
```
|
||||
|
||||
Este protocolo hereda de `UITableViewDataSource`, por lo que puedes reemplazar este protocolo por el protocolo de skeleton sin perder ninguna funcionalidad. El único método que es obligatorio implementar es `cellIdentifierForRowAt`, donde tienes que indicar el identificador de la celda.
|
||||
|
||||
**Ejemplo**
|
||||
``` swift
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier {
|
||||
return "CellIdentifier"
|
||||
}
|
||||
```
|
||||
|
||||
Además, tu puedes mostrar el skeleton en las headers y en los footers, conformando el protocolo `SkeletonTableViewDelegate`.
|
||||
|
||||
```swift
|
||||
public protocol SkeletonTableViewDelegate: UITableViewDelegate {
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -> ReusableHeaderFooterIdentifier? // default: nil
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -> ReusableHeaderFooterIdentifier? // default: nil
|
||||
}
|
||||
```
|
||||
|
||||
> 📣 **¡IMPORTANTE!**
|
||||
>
|
||||
> 1️⃣ Si estás usando celdas con altura dinámica (**`tableView.rowHeight = UITableViewAutomaticDimension`**), es obligatorio definir el **`estimatedRowHeight`**.
|
||||
>
|
||||
> 2️⃣ Cuando añades elemetos a una **`UITableViewCell`**, debes añadirlo al **`contentView`** y no a la celda directamente.
|
||||
> ```swift
|
||||
> cell.contentView.addSubview(titleLabel) ✅
|
||||
> cell.addSubview(titleLabel) ❌
|
||||
> ```
|
||||
|
||||
|
||||
|
||||
**UICollectionView**
|
||||
|
||||
Para los `UICollectionView`, debes conformar el protocolo `SkeletonCollectionViewDataSource`.
|
||||
|
||||
``` swift
|
||||
public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
|
||||
func numSections(in collectionSkeletonView: UICollectionView) -> Int // Por defecto: 1
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -> ReusableCellIdentifier? // Por defecto: nil
|
||||
}
|
||||
```
|
||||
|
||||
El resto del proceso es exactamente igual que con las `UITableView`.
|
||||
|
||||
|
||||
### 🔠 Textos
|
||||
|
||||

|
||||
|
||||
Cuando usas elementos que contienen texto,`SkeletonView` dibujo líneas para simular el texto.
|
||||
|
||||
Además, puedes decidir el número de líneas. Si `numberOfLines` es igual a **0**, se calculará automáticamente el número de líneas necesarias para ocupar todo el frame. Sin embargo, si es un número mayor que cero, solo se dibujarán esas líneas.
|
||||
|
||||
Puedes especificar algunos atributos para estos elementos:
|
||||
|
||||
|
||||
| Atributo | Valores | Por defecto | Vista previa
|
||||
| ------- | ------- |------- | -------
|
||||
| **Porcentaje de relleno** de la última línea. | `0...100` | `70%` | 
|
||||
| **Radio de las esquinas** de las líneas. | `0...10` | `0` | 
|
||||
|
||||
Para modificar alguno de los valores lo puedes hacer **con código**::
|
||||
```swift
|
||||
descriptionTextView.lastLineFillPercent = 50
|
||||
descriptionTextView.linesCornerRadius = 5
|
||||
```
|
||||
|
||||
O usando **IB/Storyboards**:
|
||||
|
||||

|
||||
|
||||
|
||||
### 🦋 Apariencia
|
||||
|
||||
Los skeletons tiene una apariencia por defecto. Así, cuando no especificas el color, el degradado o las propiedades para las multiíneas, `SkeletonView` usa estos valores.
|
||||
|
||||
Valores por defecto:
|
||||
- **tintColor**: `UIColor`
|
||||
- *default: `.skeletonDefault` (igual que `.clouds` pero se adapta al dark mode)*
|
||||
- **gradient**: `SkeletonGradient`
|
||||
- *default: `SkeletonGradient(baseColor: .skeletonDefault)`*
|
||||
- **multilineHeight**: `CGFloat`
|
||||
- *default: 15*
|
||||
- **multilineSpacing**: `CGFloat`
|
||||
- *default: 10*
|
||||
- **multilineLastLineFillPercent**: `Int`
|
||||
- *default: 70*
|
||||
- **multilineCornerRadius**: `Int`
|
||||
- *default: 0*
|
||||
- **skeletonCornerRadius**: `CGFloat` (IBInspectable)
|
||||
- *default: 0*
|
||||
|
||||
Para obtener o modificar estos valores tu puedes usar `SkeletonAppearance.default`:
|
||||
```swift
|
||||
SkeletonAppearance.default.multilineHeight = 20
|
||||
SkeletonAppearance.default.tintColor = .green
|
||||
```
|
||||
|
||||
|
||||
### 🎨 Colores
|
||||
|
||||
Puedes decidir de qué color se tinta tu skeleton. Solo tienes que indicarlo pasándolo como parámetro:
|
||||
|
||||
**Usando colores sólidos**
|
||||
```swift
|
||||
view.showSkeleton(usingColor: UIColor.gray)
|
||||
// o
|
||||
view.showSkeleton(usingColor: UIColor(red: 25.0, green: 30.0, blue: 255.0, alpha: 1.0))
|
||||
```
|
||||
**Usando degradados**
|
||||
``` swift
|
||||
let gradient = SkeletonGradient(baseColor: UIColor.midnightBlue)
|
||||
view.showGradientSkeleton(usingGradient: gradient)
|
||||
```
|
||||
|
||||
Además, **SkeletonView** añade 20 colores flat 🤙🏼
|
||||
|
||||
```UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...```
|
||||
|
||||

|
||||
###### Imagen extraída de la web [https://flatuicolors.com](https://flatuicolors.com)
|
||||
|
||||
|
||||
### 🏃♀️ Animaciones
|
||||
|
||||
**SkeletonView** tiene pre-definidas dos animaciones, *pulse* para skeleton sólidos y *sliding* para degradados.
|
||||
|
||||
Además, usando el método `showAnimatedSkeleton`, podemos incluir la `animation` que es de tipo `SkeletonLayerAnimation`, un bloque donde tu puedes crear tus propias animaciones:
|
||||
|
||||
```swift
|
||||
public typealias SkeletonLayerAnimation = (CALayer) -> CAAnimation
|
||||
```
|
||||
|
||||
Tu código quedaría así:
|
||||
|
||||
```swift
|
||||
view.showAnimatedSkeleton { (layer) -> CAAnimation in
|
||||
let animation = CAAnimation()
|
||||
// Personaliza la animación aquí
|
||||
|
||||
return animation
|
||||
}
|
||||
```
|
||||
|
||||
`SkeletonAnimationBuilder` es un builder que permite crear `SkeletonLayerAnimation`.
|
||||
|
||||
Por ejemplo, tu puedes crear **sliding animations** para los degradados, decidiendo la **direction** y indicando la **duration** de la animación (default = 1.5s).
|
||||
|
||||
```swift
|
||||
// func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation
|
||||
|
||||
let animation = SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: .leftToRight)
|
||||
view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
|
||||
|
||||
```
|
||||
|
||||
```GradientDirection``` es un enumerado con estos `cases`:
|
||||
|
||||
| Dirección | Vista previa
|
||||
|------- | -------
|
||||
| .leftRight | 
|
||||
| .rightLeft | 
|
||||
| .topBottom | 
|
||||
| .bottomTop | 
|
||||
| .topLeftBottomRight | 
|
||||
| .bottomRightTopLeft | 
|
||||
|
||||
> **😉 ¡Truco!**
|
||||
>
|
||||
> Puedes crear una animación sliding, con este shortcut:
|
||||
> ```swift
|
||||
> let animation = GradientDirection.leftToRight.slidingAnimation()
|
||||
> ```
|
||||
|
||||
|
||||
|
||||
### 🏄 Transiciones
|
||||
|
||||
**SkeletonView** tiene algunas transiciones listas para usarse cuando **aparece** o se **oculta**. Puedes especificarla así:
|
||||
|
||||
```swift
|
||||
view.showSkeleton(transition: .crossDissolve(0.25))
|
||||
view.hideSkeleton(transition: .crossDissolve(0.25))
|
||||
|
||||
```
|
||||
|
||||
La transición por defecto es `crossDissolve(0.25)`
|
||||
|
||||
**Vista previa**
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<center>Sin transición</center>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<center>Cross dissolve</center>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<img src="Assets/skeleton_transition_nofade.gif"></img>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<img src="Assets/skeleton_transition_fade.gif"></img>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
## ✨ Miscelánea
|
||||
|
||||
|
||||
|
||||
**Jerarquía**
|
||||
|
||||
|
||||
`SkeletonView` es recursivo, pero para que sea eficiente, tenemos que pararar la recursión tan pronto como sea posible. Por este motivo, el contenedor de las vistas debe ser **`skeletonable`**, porque `SkeletonView` parará de buscar vistas skeletonables cuando encuentre una que no lo sea, dentro de la jerarquía.
|
||||
|
||||
Como una imagen vale más que mil palabras:
|
||||
|
||||
En este ejemplo, tenemos un `UIViewController` con un `containerView` y una `UITableView`. Cuando la vista está lista, para mostrar el skeleton ejecutamos el método:
|
||||
```
|
||||
view.showSkeleton()
|
||||
```
|
||||
|
||||
> `isSkeletonable`= ☠️
|
||||
|
||||
| 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"/>|
|
||||
|
||||
|
||||
|
||||
**Jerarquía en las colecciones**
|
||||
|
||||
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">
|
||||
|
||||
|
||||
**Actualiza el skeleton**
|
||||
|
||||
Puedes cambiar la configuración del skeleton, como el color, la animación, etc, con los siguientes métodos:
|
||||
|
||||
```swift
|
||||
(1) view.updateSkeleton() // Sólido
|
||||
(2) view.updateGradientSkeleton() // Degradado
|
||||
(3) view.updateAnimatedSkeleton() // Sólido animado
|
||||
(4) view.updateAnimatedGradientSkeleton() // Degradado animado
|
||||
```
|
||||
|
||||
|
||||
**Debug**
|
||||
|
||||
Para facilitar las tareas de debug cuando algo no está funcionando bien, **`SkeletonView`** tiene una nueva herramienta.
|
||||
|
||||
Primero, `UIView` tiene una nueva propiedad que contiene toda la info del skeleton:
|
||||
```swift
|
||||
var skeletonDescription: String
|
||||
|
||||
```
|
||||
Y es representada de la siguiente manera:
|
||||
|
||||

|
||||
|
||||
Para activar el **modo debug**. Solo tienes que añadir una variable de entorno con esta clave `SKELETON_DEBUG` y activarla.
|
||||
|
||||

|
||||
|
||||
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" />
|
||||
</details>
|
||||
|
||||
|
||||
**OS Soportado & Versiones SDK**
|
||||
|
||||
* iOS 9.0+
|
||||
* tvOS 9.0+
|
||||
* Swift 5
|
||||
|
||||
|
||||
## ❤️ Contributing
|
||||
|
||||
Esto es un proyecto open source, siéntete libre de contribuir. ¿Cómo?
|
||||
- Abre un [issue](https://github.com/Juanpe/SkeletonView/issues/new).
|
||||
- Envía feedback a través del [email](mailto://juanpecatalan.com).
|
||||
- Propone tus propies fixes, sugerencias y abre una Pull Request con los cambios.
|
||||
|
||||
É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).
|
||||
|
||||
|
||||
## 📢 Menciones
|
||||
|
||||
- [iOS Dev Weekly #327](https://iosdevweekly.com/issues/327#start)
|
||||
- [Hacking with Swift Articles](https://www.hackingwithswift.com/articles/40/skeletonview-makes-loading-content-beautiful)
|
||||
- [Top 10 Swift Articles November](https://medium.mybridge.co/swift-top-10-articles-for-the-past-month-v-nov-2017-dfed7861cd65)
|
||||
- [30 Amazing iOS Swift Libraries (v2018)](https://medium.mybridge.co/30-amazing-ios-swift-libraries-for-the-past-year-v-2018-7cf15027eee9)
|
||||
- [AppCoda Weekly #44](http://digest.appcoda.com/issues/appcoda-weekly-issue-44-81899)
|
||||
- [iOS Cookies Newsletter #103](https://us11.campaign-archive.com/?u=cd1f3ed33c6527331d82107ba&id=48131a516d)
|
||||
- [Swift Developments Newsletter #113](https://andybargh.com/swiftdevelopments-113/)
|
||||
- [iOS Goodies #204](http://ios-goodies.com/post/167557280951/week-204)
|
||||
- [Swift Weekly #96](http://digest.swiftweekly.com/issues/swift-weekly-issue-96-81759)
|
||||
- [CocoaControls](https://www.cocoacontrols.com/controls/skeletonview)
|
||||
- [Awesome iOS Newsletter #74](https://ios.libhunt.com/newsletter/74)
|
||||
- [Swift News #36](https://www.youtube.com/watch?v=mAGpsQiy6so)
|
||||
- [Best iOS articles, new tools & more](https://medium.com/flawless-app-stories/best-ios-articles-new-tools-more-fcbe673e10d)
|
||||
|
||||
|
||||
|
||||
## 👨🏻💻 Autor
|
||||
|
||||
[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>
|
||||
|
||||
|
||||
## 👮🏻 Licencia
|
||||
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Juanpe Catalán
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "SkeletonView"
|
||||
s.version = "1.8.8"
|
||||
s.version = "1.9"
|
||||
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.
|
||||
|
||||
@@ -526,6 +526,7 @@
|
||||
17DD0DFC207FB27400C56334 /* Frameworks */,
|
||||
17DD0DFD207FB27400C56334 /* Headers */,
|
||||
17DD0DFE207FB27400C56334 /* Resources */,
|
||||
1E3CFFD5250AD9A400DDB852 /* SwiftLint */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -563,6 +564,7 @@
|
||||
52D6D9781BEFF229002C0205 /* Frameworks */,
|
||||
52D6D9791BEFF229002C0205 /* Headers */,
|
||||
52D6D97A1BEFF229002C0205 /* Resources */,
|
||||
1E3CFFD3250AD95300DDB852 /* SwiftLint */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -679,6 +681,45 @@
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
1E3CFFD3250AD95300DDB852 /* SwiftLint */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = SwiftLint;
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||
};
|
||||
1E3CFFD5250AD9A400DDB852 /* SwiftLint */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = SwiftLint;
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
17DD0DFB207FB27400C56334 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
|
||||
@@ -22,7 +22,7 @@ class SkeletonViewAppearance: Appearance {
|
||||
|
||||
var tintColor: UIColor = .skeletonDefault
|
||||
|
||||
var gradient: SkeletonGradient = SkeletonGradient(baseColor: .skeletonDefault)
|
||||
var gradient = SkeletonGradient(baseColor: .skeletonDefault)
|
||||
|
||||
var multilineHeight: CGFloat = 15
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
|
||||
func numSections(in collectionSkeletonView: UICollectionView) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int
|
||||
@@ -31,4 +30,3 @@ public extension SkeletonCollectionViewDataSource {
|
||||
}
|
||||
|
||||
public protocol SkeletonCollectionViewDelegate: UICollectionViewDelegate { }
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import UIKit
|
||||
extension UICollectionView: CollectionSkeleton {
|
||||
var estimatedNumberOfRows: Int {
|
||||
guard let flowlayout = collectionViewLayout as? UICollectionViewFlowLayout else { return 0 }
|
||||
return Int(ceil(frame.height/flowlayout.itemSize.height))
|
||||
return Int(ceil(frame.height / flowlayout.itemSize.height))
|
||||
}
|
||||
|
||||
var skeletonDataSource: SkeletonCollectionDataSource? {
|
||||
@@ -70,7 +70,7 @@ public extension UICollectionView {
|
||||
self.skeletonDataSource = dataSource
|
||||
performBatchUpdates({
|
||||
self.reloadData()
|
||||
}) { (done) in
|
||||
}) { done in
|
||||
completion(done)
|
||||
|
||||
}
|
||||
|
||||
@@ -63,9 +63,8 @@ extension SkeletonCollectionDataSource: UICollectionViewDataSource {
|
||||
func collectionView(_ collectionView: UICollectionView,
|
||||
viewForSupplementaryElementOfKind kind: String,
|
||||
at indexPath: IndexPath) -> UICollectionReusableView {
|
||||
|
||||
if let viewIdentifier = originalCollectionViewDataSource?.collectionSkeletonView(collectionView, supplementaryViewIdentifierOfKind: kind, at: indexPath) {
|
||||
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: viewIdentifier, for: indexPath)
|
||||
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: viewIdentifier, for: indexPath)
|
||||
skeletonViewIfContainerSkeletonIsActive(container: collectionView, view: view)
|
||||
return view
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ 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
|
||||
}
|
||||
@@ -34,7 +33,6 @@ extension SkeletonCollectionDelegate: UITableViewDelegate {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public typealias ReusableHeaderFooterIdentifier = String
|
||||
|
||||
extension UITableView: CollectionSkeleton {
|
||||
var estimatedNumberOfRows: Int {
|
||||
return Int(ceil(frame.height/rowHeight))
|
||||
return Int(ceil(frame.height / rowHeight))
|
||||
}
|
||||
|
||||
var skeletonDataSource: SkeletonCollectionDataSource? {
|
||||
@@ -43,8 +43,7 @@ extension UITableView: CollectionSkeleton {
|
||||
self.skeletonDataSource = dataSource
|
||||
|
||||
if let originalDelegate = self.delegate as? SkeletonTableViewDelegate,
|
||||
!(originalDelegate is SkeletonCollectionDelegate)
|
||||
{
|
||||
!(originalDelegate is SkeletonCollectionDelegate) {
|
||||
let delegate = SkeletonCollectionDelegate(tableViewDelegate: originalDelegate)
|
||||
self.skeletonDelegate = delegate
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
@@ -10,6 +9,7 @@ enum SkeletonEnvironmentKey: String {
|
||||
|
||||
extension Dictionary {
|
||||
subscript (_ key: SkeletonEnvironmentKey) -> Value? {
|
||||
// swiftlint:disable:next force_cast
|
||||
return self[key.rawValue as! Key]
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ func printSkeletonHierarchy(in view: UIView) {
|
||||
}
|
||||
|
||||
func skeletonLog(_ message: String) {
|
||||
if let _ = ProcessInfo.processInfo.environment[.debugMode] {
|
||||
if ProcessInfo.processInfo.environment[.debugMode] != nil {
|
||||
print(message)
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ extension UIView {
|
||||
public var skeletonDescription: String {
|
||||
var description = "<\(type(of: self)): \(Unmanaged.passUnretained(self).toOpaque())"
|
||||
let subSkeletons = subviewsSkeletonables
|
||||
if subSkeletons.count != 0 {
|
||||
if !subSkeletons.isEmpty {
|
||||
description += " | (\(subSkeletons.count)) subSkeletons"
|
||||
}
|
||||
if isSkeletonable {
|
||||
|
||||
@@ -30,7 +30,7 @@ extension CAGradientLayer {
|
||||
|
||||
struct SkeletonMultilinesLayerConfig {
|
||||
var lines: Int
|
||||
var lineHeight: CGFloat? = nil
|
||||
var lineHeight: CGFloat?
|
||||
var type: SkeletonType
|
||||
var lastLineFillPercent: Int
|
||||
var multilineCornerRadius: Int
|
||||
@@ -38,7 +38,6 @@ struct SkeletonMultilinesLayerConfig {
|
||||
var paddingInsets: UIEdgeInsets
|
||||
}
|
||||
|
||||
|
||||
// MARK: Skeleton sublayers
|
||||
extension CALayer {
|
||||
static let skeletonSubLayersName = "SkeletonSubLayersName"
|
||||
@@ -50,7 +49,8 @@ extension CALayer {
|
||||
func addMultilinesLayers(for config: SkeletonMultilinesLayerConfig) {
|
||||
let numberOfSublayers = config.lines == 1 ? 1 : calculateNumLines(for: config)
|
||||
var height = config.lineHeight ?? SkeletonAppearance.default.multilineHeight
|
||||
if numberOfSublayers == 1 {
|
||||
|
||||
if numberOfSublayers == 1 && SkeletonAppearance.default.renderSingleLineAsView {
|
||||
height = bounds.height
|
||||
}
|
||||
|
||||
@@ -79,7 +79,8 @@ extension CALayer {
|
||||
let paddingInsets = config.paddingInsets
|
||||
let multilineSpacing = config.multilineSpacing
|
||||
var height = config.lineHeight ?? SkeletonAppearance.default.multilineHeight
|
||||
if numberOfSublayers == 1 {
|
||||
|
||||
if numberOfSublayers == 1 && SkeletonAppearance.default.renderSingleLineAsView {
|
||||
height = bounds.height
|
||||
}
|
||||
|
||||
@@ -99,13 +100,13 @@ extension CALayer {
|
||||
|
||||
func updateLayerFrame(for index: Int, size: CGSize, multilineSpacing: CGFloat, paddingInsets: UIEdgeInsets) {
|
||||
let spaceRequiredForEachLine = SkeletonAppearance.default.multilineHeight + multilineSpacing
|
||||
frame = CGRect(x: paddingInsets.left, y: CGFloat(index) * spaceRequiredForEachLine + paddingInsets.top, width: size.width, height: size.height)
|
||||
frame = CGRect(x: paddingInsets.left, y: CGFloat(index) * spaceRequiredForEachLine + paddingInsets.top, width: size.width, height: size.height - paddingInsets.bottom - paddingInsets.top)
|
||||
}
|
||||
|
||||
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 }
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -115,6 +116,7 @@ public extension CALayer {
|
||||
var pulse: CAAnimation {
|
||||
let pulseAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.backgroundColor))
|
||||
pulseAnimation.fromValue = backgroundColor
|
||||
//swiftlint:disable:next force_unwrapping
|
||||
pulseAnimation.toValue = UIColor(cgColor: backgroundColor!).complementaryColor.cgColor
|
||||
pulseAnimation.duration = 1
|
||||
pulseAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
|
||||
@@ -127,11 +129,11 @@ public extension CALayer {
|
||||
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)
|
||||
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)
|
||||
endPointAnim.toValue = CGPoint(x: 2, y: 0.5)
|
||||
|
||||
let animGroup = CAAnimationGroup()
|
||||
animGroup.animations = [startPointAnim, endPointAnim]
|
||||
|
||||
@@ -22,7 +22,7 @@ extension UIColor {
|
||||
|
||||
public var complementaryColor: UIColor {
|
||||
if #available(iOS 13, tvOS 13, *) {
|
||||
return UIColor { traitCollection in
|
||||
return UIColor { _ in
|
||||
return self.isLight() ? self.darker : self.lighter
|
||||
}
|
||||
} else {
|
||||
@@ -50,6 +50,7 @@ extension UIColor {
|
||||
}
|
||||
|
||||
public extension UIColor {
|
||||
// swiftlint:disable operator_usage_whitespace
|
||||
static var greenSea = UIColor(0x16a085)
|
||||
static var turquoise = UIColor(0x1abc9c)
|
||||
static var emerald = UIColor(0x2ecc71)
|
||||
@@ -71,13 +72,16 @@ public extension UIColor {
|
||||
static var pomegranate = UIColor(0xc0392b)
|
||||
static var silver = UIColor(0xbdc3c7)
|
||||
static var asbestos = UIColor(0x7f8c8d)
|
||||
|
||||
// swiftlint:enable operator_usage_whitespace
|
||||
|
||||
static var skeletonDefault: UIColor {
|
||||
if #available(iOS 13, tvOS 13, *) {
|
||||
return UIColor { traitCollection in
|
||||
switch traitCollection.userInterfaceStyle {
|
||||
case .dark: return .darkClouds
|
||||
default: return .clouds
|
||||
case .dark:
|
||||
return .darkClouds
|
||||
default:
|
||||
return .clouds
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -13,15 +13,13 @@ extension UITableView {
|
||||
headerRect = rectForHeader(inSection: $1)
|
||||
}
|
||||
|
||||
if headerRect != nil {
|
||||
let visiblePartOfTableView: CGRect = CGRect(
|
||||
x: contentOffset.x,
|
||||
y: contentOffset.y,
|
||||
width: bounds.size.width,
|
||||
height: bounds.size.height
|
||||
)
|
||||
if let headerRect = headerRect {
|
||||
let visiblePartOfTableView = CGRect(x: contentOffset.x,
|
||||
y: contentOffset.y,
|
||||
width: bounds.size.width,
|
||||
height: bounds.size.height)
|
||||
|
||||
if (visiblePartOfTableView.intersects(headerRect!)) {
|
||||
if visiblePartOfTableView.intersects(headerRect) {
|
||||
return $0 + [$1]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ enum ViewAssociatedKeys {
|
||||
static var viewState = "viewState"
|
||||
static var labelViewState = "labelViewState"
|
||||
static var imageViewState = "imageViewState"
|
||||
static var buttonViewState = "buttonViewState"
|
||||
static var currentSkeletonConfig = "currentSkeletonConfig"
|
||||
static var skeletonCornerRadius = "skeletonCornerRadius"
|
||||
}
|
||||
@@ -38,13 +39,13 @@ extension UIView {
|
||||
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.currentSkeletonConfig) }
|
||||
}
|
||||
|
||||
var status: Status! {
|
||||
var status: Status {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.status) as? Status ?? .off }
|
||||
set { ao_set(newValue ?? .off, pkey: &ViewAssociatedKeys.status) }
|
||||
set { ao_set(newValue, pkey: &ViewAssociatedKeys.status) }
|
||||
}
|
||||
|
||||
var isSkeletonAnimated: Bool! {
|
||||
var isSkeletonAnimated: Bool {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.isSkeletonAnimated) as? Bool ?? false }
|
||||
set { ao_set(newValue ?? false, pkey: &ViewAssociatedKeys.isSkeletonAnimated) }
|
||||
set { ao_set(newValue, pkey: &ViewAssociatedKeys.isSkeletonAnimated) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,17 +16,16 @@ public extension UIView {
|
||||
}
|
||||
|
||||
var isSkeletonActive: Bool {
|
||||
return status == .on || (subviewsSkeletonables.first(where: { $0.isSkeletonActive }) != nil)
|
||||
return status == .on || subviewsSkeletonables.contains(where: { $0.isSkeletonActive })
|
||||
}
|
||||
|
||||
private var skeletonable: Bool! {
|
||||
private var skeletonable: Bool {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.skeletonable) as? Bool ?? false }
|
||||
set { ao_set(newValue ?? false, pkey: &ViewAssociatedKeys.skeletonable) }
|
||||
set { ao_set(newValue, pkey: &ViewAssociatedKeys.skeletonable) }
|
||||
}
|
||||
|
||||
private var skeletonableCornerRadius: Float! {
|
||||
private var skeletonableCornerRadius: Float {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.skeletonCornerRadius) as? Float ?? 0.0 }
|
||||
set { ao_set(newValue ?? 0.0, pkey: &ViewAssociatedKeys.skeletonCornerRadius) }
|
||||
set { ao_set(newValue, pkey: &ViewAssociatedKeys.skeletonCornerRadius) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ enum AssociationPolicy: UInt {
|
||||
case retainNonatomic = 1
|
||||
|
||||
var objc: objc_AssociationPolicy {
|
||||
// swiftlint:disable:next force_unwrapping
|
||||
return objc_AssociationPolicy(rawValue: rawValue)!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,3 +44,13 @@ extension UIImageView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIButton {
|
||||
override func prepareViewForSkeleton() {
|
||||
backgroundColor = .clear
|
||||
startTransition { [weak self] in
|
||||
self?.setTitle(nil, for: .normal)
|
||||
self?.isUserInteractionEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ protocol IterableElement {}
|
||||
extension UIView: IterableElement {}
|
||||
extension CALayer: IterableElement {}
|
||||
|
||||
//MARK: Recursive
|
||||
// MARK: Recursive
|
||||
protocol Recursive {
|
||||
associatedtype Element: IterableElement
|
||||
func recursiveSearch(leafBlock: VoidBlock, recursiveBlock: RecursiveBlock<Element>)
|
||||
@@ -17,12 +17,10 @@ protocol Recursive {
|
||||
|
||||
extension Array: Recursive where Element: IterableElement {
|
||||
func recursiveSearch(leafBlock: VoidBlock, recursiveBlock: RecursiveBlock<Element>) {
|
||||
guard count > 0 else {
|
||||
guard !isEmpty else {
|
||||
leafBlock()
|
||||
return
|
||||
}
|
||||
forEach { recursiveBlock($0) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import Foundation
|
||||
extension DispatchQueue {
|
||||
private static var _onceTracker = [String]()
|
||||
|
||||
class func once(token: String, block:()->Void) {
|
||||
class func once(token: String, block: () -> Void) {
|
||||
objc_sync_enter(self); defer { objc_sync_exit(self) }
|
||||
guard !_onceTracker.contains(token) else { return }
|
||||
|
||||
@@ -19,7 +19,7 @@ func swizzle(selector originalSelector: Selector, with swizzledSelector: Selecto
|
||||
let swizzledMethod = class_getInstanceMethod(usingClass, swizzledSelector)
|
||||
else { return }
|
||||
|
||||
if (class_addMethod(inClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))) {
|
||||
if class_addMethod(inClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) {
|
||||
class_replaceMethod(inClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
|
||||
} else {
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod)
|
||||
|
||||
@@ -8,17 +8,19 @@ public extension UILabel {
|
||||
get { return lastLineFillingPercent }
|
||||
set { lastLineFillingPercent = min(newValue, 100) }
|
||||
}
|
||||
|
||||
@IBInspectable
|
||||
var linesCornerRadius: Int {
|
||||
get { return multilineCornerRadius }
|
||||
set { multilineCornerRadius = min(newValue, 10) }
|
||||
}
|
||||
|
||||
@IBInspectable
|
||||
var skeletonLineSpacing: CGFloat {
|
||||
get { return multilineSpacing }
|
||||
set { multilineSpacing = min(newValue, 10) }
|
||||
}
|
||||
@IBInspectable
|
||||
|
||||
var skeletonPaddingInsets: UIEdgeInsets {
|
||||
get { return paddingInsets }
|
||||
set { paddingInsets = newValue }
|
||||
|
||||
@@ -21,7 +21,6 @@ public extension UITextView {
|
||||
set { multilineSpacing = min(newValue, 10) }
|
||||
}
|
||||
|
||||
@IBInspectable
|
||||
var skeletonPaddingInsets: UIEdgeInsets {
|
||||
get { return paddingInsets }
|
||||
set { paddingInsets = newValue }
|
||||
|
||||
@@ -37,7 +37,7 @@ extension UIView: Recoverable {
|
||||
}
|
||||
}
|
||||
|
||||
extension UILabel{
|
||||
extension UILabel {
|
||||
var labelState: RecoverableTextViewState? {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.labelViewState) as? RecoverableTextViewState }
|
||||
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.labelViewState) }
|
||||
@@ -58,7 +58,7 @@ extension UILabel{
|
||||
}
|
||||
}
|
||||
|
||||
extension UITextView{
|
||||
extension UITextView {
|
||||
var textState: RecoverableTextViewState? {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.labelViewState) as? RecoverableTextViewState }
|
||||
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.labelViewState) }
|
||||
@@ -97,3 +97,23 @@ extension UIImageView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIButton {
|
||||
var buttonState: RecoverableButtonViewState? {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.buttonViewState) as? RecoverableButtonViewState }
|
||||
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.buttonViewState) }
|
||||
}
|
||||
|
||||
override func saveViewState() {
|
||||
super.saveViewState()
|
||||
buttonState = RecoverableButtonViewState(view: self)
|
||||
}
|
||||
|
||||
override func recoverViewState(forced: Bool) {
|
||||
super.recoverViewState(forced: forced)
|
||||
startTransition { [weak self] in
|
||||
self?.setTitle(self?.buttonState?.title, for: .normal)
|
||||
self?.isUserInteractionEnabled = self?.buttonState?.isUserInteractionsEnabled ?? false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,3 +45,13 @@ struct RecoverableImageViewState {
|
||||
self.image = view.image
|
||||
}
|
||||
}
|
||||
|
||||
struct RecoverableButtonViewState {
|
||||
var title: String?
|
||||
var isUserInteractionsEnabled: Bool
|
||||
|
||||
init(view: UIButton) {
|
||||
self.title = view.titleLabel?.text
|
||||
self.isUserInteractionsEnabled = view.isUserInteractionEnabled
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,34 +26,34 @@ public enum GradientDirection {
|
||||
var startPoint: GradientAnimationPoint {
|
||||
switch self {
|
||||
case .leftRight:
|
||||
return (from: CGPoint(x:-1, y:0.5), to: CGPoint(x:1, y:0.5))
|
||||
return (from: CGPoint(x: -1, y: 0.5), to: CGPoint(x: 1, y: 0.5))
|
||||
case .rightLeft:
|
||||
return (from: CGPoint(x:1, y:0.5), to: CGPoint(x:-1, y:0.5))
|
||||
return (from: CGPoint(x: 1, y: 0.5), to: CGPoint(x: -1, y: 0.5))
|
||||
case .topBottom:
|
||||
return (from: CGPoint(x:0.5, y:-1), to: CGPoint(x:0.5, y:1))
|
||||
return (from: CGPoint(x: 0.5, y: -1), to: CGPoint(x: 0.5, y: 1))
|
||||
case .bottomTop:
|
||||
return (from: CGPoint(x:0.5, y:1), to: CGPoint(x:0.5, y:-1))
|
||||
return (from: CGPoint(x: 0.5, y: 1), to: CGPoint(x: 0.5, y: -1))
|
||||
case .topLeftBottomRight:
|
||||
return (from: CGPoint(x:-1, y:-1), to: CGPoint(x:1, y:1))
|
||||
return (from: CGPoint(x: -1, y: -1), to: CGPoint(x: 1, y: 1))
|
||||
case .bottomRightTopLeft:
|
||||
return (from: CGPoint(x:1, y:1), to: CGPoint(x:-1, y:-1))
|
||||
return (from: CGPoint(x: 1, y: 1), to: CGPoint(x: -1, y: -1))
|
||||
}
|
||||
}
|
||||
|
||||
var endPoint: GradientAnimationPoint {
|
||||
switch self {
|
||||
case .leftRight:
|
||||
return (from: CGPoint(x:0, y:0.5), to: CGPoint(x:2, y:0.5))
|
||||
return (from: CGPoint(x: 0, y: 0.5), to: CGPoint(x: 2, y: 0.5))
|
||||
case .rightLeft:
|
||||
return ( from: CGPoint(x:2, y:0.5), to: CGPoint(x:0, y:0.5))
|
||||
return ( from: CGPoint(x: 2, y: 0.5), to: CGPoint(x: 0, y: 0.5))
|
||||
case .topBottom:
|
||||
return ( from: CGPoint(x:0.5, y:0), to: CGPoint(x:0.5, y:2))
|
||||
return ( from: CGPoint(x: 0.5, y: 0), to: CGPoint(x: 0.5, y: 2))
|
||||
case .bottomTop:
|
||||
return ( from: CGPoint(x:0.5, y:2), to: CGPoint(x:0.5, y:0))
|
||||
return ( from: CGPoint(x: 0.5, y: 2), to: CGPoint(x: 0.5, y: 0))
|
||||
case .topLeftBottomRight:
|
||||
return ( from: CGPoint(x:0, y:0), to: CGPoint(x:2, y:2))
|
||||
return ( from: CGPoint(x: 0, y: 0), to: CGPoint(x: 2, y: 2))
|
||||
case .bottomRightTopLeft:
|
||||
return ( from: CGPoint(x:2, y:2), to: CGPoint(x:0, y:0))
|
||||
return ( from: CGPoint(x: 2, y: 2), to: CGPoint(x: 0, y: 0))
|
||||
}
|
||||
}
|
||||
// codebeat:enable[ABC]
|
||||
@@ -64,7 +64,6 @@ public class SkeletonAnimationBuilder {
|
||||
|
||||
public func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation {
|
||||
return { layer in
|
||||
|
||||
let startPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.startPoint))
|
||||
startPointAnim.fromValue = direction.startPoint.from
|
||||
startPointAnim.toValue = direction.startPoint.to
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
protocol SkeletonFlowDelegate {
|
||||
protocol SkeletonFlowDelegate: AnyObject {
|
||||
func willBeginShowingSkeletons(rootView: UIView)
|
||||
func didShowSkeletons(rootView: UIView)
|
||||
func willBeginUpdatingSkeletons(rootView: UIView)
|
||||
|
||||
@@ -121,7 +121,7 @@ extension UIView {
|
||||
addDummyDataSourceIfNeeded()
|
||||
subviewsSkeletonables.recursiveSearch(leafBlock: {
|
||||
showSkeletonIfNotActive(skeletonConfig: config)
|
||||
}){ subview in
|
||||
}) { subview in
|
||||
subview.recursiveShowSkeleton(skeletonConfig: config)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ extension CALayer {
|
||||
switch transition {
|
||||
case .none:
|
||||
completion?()
|
||||
break
|
||||
case .crossDissolve(let duration):
|
||||
layer.contentLayer.setOpacity(from: 0, to: 1, duration: duration, completion: completion)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user