Compare commits
583 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6887600a88 | |||
| f3baeedc14 | |||
| 29f7d8fd6a | |||
| 83e1600a73 | |||
| 450cecbd9c | |||
| 1676f8720a | |||
| 32ab6d3852 | |||
| 301ad0c040 | |||
| 3131dc829d | |||
| 7ce5e0623a | |||
| f0c7d2d6a0 | |||
| 26476fd3ed | |||
| f0c2cf4ab4 | |||
| cadf8bb136 | |||
| 91c8f953ca | |||
| 0a91aebf2a | |||
| 7d8a057b64 | |||
| 06f7d240ff | |||
| c4c725eea3 | |||
| cc9dbdb499 | |||
| c6dfcf9c1a | |||
| dd7e5243bd | |||
| 7e002ddce0 | |||
| 6dcfb325dc | |||
| 7b5739295a | |||
| 2e1808ea50 | |||
| cec3aeb781 | |||
| b16400294d | |||
| abb8ea55f6 | |||
| c833da20f8 | |||
| 292fadf5b0 | |||
| 2ce041901c | |||
| 961cc77661 | |||
| 11b623fb13 | |||
| 4899802b01 | |||
| 0dfe1ca43b | |||
| 499d01c232 | |||
| f8f368ab8a | |||
| 023a57a763 | |||
| d426a0916e | |||
| 611c248c51 | |||
| 6f20c34d56 | |||
| be25b572f8 | |||
| 3c67812453 | |||
| 0431eb2a7d | |||
| fa0b95d923 | |||
| 523cd1c657 | |||
| 29e65c70d3 | |||
| 4b7360a011 | |||
| 2753c54216 | |||
| c7b3bc67be | |||
| 0c8bbf1fed | |||
| 2e99bc98bf | |||
| d5d52d1416 | |||
| 91c7735d0c | |||
| 18c5c1deb8 | |||
| 1ecfa31743 | |||
| 82b70ea1ee | |||
| d8ee06f1c5 | |||
| 13ce7426dd | |||
| 7d5039536c | |||
| b7a7731784 | |||
| 07f92d098a | |||
| f45405c9d5 | |||
| 768354ca35 | |||
| d5819763a1 | |||
| a73fc993aa | |||
| 0d027b5927 | |||
| bc482f58b3 | |||
| 78e941e01c | |||
| 7282008606 | |||
| 52d657faa0 | |||
| cba096becf | |||
| c095f49028 | |||
| 89e292c11b | |||
| 5089295771 | |||
| 39971af22d | |||
| 81d182259d | |||
| 1d82545a3d | |||
| 9086d7e874 | |||
| 666ebdf472 | |||
| 5a5d7b66e7 | |||
| 78f2bbe9f1 | |||
| c7133a6711 | |||
| aee5cdfd8f | |||
| 638c535767 | |||
| 782dd45b33 | |||
| 073baa6483 | |||
| a26dbf7c89 | |||
| 7ebde2b030 | |||
| 4009ed2b1e | |||
| a246c16cfe | |||
| ef8e4578d7 | |||
| 46e2180c4b | |||
| f32c420165 | |||
| 0ca38d8ea1 | |||
| 9ed337ba53 | |||
| 932a1f6e6e | |||
| 5cd08fb77c | |||
| f7cb021a93 | |||
| 4fbfbeca55 | |||
| c92461ae5c | |||
| efed2e7f32 | |||
| 52cbd3ae2c | |||
| a349f7174c | |||
| a58c97eb1a | |||
| 8e6fea2de3 | |||
| bf417d6bf8 | |||
| c3295531be | |||
| a87f7302c0 | |||
| 5e22f38454 | |||
| 0dbdb9064d | |||
| c8efc4ccb1 | |||
| 01733b358c | |||
| 027143499c | |||
| ae1b5ee790 | |||
| 0c0a0ea451 | |||
| 8d090904b4 | |||
| 8d00d5fa16 | |||
| f2bc1cab27 | |||
| 83b99f16b1 | |||
| 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 | |||
| b93bae7b49 | |||
| 013cc025a1 | |||
| cc0cdf548e | |||
| 20d171f0db | |||
| ed563a29d7 | |||
| 38f9379aa5 | |||
| d94517939a | |||
| 65e86056cf | |||
| a0b01915fb | |||
| f16f4044d7 | |||
| ad28803221 | |||
| a6a988d169 | |||
| 3b17dbe7f2 | |||
| 06002ac2e2 | |||
| 060c66ecf9 | |||
| b3c25674ed | |||
| 7585d068f4 | |||
| 29c4ab8351 | |||
| 90b423c893 | |||
| 1184453782 | |||
| 33108b2a87 | |||
| e4cde53d73 | |||
| 7a35023c2d | |||
| d66c8c3f4d | |||
| fe195036cc | |||
| ac5c7b65f4 | |||
| 828a3a9655 | |||
| 8b9c1e387f | |||
| 88d7d7ea18 | |||
| d5639c6195 | |||
| c473f0c499 | |||
| a7c884771b | |||
| e291ab5da1 | |||
| e1a99a7ec1 | |||
| 0b5d6189b1 | |||
| 47a15e4c6d | |||
| 1f81365096 | |||
| 8e49eb305d | |||
| d09a5d75ee | |||
| 8ab04f8108 | |||
| f5d0620a57 | |||
| 8ddd4ccd27 | |||
| 57aa984a01 | |||
| 7a0c45a47e | |||
| 30fd5aa762 | |||
| 14b0248612 | |||
| 6b914ba1d5 | |||
| 3dac6c7f2f | |||
| 1a6ab34e7b | |||
| 601dc7a4e0 | |||
| ec3398bda0 | |||
| 5a75e00604 | |||
| 906c1845d3 | |||
| 8a2a512bbb | |||
| e6eb35e139 | |||
| 9c66a4b74c | |||
| 0d5c0a228b | |||
| 440e5ba022 | |||
| 26191ceb46 | |||
| 147ebd0365 | |||
| cd07ce7314 | |||
| 51ceb81f29 | |||
| 9d4e7688a3 | |||
| 6fc98f08d1 | |||
| 64cf3b07a2 | |||
| ba889f68c9 | |||
| e0134c3ee1 | |||
| f393954a96 | |||
| eff72e6a93 | |||
| f60982bb0e | |||
| 194e2ddaaf | |||
| 62401d502f | |||
| e54d458433 | |||
| 06085089fb | |||
| fd7ce7320e | |||
| 2538a62c03 | |||
| d0eeb5f42f | |||
| db1d8d7f4e | |||
| 43b64f8b30 | |||
| 5925d86d3f | |||
| 3a234048d4 | |||
| bea8fe7174 | |||
| b87a6e1d3c | |||
| c51f495410 | |||
| b279b8978a | |||
| 58dfa91ae6 | |||
| 42095e776b | |||
| 255479098f | |||
| 3a722b8a41 | |||
| 3ac931e15d | |||
| dfb538e233 | |||
| 27fab8f9e4 | |||
| 3ff87e0378 | |||
| ce83751152 | |||
| ecc90853e5 | |||
| 0799437dd7 | |||
| 89a098ea44 | |||
| 5a59fe1ed1 | |||
| c7bf9fdc10 | |||
| ec15de8ec7 | |||
| dd6d5b0e7d | |||
| d5165fe013 | |||
| 544f1ad66f | |||
| 744098d641 | |||
| 1fd952ced8 | |||
| 3840dc6cb5 | |||
| 23a77fd90f | |||
| 8d19f844f7 | |||
| 89858a4e25 | |||
| d32ea14495 | |||
| 815f17145c | |||
| 86cbaa2d72 | |||
| c206e48732 | |||
| fb835a438b | |||
| 9f73a137c6 | |||
| 83ecd7110d | |||
| 2dbc82ccc9 | |||
| 2e40eec3b3 | |||
| 3fe5629ca3 | |||
| bde2452bc9 | |||
| d030c80b05 | |||
| f082bfbcc3 | |||
| 0d8313cd7e | |||
| a338ffa9ae | |||
| 809dc4a9ba | |||
| b040f4771c | |||
| b938eddb87 | |||
| 01fe85b95c | |||
| f538673b53 | |||
| 898f7e4de4 | |||
| 570f059615 | |||
| 9a106d1af2 | |||
| 5544acc63e | |||
| 65299378c4 | |||
| d8f1b4c53b | |||
| d2d8c1f5db | |||
| ab385e5afb | |||
| 5d8cd9432e | |||
| fbaf2e7b4b | |||
| 97d83c7038 | |||
| ce83713240 | |||
| 56d3156f8e | |||
| aeb9dcf2c7 | |||
| 9914be0f5b | |||
| 7d0609098c | |||
| ec7a9973c5 | |||
| 06a9fb769e | |||
| d2797238f2 | |||
| b431aabddb | |||
| 0091ffc08b | |||
| e948e313a1 | |||
| a7ae5f0f9f | |||
| 85cce0cd7c | |||
| 3afe7286a2 | |||
| 3d8612ec0e | |||
| 6f1db7e303 | |||
| c1815642db | |||
| a6a168a919 | |||
| d0dbd1e004 | |||
| 4ade8f8797 | |||
| 264195bf16 | |||
| 11cc9a3ff7 | |||
| 37ac7d6e5d | |||
| a1e183a5e1 | |||
| 420785502b | |||
| eed18e5372 | |||
| 0a86ac4a9c | |||
| 264b0a70c2 | |||
| 01d68190ab | |||
| 2d57efd9cb | |||
| da51a6f673 | |||
| f6d4343cc6 | |||
| c6e20aa1a0 | |||
| 809544066f | |||
| 9406e3ef62 | |||
| 6d4c7d76c3 | |||
| f580fdaac2 | |||
| 4be93db383 | |||
| ae4ecfa760 | |||
| f60e5cd7ae | |||
| e097385de9 | |||
| 84d8971aa2 | |||
| 5384fd34dd | |||
| 53d965e151 | |||
| 04678fc772 | |||
| 46da5ab6fa | |||
| 45871be409 | |||
| 93f54dcc4d | |||
| 3bf3038941 | |||
| df1454c749 | |||
| 8212fc1a0b | |||
| e4b9416667 | |||
| f6f001068d | |||
| cb4ddd487a | |||
| 18cd0f9aba | |||
| 731509a46f | |||
| 7833c94f2e | |||
| 71d3e72eec | |||
| a0a2ae760b | |||
| 71d40d24b2 | |||
| 4236e9d424 | |||
| 19b88fce3e | |||
| b200a1ff3a | |||
| d9408d59b4 | |||
| 5a0f6e2314 | |||
| 3f7505bed9 | |||
| 5436e44f15 | |||
| 2f2e542d51 | |||
| 15764debf0 | |||
| bcd0fa7983 | |||
| 4cdc5935fc | |||
| 93769902a3 | |||
| a1d54a448d | |||
| cc8d21e7af | |||
| 69a0c8319d | |||
| 3c173c0a23 | |||
| dce910d6d0 | |||
| 2f751b9036 | |||
| fdd17dd4e9 | |||
| 978fd553e1 | |||
| 14ef5012f3 | |||
| e62c7d8c0e | |||
| e7aa9da5ae | |||
| 09a30d36b8 | |||
| d5656b9715 | |||
| 66dc7e89c5 | |||
| 5c815d7647 | |||
| aa60f82c81 | |||
| 6676760860 | |||
| b571988fad | |||
| abd9130ff6 | |||
| fc9dca1730 | |||
| 46a95eecb4 | |||
| e08e563ec0 | |||
| 1c24785ed6 | |||
| bbcaeedd19 | |||
| 6fc8f5caea | |||
| ab6efd1504 | |||
| 6632f5d91e | |||
| c1a47f098b | |||
| 02be363c95 | |||
| cb0e4c63cf | |||
| 26d839387d | |||
| e05d013af8 | |||
| d8a5df75ee | |||
| f7eb048317 | |||
| 4497e5cdb9 | |||
| e83ab2e033 | |||
| d40a877c42 | |||
| 3b6c61cfcb | |||
| f42b77fd4d | |||
| c75df015d8 | |||
| 0393c04aa8 | |||
| c3df0bc5df | |||
| 0f0bb220f2 | |||
| a299c8c0c8 | |||
| aea2ae6793 | |||
| a3ed33f53b | |||
| 6cf19ca50d | |||
| ca0b295a80 | |||
| 60c387b250 | |||
| 5b3bc204bf | |||
| 1eece8e013 | |||
| d665d01469 | |||
| 623b326e7b | |||
| 3a4bbadcbe | |||
| dc92e652cb | |||
| e3f38fdd25 | |||
| 6c1c4dda42 | |||
| 39c60b6da2 | |||
| c75d34e7de | |||
| c5a0bc0050 | |||
| be74f093f3 | |||
| 0f90edfc8e | |||
| 67daffd7c9 | |||
| 961c731888 | |||
| 39fa679ddc | |||
| 40c107af23 | |||
| 0781fceab7 | |||
| eef7a87eb6 | |||
| be25db821b | |||
| 9e014dab0e | |||
| f53b722b52 | |||
| bd02497124 | |||
| 1802e76da9 | |||
| 318b2546c6 | |||
| 37df94b09f | |||
| 81599f2980 | |||
| b28358663b | |||
| b364218213 | |||
| 18048c9bcd | |||
| 510fe34476 | |||
| 932579edc0 | |||
| 96673df005 | |||
| 43c1f2e5ac | |||
| 37f6205421 | |||
| 3471288307 | |||
| b77edf84b2 | |||
| 3e87293a84 | |||
| f637c20ea9 | |||
| 1737536057 | |||
| 31fe04b92e | |||
| f7d577c269 | |||
| 3a7be98057 | |||
| dab24e40a7 | |||
| c729dec667 | |||
| f6f0a11968 | |||
| 6784de9597 | |||
| 6e91b3fa71 | |||
| 4b6f55cf66 | |||
| beaf22d696 | |||
| c62586ccff | |||
| 55cb95e3fa | |||
| d72b28dc53 | |||
| b742179fec | |||
| f2b0329db9 | |||
| 8271110682 | |||
| 096099e2a0 | |||
| 4d4fda2177 | |||
| 4296d1cb04 | |||
| db19eae968 | |||
| 1d2256b4e6 | |||
| 4e5c8627dd | |||
| 6012b0c84b | |||
| 09e1fe31e0 | |||
| 4fb8020c83 | |||
| 303ae5aeb8 | |||
| 4649c7e61f | |||
| 1671af6d28 | |||
| 83e7e48caa | |||
| c03af15070 | |||
| ed82f74ba8 | |||
| 01aba0b3ff | |||
| 6352030012 | |||
| 4b06c30b9d | |||
| 3dcde46fe9 | |||
| c9de28eb37 | |||
| 915e838994 | |||
| 74b44264ec | |||
| a9ad72aa0c | |||
| d535529be8 | |||
| a6bff05ca4 | |||
| bc98cd600e | |||
| 8f1cfc0045 | |||
| 432ec6caa2 | |||
| e18aedbbf8 | |||
| 4dc67ac3d7 | |||
| aa29cd3d6b | |||
| a2def55880 | |||
| 97f5e3e2e1 | |||
| 420cc7a669 | |||
| b9601f56c3 | |||
| fbca1092c3 | |||
| eb90faf413 | |||
| f0cc7125ef | |||
| f5b493d6f0 | |||
| 48bc217413 | |||
| 516fcecce2 | |||
| 9052d5d806 | |||
| 12dff52238 | |||
| f0b4575de6 | |||
| 7be8ddd70a | |||
| a9628c0de8 | |||
| 339191f016 | |||
| 7022942d92 | |||
| 03cf1bfea8 | |||
| 9f46e7a647 | |||
| 674cd1aa9f | |||
| 36a863b557 | |||
| 3b83b85249 | |||
| afbb10d785 | |||
| 99ccd1e640 | |||
| e6834d1296 | |||
| 89cb6f4116 | |||
| b74592e6be | |||
| 5f79708f03 | |||
| a83e1a00bf | |||
| 61e98b26ad | |||
| 0ec754dfc5 | |||
| 78b4b7b31c | |||
| e3ddc4fe98 | |||
| 13485e61f7 | |||
| 8f5d409304 | |||
| bc3258b8a2 | |||
| fd4683f555 | |||
| 97ebbcc917 | |||
| a02922dba6 | |||
| 4ac1abe50e | |||
| 25e313850e | |||
| 88914f7816 | |||
| 14ab00d13a | |||
| 90b993a16b | |||
| 413867718e | |||
| e43b3f3750 | |||
| b9b368b7e8 | |||
| fc22d58f89 | |||
| 8988b22784 | |||
| 3cb1602e11 | |||
| 649672182e | |||
| 3c16416dbb | |||
| 0eff052314 |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"SWIFT": {
|
||||
"TOO_MANY_FUNCTIONS": [50, 100, 150, 200],
|
||||
"TOTAL_LOC": [200, 400, 500, 600]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
github: [juanpe]
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
name: "\U0001F41B Bug report"
|
||||
about: Report a bug or unexpected behavior while using SkeletonView
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Description
|
||||
|
||||
Describe your issue here.
|
||||
|
||||
### What type of issue is this? (place an `x` in one of the `[ ]`)
|
||||
- [ ] bug
|
||||
- [ ] enhancement (feature request)
|
||||
- [ ] question
|
||||
- [ ] documentation related
|
||||
- [ ] discussion
|
||||
|
||||
### Requirements (place an `x` in each of the `[ ]`)
|
||||
* [ ] I've read and understood the [Contributing guidelines](https://github.com/Juanpe/SkeletonView/blob/main/CONTRIBUTING.md) and have done my best effort to follow them.
|
||||
* [ ] I've read and agree to the [Code of Conduct](https://github.com/Juanpe/SkeletonView/blob/main/CODE_OF_CONDUCT.md).
|
||||
* [ ] I've searched for any related issues and avoided creating a duplicate issue.
|
||||
|
||||
---
|
||||
|
||||
### Bug Report
|
||||
|
||||
Filling out the following details about bugs will help us solve your issue sooner.
|
||||
|
||||
### 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,28 @@
|
||||
---
|
||||
name: "\U0001F4E3 Feedback"
|
||||
about: Give us general feedback about the SkeletonView
|
||||
title: ''
|
||||
labels: feedback
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
# SkeletonView Feedback
|
||||
|
||||
You can use this template to give us structured feedback or just wipe it and leave us a note. Thank you!
|
||||
|
||||
## What have you loved?
|
||||
|
||||
_eg "the nice colors"_
|
||||
|
||||
## What was confusing or gave you pause?
|
||||
|
||||
_eg "it did something unexpected"_
|
||||
|
||||
## Are there features you'd like to see added?
|
||||
|
||||
_eg "SkeletonView should be compatible with SwiftUI"_
|
||||
|
||||
## Anything else?
|
||||
|
||||
_eg "have a nice day"_
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: "⭐ Submit a request"
|
||||
about: Surface a feature or problem that you think should be solved
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Describe the feature or problem you’d like to solve
|
||||
|
||||
A clear and concise description of what the feature or problem is.
|
||||
|
||||
### Proposed solution
|
||||
|
||||
How will it benefit SkeletonView and its users?
|
||||
|
||||
### Additional context
|
||||
|
||||
Add any other context like screenshots or mockups are helpful, if applicable.
|
||||
@@ -1,25 +0,0 @@
|
||||
⚠️ Please fill out this template when filing an issue.
|
||||
|
||||
#### 🙏🏼 *Please check if it already exists other issue related with yours.*
|
||||
|
||||
### What did you do?
|
||||
|
||||
*Please replace this with what you did.*
|
||||
|
||||
### What did you expect to happen?
|
||||
|
||||
*Please replace this with what you expected to happen.*
|
||||
|
||||
### What happened instead?
|
||||
|
||||
*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 version:**
|
||||
**Xcode version:**
|
||||
**Swift version:**
|
||||
@@ -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/main/CONTRIBUTING.md) and have done my best effort to follow them.
|
||||
* [ ] I've read and agree to the [Code of Conduct](https://github.com/Juanpe/SkeletonView/blob/main/CODE_OF_CONDUCT.md).
|
||||
@@ -0,0 +1,39 @@
|
||||
name-template: '📦 $RESOLVED_VERSION'
|
||||
tag-template: '$RESOLVED_VERSION'
|
||||
category-template: '#### $TITLE'
|
||||
change-template: '- **#$NUMBER**: $TITLE - @$AUTHOR'
|
||||
template: |
|
||||
$CHANGES
|
||||
categories:
|
||||
- title: '🚨 Breaking'
|
||||
label: 'breaking'
|
||||
- title: '🔬Improvements'
|
||||
label: '💡 enhancement'
|
||||
- title: '🙌 New'
|
||||
label: 'feature'
|
||||
- title: '🩹 Bug fixes'
|
||||
label: '🐞 bug'
|
||||
- title: '⚙️ Maintenance'
|
||||
label: '⚙️ maintenance'
|
||||
- title: '📚 Documentation'
|
||||
label: '📚 docs'
|
||||
- title: '💾 Dependency Updates'
|
||||
label: 'dependencies'
|
||||
|
||||
version-resolver:
|
||||
major:
|
||||
labels:
|
||||
- 'breaking'
|
||||
minor:
|
||||
labels:
|
||||
- '💡 enhancement'
|
||||
- 'feature'
|
||||
patch:
|
||||
labels:
|
||||
- '🐞 bug'
|
||||
- '⚙️ maintenance'
|
||||
- '📚 docs'
|
||||
- 'dependencies'
|
||||
|
||||
exclude-labels:
|
||||
- 'skip-changelog'
|
||||
@@ -0,0 +1,10 @@
|
||||
daysUntilStale: 7
|
||||
daysUntilClose: 7
|
||||
onlyLabels:
|
||||
- awaiting user input
|
||||
staleLabel: given up
|
||||
markComment: >
|
||||
🤖 This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions 🙂
|
||||
closeComment: false
|
||||
@@ -0,0 +1,19 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
build-config:
|
||||
- { target: 'SkeletonView-iOS', destination: 'platform=iOS Simulator,name=iPhone 8', sdk: 'iphonesimulator' }
|
||||
- { target: 'SkeletonView-tvOS', destination: 'platform=tvOS Simulator,name=Apple TV', sdk: 'appletvsimulator' }
|
||||
- { target: 'SkeletonViewExample', destination: 'platform=iOS Simulator,name=iPhone 8', sdk: 'iphonesimulator' }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: xcodebuild clean -target '${{ matrix.build-config['target'] }}' -sdk '${{ matrix.build-config['sdk'] }}' -destination '${{ matrix.build-config['destination'] }}'
|
||||
@@ -0,0 +1,14 @@
|
||||
name: Pod lint
|
||||
on: [workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
pod_lib_lint:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- env:
|
||||
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
|
||||
run: |
|
||||
set -eo pipefail
|
||||
pod lib lint --allow-warnings
|
||||
@@ -0,0 +1,38 @@
|
||||
name: Release
|
||||
on: [workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
release_version:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup fastlane
|
||||
run: brew install fastlane
|
||||
|
||||
- name: Publish release
|
||||
id: publish_release
|
||||
uses: release-drafter/release-drafter@v5
|
||||
with:
|
||||
publish: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Update podspec
|
||||
run: fastlane bump_version next_version:${{ steps.publish_release.outputs.tag_name }}
|
||||
|
||||
- name: Commit changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v4
|
||||
with:
|
||||
branch: 'main'
|
||||
commit_message: 'Bump version ${{ steps.publish_release.outputs.tag_name }}'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Deploy to Cocoapods
|
||||
env:
|
||||
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
|
||||
run: |
|
||||
set -eo pipefail
|
||||
pod lib lint --allow-warnings
|
||||
pod trunk push --allow-warnings
|
||||
@@ -0,0 +1,14 @@
|
||||
name: Release Notes
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
update_release_notes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Validations
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
branches: [main]
|
||||
types: [opened, reoneped, edited, synchronized]
|
||||
|
||||
# workflow_dispatch:
|
||||
# inputs:
|
||||
# commit hash:
|
||||
# description: "Commit hash"
|
||||
# required: true
|
||||
# default: ""
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run SwiftLint
|
||||
run: swiftlint lint --reporter github-actions-logging
|
||||
|
||||
danger:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Danger
|
||||
uses: docker://frmeloni/danger-swift-with-swiftlint:1.3.1
|
||||
with:
|
||||
args: --failOnErrors --verbose
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ playground.xcworkspace
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
# Pods/
|
||||
Pods/
|
||||
|
||||
# Carthage
|
||||
#
|
||||
@@ -66,3 +66,7 @@ fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
|
||||
# JetBrains
|
||||
|
||||
.idea
|
||||
|
||||
@@ -1 +1 @@
|
||||
4.1
|
||||
5.3
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
included:
|
||||
- Sources
|
||||
disabled_rules:
|
||||
- trailing_whitespace
|
||||
- line_length
|
||||
- type_body_length
|
||||
- identifier_name
|
||||
- multiple_closures_with_trailing_closure
|
||||
- class_delegate_protocol
|
||||
- force_unwrapping
|
||||
- force_try
|
||||
- force_cast
|
||||
- function_parameter_count
|
||||
- discouraged_optional_collection
|
||||
- shorthand_operator
|
||||
- reduce_boolean
|
||||
- weak_delegate
|
||||
- nesting
|
||||
- closure_end_indentation
|
||||
- function_default_parameter_at_end
|
||||
- unowned_variable_capture
|
||||
- legacy_constructor
|
||||
opt_in_rules:
|
||||
- multiline_arguments
|
||||
- multiline_parameters
|
||||
- closure_spacing
|
||||
- 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
|
||||
- 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
|
||||
- unused_declaration
|
||||
- unused_import
|
||||
- vertical_whitespace_opening_braces
|
||||
- discouraged_optional_collection
|
||||
- enum_case_associated_values_counts
|
||||
- legacy_multiple
|
||||
- legacy_random
|
||||
indentation: 2
|
||||
file_length:
|
||||
- 2500
|
||||
- 3000
|
||||
large_tuple:
|
||||
- 5
|
||||
- 6
|
||||
@@ -1,7 +0,0 @@
|
||||
language: objective-c
|
||||
osx_image: xcode9.3
|
||||
script:
|
||||
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonView-iOS -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=11'
|
||||
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonView-tvOS -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV,OS=11'
|
||||
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonViewExample -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=11'
|
||||
after_success:
|
||||
|
After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 388 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 228 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 267 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 29 KiB |
@@ -1,103 +1,245 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file
|
||||
|
||||
## [Custom defaults (1.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.3)
|
||||
### Next version
|
||||
|
||||
### New
|
||||
#### 🙌 New
|
||||
|
||||
#### 🔬 Improvements
|
||||
* [**369**](https://github.com/Juanpe/SkeletonView/pull/369): remove useless corner radius constraint - [@Juanpe](https://github.com/Juanpe)
|
||||
* [**357**](https://github.com/Juanpe/SkeletonView/pull/357): Removed duplicate code in SkeletonCollectionDelegate. - [@keshavamurthy1](https://github.com/keshavamurthy1)
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
* [**359**](https://github.com/Juanpe/SkeletonView/pull/359): SkeletonView respecting Font's height, rather than the `UIView` actual height. - [@keshavamurthy1](https://github.com/keshavamurthy1)
|
||||
|
||||
|
||||
## 📦 [1.11.0](https://github.com/Juanpe/SkeletonView/releases/tag/1.11.0)
|
||||
|
||||
#### 🙌 New
|
||||
* [**339**](https://github.com/Juanpe/SkeletonView/pull/339): Add `hiddenWhenSkeletonIsActive` property - [@mohn93](https://github.com/mohn93)
|
||||
* [**341**](https://github.com/Juanpe/SkeletonView/pull/341): Support autoreverses in gradient animations - [@Juanpe](https://github.com/Juanpe)
|
||||
|
||||
#### 🔬Improvements
|
||||
* [**344**](https://github.com/Juanpe/SkeletonView/pull/344): Resize labels based on number of lines - [@Juanpe](https://github.com/Juanpe)
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
* [**340**](https://github.com/Juanpe/SkeletonView/pull/340): Fixed incorrect padding, and incorrect multiline layer frame calculation - [@yzhao198](https://github.com/yzhao198)
|
||||
|
||||
## 📦 [1.10.0](https://github.com/Juanpe/SkeletonView/releases/tag/1.10.0)
|
||||
|
||||
#### 🙌 New
|
||||
* [**327**](https://github.com/Juanpe/SkeletonView/pull/327): Add SwiftLint - [@Juanpe](https://github.com/Juanpe)
|
||||
* [**329**](https://github.com/Juanpe/SkeletonView/pull/329): Spanish README 🇪🇸 - [@Juanpe](https://github.com/Juanpe)
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
* [**336**](https://github.com/Juanpe/SkeletonView/pull/336): Not replace text when the skeleton disappears. Solved issues: [#296](https://github.com/Juanpe/SkeletonView/issues/296), [#330](https://github.com/Juanpe/SkeletonView/issues/330) - [@Juanpe](https://github.com/Juanpe)
|
||||
* [**337**](https://github.com/Juanpe/SkeletonView/pull/337): RTL support. Solved issues: [#143](https://github.com/Juanpe/SkeletonView/issues/143) - [@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)
|
||||
|
||||
#### 🔬Improvements
|
||||
* [**311**](https://github.com/Juanpe/SkeletonView/pull/311): Bump json from 2.2.0 to 2.3.1 - [@dependabot](https://github.com/dependabot)
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
* [**286**](https://github.com/Juanpe/SkeletonView/pull/286): Fix issue when WKWebView calls skeletonLayoutSubviews not on the main thread - [@paulanatoleclaudot-betclic](https://github.com/paulanatoleclaudot-betclic)
|
||||
* [**292**](https://github.com/Juanpe/SkeletonView/pull/292): Fix IBInspectable support when using Carthage - [@marisalaneous](https://github.com/marisalaneous)
|
||||
* [**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)
|
||||
|
||||
#### 🔬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)
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
* [**259**](https://github.com/Juanpe/SkeletonView/issues/259): Prevent isSkeletonActive to be called when isSkeletonable is false - [@wsalim1610](https://github.com/wsalim1610)
|
||||
* [**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)
|
||||
|
||||
#### 🔬Improvements
|
||||
* [**242**](https://github.com/Juanpe/SkeletonView/pull/242): Offscreen table view layout issue fixed - [@Cacodemon](https://github.com/Cacodemon)
|
||||
* [**261**](https://github.com/Juanpe/SkeletonView/pull/261): Fixes removing skeleton layers from table header footer sections - [@darkside999](https://github.com/darkside999)
|
||||
* [**263**](https://github.com/Juanpe/SkeletonView/pull/263): Feature/set cross dissolve transitions as default - [@Juanpe](https://github.com/Juanpe)
|
||||
* [**264**](https://github.com/Juanpe/SkeletonView/pull/264): not replace original datasource is running XCTests - [@Juanpe](https://github.com/Juanpe)
|
||||
* [**265**](https://github.com/Juanpe/SkeletonView/pull/265): call original traitCollectionDidChange method - [@Juanpe](https://github.com/Juanpe)
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
* [**260**](https://github.com/Juanpe/SkeletonView/issues/260): Don't hide skeleton layers on TableViewHeaderFooterView
|
||||
* [**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)
|
||||
|
||||
- Support for iOS 13 dark mode. (thanks @Wilsonator5000)
|
||||
|
||||
## 📦 [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)
|
||||
|
||||
#### 🔬Improvements
|
||||
- Fix completion call in .none transition style while hide skeletons. (thanks @aadudyrev)
|
||||
|
||||
#### 🙌 New
|
||||
- Swizzle `layoutSubviews` method.
|
||||
|
||||
#### 🔬Improvements
|
||||
- Fix completion call in .none transition style while hiding skeletons. (thanks @aadudyrev)
|
||||
- Swift format.
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
- Update layout subviews when the original method is called.
|
||||
- Issues: [#88, #149]
|
||||
|
||||
## 📦 [Transitions (1.8)](https://github.com/Juanpe/SkeletonView/releases/tag/1.8)
|
||||
|
||||
#### 🙌 New
|
||||
|
||||
- Adding swift news to mentioned section (thanks @osterbergmarcus).
|
||||
- Create `SkeletonTransitionStyle`. Now, you can animate transition when you show or hide skeletons. (thanks @pontusjacobsson)
|
||||
|
||||
#### 🔬Improvements
|
||||
- Refactor some methods.
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
- 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)
|
||||
|
||||
#### 🙌 New
|
||||
|
||||
- Allow updating skeleton layout to recalculate skeleton bounds: `layoutSkeletonIfNeeded`. See the examples to know how to use it. (thanks @eduardbosch)
|
||||
|
||||
#### 🔬Improvements
|
||||
|
||||
- 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)
|
||||
|
||||
#### 🙌 New
|
||||
|
||||
- Create `skeletonDescription` print a skeleton representation of the view.
|
||||
- Create `SKELETON_DEBUG` environment variable, in order to print the view hierarchy when the skeleton appears.
|
||||
|
||||
#### 🔬Improvements
|
||||
- Add two new methods to `SkeletonFlowDelegate` protocol. Now you can know when the skeleton did show and when it did hide.
|
||||
- `Recursive` protocol
|
||||
|
||||
#### 🩹 Bug fixes
|
||||
- Solved issue [#86](https://github.com/Juanpe/SkeletonView/issues/86) (thanks @reececomo)
|
||||
|
||||
## 📦 [Custom defaults (1.3)](https://github.com/Juanpe/SkeletonView/releases/tag/1.3)
|
||||
|
||||
#### 🙌 New
|
||||
|
||||
- Default values customizables. Now you can set the default values of Skeleton appearance.(thanks @reececomo)
|
||||
- issues: [[#50](https://github.com/Juanpe/SkeletonView/issues/50), [#83](https://github.com/Juanpe/SkeletonView/issues/83)]
|
||||
|
||||
### Bug fixes
|
||||
#### 🩹 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
|
||||
#### Fixes
|
||||
|
||||
- Fix typo in `SkeletonTableViewDataSource` protocol
|
||||
|
||||
### Improvements
|
||||
#### 🔬Improvements
|
||||
|
||||
- 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
|
||||
#### 🙌 New
|
||||
|
||||
- Rebranding
|
||||
|
||||
### Bug fixes
|
||||
#### 🩹 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
|
||||
#### 🙌 New
|
||||
|
||||
- You can set the corner radius multiline elements (thanks @B4V4-G)
|
||||
- Save view state when skeleton appears and recovery when it is hidden (@juanpe)
|
||||
|
||||
### Bug fixes
|
||||
#### 🩹 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
|
||||
#### 🙌 New
|
||||
- Now ```SkeletonView``` is **tvOS** compatible! 🎉. (thanks @mihai8804858)
|
||||
|
||||
### Bug fixes
|
||||
#### 🩹 Bug fixes
|
||||
- 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
|
||||
#### 🩹 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
|
||||
#### 🙌 New
|
||||
- Now ```SkeletonView```supports **UICollectionViews**! 🎉. (thanks @Renatdz)
|
||||
|
||||
### Bug fixes
|
||||
#### 🩹 Bug fixes
|
||||
- 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
|
||||
#### 🙌 New
|
||||
- Now you can use table views with resizable cells.
|
||||
|
||||
### Bug fixes
|
||||
#### 🩹 Bug fixes
|
||||
- Solved issues.
|
||||
[#17](https://github.com/Juanpe/SkeletonView/issues/17),
|
||||
[#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
|
||||
#### 🙌 New
|
||||
- You can set the filling percent of the last line in multiline elements (thanks @jontelang!)
|
||||
|
||||
### Bug fixes
|
||||
#### 🩹 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
|
||||
#### 🙌 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
|
||||
#### 🙌 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
|
||||
#### 🩹 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
|
||||
|
||||
@@ -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.
|
||||
@@ -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/main/CODE_OF_CONDUCT.md). We take it very seriously, and expect that you will as
|
||||
well.
|
||||
|
||||
There are many ways you can contribute! :heart:
|
||||
|
||||
### 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 `main` 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,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,34 @@
|
||||
import Danger
|
||||
|
||||
let danger = Danger()
|
||||
let github = danger.github
|
||||
|
||||
// Make it more obvious that a PR is a work in progress and shouldn't be merged yet
|
||||
if danger.github.pullRequest.title.contains("WIP") {
|
||||
warn("PR is classed as Work in Progress")
|
||||
}
|
||||
|
||||
// Warn, asking to update all README files if only English README are updated
|
||||
let enReameModified = danger.git.modifiedFiles.contains { $0.contains("README.md") }
|
||||
let zhReameModified = danger.git.modifiedFiles.contains { $0.contains("README_zh.md") }
|
||||
let koReameModified = danger.git.modifiedFiles.contains { $0.contains("README_ko.md") }
|
||||
let ptBrReameModified = danger.git.modifiedFiles.contains { $0.contains("README_pt-br.md") }
|
||||
let otherLanguagesReadmeHaveBeenModified = zhReameModified && koReameModified && ptBrReameModified
|
||||
|
||||
if (enReameModified && !otherLanguagesReadmeHaveBeenModified) {
|
||||
warn("Consider **also** updating the README for other languages.")
|
||||
}
|
||||
|
||||
// Warn when there is a big PR
|
||||
if (danger.github.pullRequest.additions ?? 0) > 500 {
|
||||
warn("Big PR, try to keep changes smaller if you can")
|
||||
}
|
||||
|
||||
// Added (or removed) library files need to be added (or removed) from the
|
||||
// Xcode project to avoid breaking things.
|
||||
let addedSwiftLibraryFiles = danger.git.createdFiles.contains { $0.fileType == .swift && $0.hasPrefix("Sources") }
|
||||
let deletedSwiftLibraryFiles = danger.git.deletedFiles.contains { $0.fileType == .swift && $0.hasPrefix("Sources") }
|
||||
let modifiedXcodeProject = danger.git.modifiedFiles.contains { $0.contains(".xcodeproj") }
|
||||
if (addedSwiftLibraryFiles || deletedSwiftLibraryFiles) && !modifiedXcodeProject {
|
||||
fail("Added or removed files require the Xcode project to be updated.")
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// SkeletonViewExampleUICollectionView
|
||||
//
|
||||
// Created by Andrei Hogea on 14/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,41 +0,0 @@
|
||||
//
|
||||
// CollectionViewCell.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Andrei Hogea on 14/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SkeletonView
|
||||
|
||||
class CollectionViewCell: UICollectionViewCell {
|
||||
|
||||
var label: UILabel!
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
isSkeletonable = true
|
||||
createLabel()
|
||||
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private func createLabel() {
|
||||
label = UILabel()
|
||||
label.isSkeletonable = true
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(label)
|
||||
NSLayoutConstraint.activate([
|
||||
label.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||
label.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
label.heightAnchor.constraint(equalToConstant: frame.height / 2),
|
||||
label.widthAnchor.constraint(equalToConstant: frame.width / 2)
|
||||
])
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
//
|
||||
// Constants.swift
|
||||
// SkeletonViewExampleUICollectionView
|
||||
//
|
||||
// Created by Andrei Hogea on 15/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
let colors = [(UIColor.turquoise,"turquoise"), (UIColor.emerald,"emerald"), (UIColor.peterRiver,"peterRiver"), (UIColor.amethyst,"amethyst"),(UIColor.wetAsphalt,"wetAsphalt"), (UIColor.nephritis,"nephritis"), (UIColor.belizeHole,"belizeHole"), (UIColor.wisteria,"wisteria"), (UIColor.midnightBlue,"midnightBlue"), (UIColor.sunFlower,"sunFlower"), (UIColor.carrot,"carrot"), (UIColor.alizarin,"alizarin"),(UIColor.clouds,"clouds"), (UIColor.concrete,"concrete"), (UIColor.flatOrange,"flatOrange"), (UIColor.pumpkin,"pumpkin"), (UIColor.pomegranate,"pomegranate"), (UIColor.silver,"silver"), (UIColor.asbestos,"asbestos")]
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="irH-dz-xqL">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="qda-qV-vJk">
|
||||
<objects>
|
||||
<viewController id="irH-dz-xqL" customClass="ViewController" customModule="SkeletonView" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Fso-nq-n6t">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="HKL-L0-T2w">
|
||||
<rect key="frame" x="0.0" y="243" width="375" height="284"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="mGU-kn-rfE">
|
||||
<size key="itemSize" width="50" height="50"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
</collectionViewFlowLayout>
|
||||
<cells/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="irH-dz-xqL" id="wya-hE-ovQ"/>
|
||||
</connections>
|
||||
</collectionView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JjA-MK-YzZ">
|
||||
<rect key="frame" x="0.0" y="527" width="375" height="140"/>
|
||||
<subviews>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="fMR-vj-7de">
|
||||
<rect key="frame" x="20" y="23" width="140" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="Solid"/>
|
||||
<segment title="Gradient"/>
|
||||
</segments>
|
||||
<connections>
|
||||
<action selector="changeSkeletonType:" destination="irH-dz-xqL" eventType="valueChanged" id="lfR-JV-DU4"/>
|
||||
</connections>
|
||||
</segmentedControl>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KBe-RM-BG8">
|
||||
<rect key="frame" x="310" y="21" width="49" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="changeAnimated:" destination="irH-dz-xqL" eventType="valueChanged" id="dlH-KK-iee"/>
|
||||
</connections>
|
||||
</switch>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Animated" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GSj-Ze-UIK">
|
||||
<rect key="frame" x="211" y="28" width="91" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Color" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4Hm-fj-45V">
|
||||
<rect key="frame" x="32" y="89" width="52" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HBJ-nh-56V">
|
||||
<rect key="frame" x="92" y="84" width="30" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aUR-Qo-gHK">
|
||||
<rect key="frame" x="20" y="74" width="140" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="btnChangeColorTouchUpInside:" destination="irH-dz-xqL" eventType="touchUpInside" id="Xca-QC-htl"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="140" id="QDV-wu-e3I"/>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="140" id="qR5-cz-YAm"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eHI-ka-8vS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="243"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="obr-b6-dib">
|
||||
<rect key="frame" x="45" y="142" width="287" height="78"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="78" id="jx6-c1-U0j"/>
|
||||
</constraints>
|
||||
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </string>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="lastLineFillPercent">
|
||||
<integer key="value" value="40"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</textView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar" translatesAutoresizingMaskIntoConstraints="NO" id="Ql9-Jy-aWM">
|
||||
<rect key="frame" x="141" y="20" width="93" height="93"/>
|
||||
<color key="backgroundColor" red="0.56078431370000004" green="0.59607843140000005" blue="0.7843137255" alpha="0.90709546230000004" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="93" id="jlG-7K-wMd"/>
|
||||
<constraint firstAttribute="width" constant="93" id="xHX-Y1-dvi"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="243" id="0g6-3g-uII"/>
|
||||
<constraint firstAttribute="trailing" secondItem="obr-b6-dib" secondAttribute="trailing" constant="43" id="3ms-Wk-qcn"/>
|
||||
<constraint firstItem="obr-b6-dib" firstAttribute="centerX" secondItem="eHI-ka-8vS" secondAttribute="centerX" constant="1" id="B5s-DM-eR8"/>
|
||||
<constraint firstAttribute="height" constant="243" id="GX5-3W-tUt"/>
|
||||
<constraint firstItem="Ql9-Jy-aWM" firstAttribute="centerX" secondItem="eHI-ka-8vS" secondAttribute="centerX" id="HsA-ID-oSK"/>
|
||||
<constraint firstItem="Ql9-Jy-aWM" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="top" constant="20" id="Hxu-ae-hXQ"/>
|
||||
<constraint firstItem="obr-b6-dib" firstAttribute="leading" secondItem="eHI-ka-8vS" secondAttribute="leading" constant="45" id="eop-Gq-7mO"/>
|
||||
<constraint firstItem="obr-b6-dib" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="top" constant="142" id="inJ-75-hGX"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="eHI-ka-8vS" firstAttribute="trailing" secondItem="2Gq-Y8-1TU" secondAttribute="trailing" id="0dc-Vd-yJY"/>
|
||||
<constraint firstItem="JjA-MK-YzZ" firstAttribute="leading" secondItem="2Gq-Y8-1TU" secondAttribute="leading" id="57i-UV-Wqd"/>
|
||||
<constraint firstItem="eHI-ka-8vS" firstAttribute="leading" secondItem="2Gq-Y8-1TU" secondAttribute="leading" id="5tt-Ne-67Y"/>
|
||||
<constraint firstItem="JjA-MK-YzZ" firstAttribute="bottom" secondItem="2Gq-Y8-1TU" secondAttribute="bottom" id="AAr-ke-R7M"/>
|
||||
<constraint firstItem="JjA-MK-YzZ" firstAttribute="trailing" secondItem="2Gq-Y8-1TU" secondAttribute="trailing" id="DtS-9c-zBC"/>
|
||||
<constraint firstItem="HKL-L0-T2w" firstAttribute="top" secondItem="eHI-ka-8vS" secondAttribute="bottom" id="Jgf-jS-PLT"/>
|
||||
<constraint firstItem="JjA-MK-YzZ" firstAttribute="top" secondItem="HKL-L0-T2w" secondAttribute="bottom" id="XEd-Gf-KFI"/>
|
||||
<constraint firstItem="2Gq-Y8-1TU" firstAttribute="trailing" secondItem="HKL-L0-T2w" secondAttribute="trailing" id="bNo-98-pE4"/>
|
||||
<constraint firstItem="HKL-L0-T2w" firstAttribute="leading" secondItem="2Gq-Y8-1TU" secondAttribute="leading" id="iIq-cx-paX"/>
|
||||
<constraint firstItem="eHI-ka-8vS" firstAttribute="top" secondItem="Fso-nq-n6t" secondAttribute="top" id="tlZ-Wl-lvE"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="2Gq-Y8-1TU"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="avatarImage" destination="Ql9-Jy-aWM" id="VoL-by-ygR"/>
|
||||
<outlet property="collectionView" destination="HKL-L0-T2w" id="HSe-j0-S5d"/>
|
||||
<outlet property="colorSelectedView" destination="HBJ-nh-56V" id="Iiq-iY-Glj"/>
|
||||
<outlet property="skeletonTypeSelector" destination="fMR-vj-7de" id="CgX-3A-weo"/>
|
||||
<outlet property="switchAnimated" destination="KBe-RM-BG8" id="emU-g9-NHT"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="PkM-Y0-M5i" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-972" y="-209.14542728635683"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="avatar" width="215" height="211"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -1,179 +0,0 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// SkeletonViewExampleUICollectionView
|
||||
//
|
||||
// Created by Andrei Hogea on 14/02/2018.
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SkeletonView
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var collectionView: UICollectionView! {
|
||||
didSet {
|
||||
collectionView.isSkeletonable = true
|
||||
collectionView.backgroundColor = .clear
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
|
||||
collectionView.dataSource = self
|
||||
collectionView.delegate = self
|
||||
|
||||
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var avatarImage: UIImageView! {
|
||||
didSet {
|
||||
avatarImage.layer.cornerRadius = avatarImage.frame.width/2
|
||||
avatarImage.layer.masksToBounds = true
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var colorSelectedView: UIView! {
|
||||
didSet {
|
||||
colorSelectedView.layer.cornerRadius = 5
|
||||
colorSelectedView.layer.masksToBounds = true
|
||||
colorSelectedView.backgroundColor = SkeletonAppearance.default.tintColor
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var switchAnimated: UISwitch!
|
||||
@IBOutlet weak var skeletonTypeSelector: UISegmentedControl!
|
||||
|
||||
var type: SkeletonType {
|
||||
return skeletonTypeSelector.selectedSegmentIndex == 0 ? .solid : .gradient
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.isSkeletonable = true
|
||||
collectionView.prepareSkeleton(completion: { done in
|
||||
self.view.showAnimatedSkeleton()
|
||||
})
|
||||
}
|
||||
|
||||
@IBAction func changeAnimated(_ sender: Any) {
|
||||
if switchAnimated.isOn {
|
||||
view.startSkeletonAnimation()
|
||||
} else {
|
||||
view.stopSkeletonAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func changeSkeletonType(_ sender: Any) {
|
||||
refreshSkeleton()
|
||||
}
|
||||
|
||||
@IBAction func btnChangeColorTouchUpInside(_ sender: Any) {
|
||||
showAlertPicker()
|
||||
}
|
||||
|
||||
func refreshSkeleton() {
|
||||
self.view.hideSkeleton()
|
||||
if type == .gradient { showGradientSkeleton() }
|
||||
else { showSolidSkeleton() }
|
||||
}
|
||||
|
||||
func showSolidSkeleton() {
|
||||
if switchAnimated.isOn {
|
||||
view.showAnimatedSkeleton(usingColor: colorSelectedView.backgroundColor!)
|
||||
} else {
|
||||
view.showSkeleton(usingColor: colorSelectedView.backgroundColor!)
|
||||
}
|
||||
}
|
||||
|
||||
func showGradientSkeleton() {
|
||||
let gradient = SkeletonGradient(baseColor: colorSelectedView.backgroundColor!)
|
||||
if switchAnimated.isOn {
|
||||
view.showAnimatedGradientSkeleton(usingGradient: gradient)
|
||||
} else {
|
||||
view.showGradientSkeleton(usingGradient: gradient)
|
||||
}
|
||||
}
|
||||
|
||||
func showAlertPicker() {
|
||||
|
||||
let alertView = UIAlertController(title: "Select color", message: "\n\n\n\n\n\n", preferredStyle: .alert)
|
||||
|
||||
let pickerView = UIPickerView(frame: CGRect(x: 0, y: 50, width: 260, height: 115))
|
||||
pickerView.dataSource = self
|
||||
pickerView.delegate = self
|
||||
|
||||
alertView.view.addSubview(pickerView)
|
||||
|
||||
let action = UIAlertAction(title: "OK", style: .default) { [unowned pickerView, unowned self] _ in
|
||||
let row = pickerView.selectedRow(inComponent: 0)
|
||||
self.colorSelectedView.backgroundColor = colors[row].0
|
||||
self.refreshSkeleton()
|
||||
}
|
||||
alertView.addAction(action)
|
||||
|
||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
||||
alertView.addAction(cancelAction)
|
||||
|
||||
present(alertView, animated: false, completion: {
|
||||
pickerView.frame.size.width = alertView.view.frame.size.width
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIPickerViewDelegate, UIPickerViewDataSource
|
||||
|
||||
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
|
||||
|
||||
func numberOfComponents(in pickerView: UIPickerView) -> Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||
return colors.count
|
||||
}
|
||||
|
||||
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
|
||||
return colors[row].1
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDelegateFlowLayout
|
||||
|
||||
extension ViewController: UICollectionViewDelegateFlowLayout {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
||||
return CGSize(width: view.frame.width/3 - 10, height: view.frame.width/3 - 10)
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
|
||||
return 5
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
|
||||
return 5
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SkeletonCollectionViewDataSource
|
||||
|
||||
extension ViewController: SkeletonCollectionViewDataSource {
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier {
|
||||
return "CollectionViewCell"
|
||||
}
|
||||
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return 10
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDataSource
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
|
||||
return cell
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// SkeletonViewExample
|
||||
//
|
||||
// Created by Juanpe Catalán on 02/11/2017.
|
||||
// Copyright © 2017 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "avatar.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 933 B |
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,222 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="SkeletonViewExample" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="UCB-SP-lQk">
|
||||
<rect key="frame" x="0.0" y="263" width="375" height="264"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="separatorColor" red="0.1061807256" green="0.84678786989999999" blue="0.031482450150000001" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="CellIdentifier" rowHeight="120" id="2dN-Bd-tdy" customClass="Cell" customModule="SkeletonViewExample" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="28" width="375" height="120"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="2dN-Bd-tdy" id="7IN-F3-Mr6">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="120"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar" translatesAutoresizingMaskIntoConstraints="NO" id="oiE-tt-nc2">
|
||||
<rect key="frame" x="15" y="18" width="82" height="82"/>
|
||||
<color key="backgroundColor" red="0.56078431370000004" green="0.59607843140000005" blue="0.7843137255" alpha="0.90709546230000004" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="82" id="4j0-PU-CmN"/>
|
||||
<constraint firstAttribute="height" constant="82" id="iqE-Lc-FOj"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="15" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VhU-1t-AaI">
|
||||
<rect key="frame" x="118" y="29" width="237" height="20.5"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="lessThanOrEqual" constant="71" id="HRL-cI-ieC"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="linesCornerRadius">
|
||||
<integer key="value" value="0"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="oiE-tt-nc2" firstAttribute="leading" secondItem="7IN-F3-Mr6" secondAttribute="leadingMargin" id="1be-ak-AH1"/>
|
||||
<constraint firstItem="oiE-tt-nc2" firstAttribute="top" secondItem="7IN-F3-Mr6" secondAttribute="topMargin" constant="7" id="EKn-ST-LDX"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="VhU-1t-AaI" secondAttribute="trailing" constant="5" id="I7C-Bq-mfK"/>
|
||||
<constraint firstItem="VhU-1t-AaI" firstAttribute="leading" secondItem="oiE-tt-nc2" secondAttribute="trailing" constant="21" id="Ojr-Kz-1k6"/>
|
||||
<constraint firstItem="VhU-1t-AaI" firstAttribute="top" secondItem="7IN-F3-Mr6" secondAttribute="topMargin" constant="18" id="ZW6-JY-S4c"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</tableViewCellContentView>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="avatar" destination="oiE-tt-nc2" id="Dkh-R5-Qhu"/>
|
||||
<outlet property="label1" destination="VhU-1t-AaI" id="kUW-HV-KrD"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="NO"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="BYZ-38-t0r" id="Hxi-nC-gbY"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="F9K-jU-100">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="243"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="e9V-mk-xH0">
|
||||
<rect key="frame" x="45" y="142" width="287" height="78"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="78" id="gF5-G1-lKI"/>
|
||||
</constraints>
|
||||
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </string>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="lastLineFillPercent">
|
||||
<integer key="value" value="40"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="linesCornerRadius">
|
||||
<integer key="value" value="6"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</textView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar" translatesAutoresizingMaskIntoConstraints="NO" id="nMj-pU-5wJ">
|
||||
<rect key="frame" x="141" y="20" width="93" height="93"/>
|
||||
<color key="backgroundColor" red="0.56078431370000004" green="0.59607843140000005" blue="0.7843137255" alpha="0.90709546230000004" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="93" id="gw9-nu-cKo"/>
|
||||
<constraint firstAttribute="width" constant="93" id="zB6-Lp-IUt"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="nMj-pU-5wJ" firstAttribute="centerX" secondItem="F9K-jU-100" secondAttribute="centerX" id="9X4-2r-AKx"/>
|
||||
<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 firstAttribute="height" constant="243" id="MIj-xq-gr1"/>
|
||||
<constraint firstItem="e9V-mk-xH0" firstAttribute="top" secondItem="F9K-jU-100" secondAttribute="top" constant="142" id="Wcx-nZ-1lR"/>
|
||||
<constraint firstAttribute="trailing" secondItem="e9V-mk-xH0" secondAttribute="trailing" constant="43" id="XbU-Og-rht"/>
|
||||
<constraint firstItem="nMj-pU-5wJ" firstAttribute="top" secondItem="F9K-jU-100" secondAttribute="top" constant="20" id="hQL-cr-MaN"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XgY-1a-UGc">
|
||||
<rect key="frame" x="0.0" y="527" width="375" height="140"/>
|
||||
<subviews>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="xOL-Sq-r4i">
|
||||
<rect key="frame" x="20" y="23" width="140" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="Solid"/>
|
||||
<segment title="Gradient"/>
|
||||
</segments>
|
||||
<connections>
|
||||
<action selector="changeSkeletonType:" destination="BYZ-38-t0r" eventType="valueChanged" id="iAS-ab-0jP"/>
|
||||
</connections>
|
||||
</segmentedControl>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vz0-qg-GcZ">
|
||||
<rect key="frame" x="310" y="21" width="49" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="changeAnimated:" destination="BYZ-38-t0r" eventType="valueChanged" id="w1G-gZ-RE0"/>
|
||||
</connections>
|
||||
</switch>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Animated" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WHN-wR-TKt">
|
||||
<rect key="frame" x="211" y="28" width="91" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Color" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7CF-rV-pK2">
|
||||
<rect key="frame" x="32" y="89" width="52" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iGp-rp-t1d">
|
||||
<rect key="frame" x="92" y="84" width="30" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Mde-Cm-CoS">
|
||||
<rect key="frame" x="20" y="74" width="140" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="btnChangeColorTouchUpInside:" destination="BYZ-38-t0r" eventType="touchUpInside" id="cB8-Ik-LIJ"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="140" id="OH5-ja-ZlB"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="F9K-jU-100" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="1es-nY-bd3"/>
|
||||
<constraint firstItem="F9K-jU-100" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="A3E-iv-1qp"/>
|
||||
<constraint firstItem="XgY-1a-UGc" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="Luk-cg-4Ez"/>
|
||||
<constraint firstItem="UCB-SP-lQk" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="Qbw-Rq-Rhw"/>
|
||||
<constraint firstItem="F9K-jU-100" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="VLb-cX-ZHC"/>
|
||||
<constraint firstItem="XgY-1a-UGc" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="Y8A-sq-fmq"/>
|
||||
<constraint firstItem="XgY-1a-UGc" firstAttribute="top" secondItem="UCB-SP-lQk" secondAttribute="bottom" id="eof-MM-DrW"/>
|
||||
<constraint firstItem="UCB-SP-lQk" firstAttribute="top" secondItem="F9K-jU-100" secondAttribute="bottom" id="hwL-ec-fKo"/>
|
||||
<constraint firstItem="UCB-SP-lQk" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="o6z-Dj-ppC"/>
|
||||
<constraint firstItem="XgY-1a-UGc" firstAttribute="bottom" secondItem="6Tk-OE-BBY" secondAttribute="bottom" id="vnZ-9k-MfI"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="BEI-dU-kr2"/>
|
||||
<connections>
|
||||
<outlet property="avatarImage" destination="nMj-pU-5wJ" id="9fa-Z7-vYi"/>
|
||||
<outlet property="colorSelectedView" destination="iGp-rp-t1d" id="0Zm-9d-jRU"/>
|
||||
<outlet property="skeletonTypeSelector" destination="xOL-Sq-r4i" id="yTr-8L-I4Y"/>
|
||||
<outlet property="switchAnimated" destination="vz0-qg-GcZ" id="d2R-8x-lRb"/>
|
||||
<outlet property="tableview" destination="UCB-SP-lQk" id="XV0-KX-lAN"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-2582" y="-400"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="avatar" width="215" height="211"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// Cell.swift
|
||||
// SkeletonViewExample
|
||||
//
|
||||
// Created by Juanpe Catalán on 03/11/2017.
|
||||
// Copyright © 2017 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class Cell: UITableViewCell {
|
||||
|
||||
@IBOutlet weak var avatar: UIImageView!
|
||||
@IBOutlet weak var label1: UILabel!
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
//
|
||||
// Constants.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Renato Mendes on 28/11/2017.
|
||||
// Copyright © 2017 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
let colors = [(UIColor.turquoise,"turquoise"), (UIColor.emerald,"emerald"), (UIColor.peterRiver,"peterRiver"), (UIColor.amethyst,"amethyst"),(UIColor.wetAsphalt,"wetAsphalt"), (UIColor.nephritis,"nephritis"), (UIColor.belizeHole,"belizeHole"), (UIColor.wisteria,"wisteria"), (UIColor.midnightBlue,"midnightBlue"), (UIColor.sunFlower,"sunFlower"), (UIColor.carrot,"carrot"), (UIColor.alizarin,"alizarin"),(UIColor.clouds,"clouds"), (UIColor.concrete,"concrete"), (UIColor.flatOrange,"flatOrange"), (UIColor.pumpkin,"pumpkin"), (UIColor.pomegranate,"pomegranate"), (UIColor.silver,"silver"), (UIColor.asbestos,"asbestos")]
|
||||
@@ -1,149 +0,0 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// SkeletonViewExample
|
||||
//
|
||||
// Created by Juanpe Catalán on 02/11/2017.
|
||||
// Copyright © 2017 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SkeletonView
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var tableview: UITableView! {
|
||||
didSet {
|
||||
tableview.rowHeight = UITableViewAutomaticDimension
|
||||
tableview.estimatedRowHeight = 120.0
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var avatarImage: UIImageView! {
|
||||
didSet {
|
||||
avatarImage.layer.cornerRadius = avatarImage.frame.width/2
|
||||
avatarImage.layer.masksToBounds = true
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var colorSelectedView: UIView! {
|
||||
didSet {
|
||||
colorSelectedView.layer.cornerRadius = 5
|
||||
colorSelectedView.layer.masksToBounds = true
|
||||
colorSelectedView.backgroundColor = SkeletonAppearance.default.tintColor
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var switchAnimated: UISwitch!
|
||||
@IBOutlet weak var skeletonTypeSelector: UISegmentedControl!
|
||||
|
||||
var type: SkeletonType {
|
||||
return skeletonTypeSelector.selectedSegmentIndex == 0 ? .solid : .gradient
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableview.isSkeletonable = true
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
view.showAnimatedSkeleton()
|
||||
}
|
||||
|
||||
@IBAction func changeAnimated(_ sender: Any) {
|
||||
if switchAnimated.isOn {
|
||||
view.startSkeletonAnimation()
|
||||
} else {
|
||||
view.stopSkeletonAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func changeSkeletonType(_ sender: Any) {
|
||||
refreshSkeleton()
|
||||
}
|
||||
|
||||
@IBAction func btnChangeColorTouchUpInside(_ sender: Any) {
|
||||
showAlertPicker()
|
||||
}
|
||||
|
||||
func refreshSkeleton() {
|
||||
self.view.hideSkeleton()
|
||||
if type == .gradient { showGradientSkeleton() }
|
||||
else { showSolidSkeleton() }
|
||||
}
|
||||
|
||||
func showSolidSkeleton() {
|
||||
if switchAnimated.isOn {
|
||||
view.showAnimatedSkeleton(usingColor: colorSelectedView.backgroundColor!)
|
||||
} else {
|
||||
view.showSkeleton(usingColor: colorSelectedView.backgroundColor!)
|
||||
}
|
||||
}
|
||||
|
||||
func showGradientSkeleton() {
|
||||
let gradient = SkeletonGradient(baseColor: colorSelectedView.backgroundColor!)
|
||||
if switchAnimated.isOn {
|
||||
view.showAnimatedGradientSkeleton(usingGradient: gradient)
|
||||
} else {
|
||||
view.showGradientSkeleton(usingGradient: gradient)
|
||||
}
|
||||
}
|
||||
|
||||
func showAlertPicker() {
|
||||
|
||||
let alertView = UIAlertController(title: "Select color", message: "\n\n\n\n\n\n", preferredStyle: .alert)
|
||||
|
||||
let pickerView = UIPickerView(frame: CGRect(x: 0, y: 50, width: 260, height: 115))
|
||||
pickerView.dataSource = self
|
||||
pickerView.delegate = self
|
||||
|
||||
alertView.view.addSubview(pickerView)
|
||||
|
||||
let action = UIAlertAction(title: "OK", style: .default) { [unowned pickerView, unowned self] _ in
|
||||
let row = pickerView.selectedRow(inComponent: 0)
|
||||
self.colorSelectedView.backgroundColor = colors[row].0
|
||||
self.refreshSkeleton()
|
||||
}
|
||||
alertView.addAction(action)
|
||||
|
||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
||||
alertView.addAction(cancelAction)
|
||||
|
||||
present(alertView, animated: false, completion: {
|
||||
pickerView.frame.size.width = alertView.view.frame.size.width
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
|
||||
|
||||
func numberOfComponents(in pickerView: UIPickerView) -> Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||
return colors.count
|
||||
}
|
||||
|
||||
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
|
||||
return colors[row].1
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewController: SkeletonTableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return 9
|
||||
}
|
||||
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier {
|
||||
return "CellIdentifier"
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier", for: indexPath) as! Cell
|
||||
cell.label1.text = "cell => \(indexPath.row)"
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
||||
gem 'cocoapods', '~> 1.7.0.beta.2'
|
||||
@@ -0,0 +1,212 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.0)
|
||||
activesupport (4.2.11.1)
|
||||
i18n (~> 0.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.6.0)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
atomos (0.1.3)
|
||||
babosa (1.0.2)
|
||||
claide (1.0.2)
|
||||
cocoapods (1.7.5)
|
||||
activesupport (>= 4.0.2, < 5)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
cocoapods-core (= 1.7.5)
|
||||
cocoapods-deintegrate (>= 1.0.3, < 2.0)
|
||||
cocoapods-downloader (>= 1.2.2, < 2.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
cocoapods-search (>= 1.0.0, < 2.0)
|
||||
cocoapods-stats (>= 1.0.0, < 2.0)
|
||||
cocoapods-trunk (>= 1.3.1, < 2.0)
|
||||
cocoapods-try (>= 1.1.0, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
escape (~> 0.0.4)
|
||||
fourflusher (>= 2.3.0, < 3.0)
|
||||
gh_inspector (~> 1.0)
|
||||
molinillo (~> 0.6.6)
|
||||
nap (~> 1.0)
|
||||
ruby-macho (~> 1.4)
|
||||
xcodeproj (>= 1.10.0, < 2.0)
|
||||
cocoapods-core (1.7.5)
|
||||
activesupport (>= 4.0.2, < 6)
|
||||
fuzzy_match (~> 2.0.4)
|
||||
nap (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.4)
|
||||
cocoapods-downloader (1.2.2)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.0)
|
||||
cocoapods-stats (1.1.0)
|
||||
cocoapods-trunk (1.3.1)
|
||||
nap (>= 0.8, < 2.0)
|
||||
netrc (~> 0.11)
|
||||
cocoapods-try (1.1.0)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander-fastlane (4.4.6)
|
||||
highline (~> 1.7.2)
|
||||
concurrent-ruby (1.1.5)
|
||||
declarative (0.0.10)
|
||||
declarative-option (0.1.0)
|
||||
digest-crc (0.4.1)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.7.4)
|
||||
emoji_regex (1.0.1)
|
||||
escape (0.0.4)
|
||||
excon (0.71.0)
|
||||
faraday (0.15.4)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday-cookie_jar (0.0.6)
|
||||
faraday (>= 0.7.4)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday_middleware (0.13.1)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
fastimage (2.1.5)
|
||||
fastlane (2.128.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
babosa (>= 1.0.2, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored
|
||||
commander-fastlane (>= 4.4.6, < 5.0.0)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 2.0)
|
||||
excon (>= 0.45.0, < 1.0.0)
|
||||
faraday (~> 0.9)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 0.9)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-api-client (>= 0.21.2, < 0.24.0)
|
||||
google-cloud-storage (>= 1.15.0, < 2.0.0)
|
||||
highline (>= 1.7.2, < 2.0.0)
|
||||
json (< 3.0.0)
|
||||
jwt (~> 2.1.0)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multi_xml (~> 0.5)
|
||||
multipart-post (~> 2.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
public_suffix (~> 2.0.0)
|
||||
rubyzip (>= 1.2.2, < 2.0.0)
|
||||
security (= 0.1.3)
|
||||
simctl (~> 1.6.3)
|
||||
slack-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.8.1, < 2.0.0)
|
||||
xcpretty (~> 0.3.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
fourflusher (2.3.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
google-api-client (0.23.9)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (>= 0.5, < 0.7.0)
|
||||
httpclient (>= 2.8.1, < 3.0)
|
||||
mime-types (~> 3.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
signet (~> 0.9)
|
||||
google-cloud-core (1.3.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-env (1.2.0)
|
||||
faraday (~> 0.11)
|
||||
google-cloud-storage (1.16.0)
|
||||
digest-crc (~> 0.4)
|
||||
google-api-client (~> 0.23)
|
||||
google-cloud-core (~> 1.2)
|
||||
googleauth (>= 0.6.2, < 0.10.0)
|
||||
googleauth (0.6.7)
|
||||
faraday (~> 0.12)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (~> 0.7)
|
||||
highline (1.7.10)
|
||||
http-cookie (1.0.3)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
i18n (0.9.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
json (2.3.1)
|
||||
jwt (2.1.0)
|
||||
memoist (0.16.0)
|
||||
mime-types (3.2.2)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2019.0331)
|
||||
mini_magick (4.9.5)
|
||||
minitest (5.11.3)
|
||||
molinillo (0.6.6)
|
||||
multi_json (1.13.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.0.0)
|
||||
nanaimo (0.2.6)
|
||||
nap (1.1.0)
|
||||
naturally (2.2.0)
|
||||
netrc (0.11.0)
|
||||
os (1.0.1)
|
||||
plist (3.5.0)
|
||||
public_suffix (2.0.5)
|
||||
representable (3.0.4)
|
||||
declarative (< 0.1.0)
|
||||
declarative-option (< 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rouge (2.0.7)
|
||||
ruby-macho (1.4.0)
|
||||
rubyzip (1.3.0)
|
||||
security (0.1.3)
|
||||
signet (0.11.0)
|
||||
addressable (~> 2.3)
|
||||
faraday (~> 0.9)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.5)
|
||||
CFPropertyList
|
||||
naturally
|
||||
slack-notifier (2.3.2)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
thread_safe (0.3.6)
|
||||
tty-cursor (0.7.0)
|
||||
tty-screen (0.7.0)
|
||||
tty-spinner (0.9.1)
|
||||
tty-cursor (~> 0.7)
|
||||
tzinfo (1.2.5)
|
||||
thread_safe (~> 0.1)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.6)
|
||||
unicode-display_width (1.6.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.11.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.2.6)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (1.0.0)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
cocoapods (~> 1.7.0.beta.2)
|
||||
fastlane
|
||||
|
||||
BUNDLED WITH
|
||||
2.0.1
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "SnapshotTesting",
|
||||
"repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "c466812aa2e22898f27557e2e780d3aad7a27203",
|
||||
"version": "1.8.2"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// swift-tools-version:5.3
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "SkeletonView",
|
||||
platforms: [
|
||||
.iOS(.v11),
|
||||
.tvOS(.v11)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "SkeletonView",
|
||||
targets: ["SkeletonView"]
|
||||
)
|
||||
],
|
||||
dependencies: [
|
||||
.package(name: "SnapshotTesting", url: "https://github.com/pointfreeco/swift-snapshot-testing.git", .exact("1.8.2"))
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "SkeletonView",
|
||||
path: "Sources",
|
||||
exclude: [
|
||||
"*.md"
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "SkeletonViewTests",
|
||||
dependencies: [
|
||||
"SkeletonView",
|
||||
"SnapshotTesting"
|
||||
],
|
||||
path: "Tests/SkeletonViewTests",
|
||||
exclude: [
|
||||
"UI/__Snapshots__"
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@@ -1,113 +1,104 @@
|
||||

|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/Juanpe/SkeletonView">
|
||||
<img src="https://img.shields.io/travis/Juanpe/SkeletonView.svg">
|
||||
</a>
|
||||
<a href="https://instagram.github.io/IGListKit/">
|
||||
<img src="https://img.shields.io/cocoapods/p/SkeletonView.svg" alt="Platforms">
|
||||
</a>
|
||||
<img src="https://img.shields.io/badge/Swift-4.1-orange.svg" />
|
||||
<a href="https://cocoapods.org/pods/SkeletonView">
|
||||
<img src="https://img.shields.io/cocoapods/v/SkeletonView.svg" alt="CocoaPods" />
|
||||
</a>
|
||||
<a href="https://github.com/Carthage/Carthage">
|
||||
<img src="https://img.shields.io/badge/carthage-compatible-4BC51D.svg?style=flat" alt="Carthage" />
|
||||
</a>
|
||||
<a href="https://cocoapods.org/pods/SkeletonView">
|
||||
<img src="https://img.shields.io/cocoapods/dt/SkeletonView.svg?style=flat" alt="CocoaPods downloads" />
|
||||
</a>
|
||||
<a href="https://twitter.com/JuanpeCatalan">
|
||||
<img src="https://img.shields.io/badge/contact-@JuanpeCatalan-blue.svg?style=flat" alt="Twitter: @JuanpeCatalan" />
|
||||
</a>
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=MJ4Y2D9DEX6FL&lc=ES&item_name=SkeletonView¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted">
|
||||
<img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Paypal" />
|
||||
</a>
|
||||
<a href="https://twitter.com/intent/tweet?text=Wow%20This%20library%20is%20awesome:&url=https%3A%2F%2Fgithub.com%2FJuanpe%2FSkeletonView">
|
||||
<img src="https://img.shields.io/twitter/url/https/github.com/Juanpe/SkeletonView.svg?style=social" alt="License" />
|
||||
</a>
|
||||
<a href="https://twitter.com/JuanpeCatalan">
|
||||
<img src="https://img.shields.io/twitter/follow/JuanpeCatalan.svg?style=social&label=Follow" alt="Twitter" />
|
||||
<a href="https://github.com/Juanpe/SkeletonView/actions?query=workflow%3ACI">
|
||||
<img src="https://github.com/Juanpe/SkeletonView/workflows/CI/badge.svg">
|
||||
</a>
|
||||
<a href="https://codebeat.co/projects/github-com-juanpe-skeletonview-main"><img alt="codebeat badge" src="https://codebeat.co/badges/f854fdfd-31e5-4689-ba04-075d83653e60" /></a>
|
||||
<img src="http://img.shields.io/badge/dependency%20manager-swiftpm%2Bcocoapods%2Bcarthage-green" />
|
||||
<img src="https://img.shields.io/badge/platforms-ios%2Btvos-green" />
|
||||
<a href="https://badge.bow-swift.io/recipe?name=SkeletonView&description=An%20elegant%20way%20to%20show%20users%20that%20something%20is%20happening%20and%20also%20prepare%20them%20to%20which%20contents%20he%20is%20waiting&url=https://github.com/juanpe/skeletonview&owner=Juanpe&avatar=https://avatars0.githubusercontent.com/u/1409041?v=4&tag=1.8.7"><img src="https://raw.githubusercontent.com/bow-swift/bow-art/main/badges/nef-playgrounds-badge.svg" alt="SkeletonView Playground" style="height:20px"></a>
|
||||
</p>
|
||||
|
||||
🌎 Translations: [ [🇨🇳](https://github.com/Juanpe/SkeletonView/blob/master/README_zh.md) by [@WhatsXie](https://twitter.com/WhatsXie) ]
|
||||
<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>
|
||||
|
||||
Today almost all apps have async processes, such as Api requests, long running processes, etc. And while the processes are working, usually developers place a loading view to show users that something is going on.
|
||||
**🌎 README is available in other languages: [🇪🇸](https://github.com/Juanpe/SkeletonView/blob/main/README_es.md) . [🇨🇳](https://github.com/Juanpe/SkeletonView/blob/main/README_zh.md) . [🇧🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_pt-br.md) . [🇰🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_ko.md) . [🇫🇷](https://github.com/Juanpe/SkeletonView/blob/main/README_fr.md)**
|
||||
|
||||
```SkeletonView``` has been conceived to address this need, an elegant way to show users that something is happening and also prepare them to which contents he is waiting.
|
||||
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.
|
||||
|
||||
Enjoy it! 🙂
|
||||
|
||||
* [Features](#-features)
|
||||
* [Requirements](#-supported-os--sdk-versions)
|
||||
* [Example Project](#-example)
|
||||
* [Installation](#-installation)
|
||||
* [Cocoapods](#using-cocoapods)
|
||||
* [Carthage](#using-carthage)
|
||||
* [How to use](#-how-to-use)
|
||||
* [Collections](#-collections)
|
||||
* [Multiline text](#-multiline-text)
|
||||
* [Custom colors](#-custom-colors)
|
||||
* [Appearance](#-appearance)
|
||||
* [Custom animations](#-custom-animations)
|
||||
* [Hierarchy](#-hierarchy)
|
||||
* [Documentation](#-documentation)
|
||||
* [Next steps](#-next-steps)
|
||||
* [Contributing](#-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)
|
||||
- [Image captured from website https://flatuicolors.com](#image-captured-from-website-httpsflatuicolorscom)
|
||||
- [🏃♀️ Animations](#️-animations)
|
||||
- [🏄 Transitions](#-transitions)
|
||||
- [✨ Miscellaneous](#-miscellaneous)
|
||||
- [❤️ Contributing](#️-contributing)
|
||||
- [📢 Mentions](#-mentions)
|
||||
- [👨🏻💻 Author](#-author)
|
||||
- [👮🏻 License](#-license)
|
||||
|
||||
|
||||
|
||||
## 🌟 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
|
||||
|
||||
### 📋 Supported OS & SDK Versions
|
||||
|
||||
* iOS 9.0+
|
||||
* tvOS 9.0+
|
||||
* Swift 4
|
||||
## 🎬 Guides
|
||||
|
||||
### 🔮 Example
|
||||
| [](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
|
||||
|
||||
To run the example project, clone the repo and run `SkeletonViewExample` target.
|
||||
|
||||
## 📲 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"
|
||||
```
|
||||
|
||||
## 🐒 How to use
|
||||
* [Swift Package Manager](https://swift.org/package-manager/):
|
||||
|
||||
```swift
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/Juanpe/SkeletonView.git", from: "1.7.0")
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
## 🐒 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 +108,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,14 +150,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
|
||||
|
||||
> 📣 **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`.
|
||||
|
||||
|
||||
|
||||
|
||||
### 🌿 Collections
|
||||
|
||||
Now, ```SkeletonView``` is compatible with ```UITableView``` and ```UICollectionView```.
|
||||
```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.
|
||||
|
||||
@@ -203,34 +200,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
|
||||
}
|
||||
```
|
||||
|
||||
###### UICollectionView
|
||||
> 📣 **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) ❌
|
||||
> ```
|
||||
|
||||
For ```UICollectionView```, you need to conform to ```SkeletonCollectionViewDataSource``` protocol.
|
||||
|
||||
|
||||
**UICollectionView**
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -251,12 +265,46 @@ Or, if you prefer use **IB/Storyboard**:
|
||||
|
||||

|
||||
|
||||
|
||||
### 🦋 Appearance
|
||||
|
||||
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
|
||||
- *default: `.skeletonDefault` (same as `.clouds` but adaptive to 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) (Make your skeleton view with corner)
|
||||
- *default: 0*
|
||||
|
||||
To get these default values you can use `SkeletonAppearance.default`. Using this property you can set the values as well:
|
||||
```swift
|
||||
SkeletonAppearance.default.multilineHeight = 20
|
||||
SkeletonAppearance.default.tintColor = .green
|
||||
```
|
||||
|
||||
You can also specifiy these line appearance properties on a per-label basis:
|
||||
- **lastLineFillPercent**: Int
|
||||
- **linesCornerRadius**: Int
|
||||
- **skeletonLineSpacing**: CGFloat
|
||||
- **skeletonPaddingInsets**: UIEdgeInsets
|
||||
|
||||
|
||||
### 🎨 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
|
||||
```swift
|
||||
view.showSkeleton(usingColor: UIColor.gray) // Solid
|
||||
// or
|
||||
view.showSkeleton(usingColor: UIColor(red: 25.0, green: 30.0, blue: 255.0, alpha: 1.0))
|
||||
@@ -267,29 +315,17 @@ let gradient = SkeletonGradient(baseColor: UIColor.midnightBlue)
|
||||
view.showGradientSkeleton(usingGradient: gradient) // Gradient
|
||||
```
|
||||
|
||||
Besides, ```SkeletonView``` features 20 flat colors 🤙🏼
|
||||
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.
|
||||
### 🏃♀️ Animations
|
||||
|
||||
Default values:
|
||||
- **tintColor**: UIColor
|
||||
- **gradient**: SkeletonGradient
|
||||
- **multilineHeight**: CGFloat
|
||||
- **multilineSpacing**: CGFloat
|
||||
- **multilineLastLineFillPercent**: Int
|
||||
- **multilineCornerRadius**: Int _0_
|
||||
|
||||
|
||||
### 🤓 Custom animations
|
||||
|
||||
```SkeletonView``` has two built-in animations, *pulse* for solid skeletons and *sliding* for gradients.
|
||||
**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.
|
||||
|
||||
@@ -323,7 +359,7 @@ view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
|
||||
|
||||
```
|
||||
|
||||
```GradientDirection``` is an enum, with this cases:
|
||||
```GradientDirection``` is an enum, with theses cases:
|
||||
|
||||
| Direction | Preview
|
||||
|------- | -------
|
||||
@@ -335,41 +371,157 @@ 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()
|
||||
> ```
|
||||
|
||||
### 👨👧👦 Hierarchy
|
||||
|
||||
|
||||
### 🏄 Transitions
|
||||
|
||||
**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:
|
||||
|
||||
```swift
|
||||
view.showSkeleton(transition: .crossDissolve(0.25)) //Show skeleton cross dissolve transition with 0.25 seconds fade time
|
||||
view.hideSkeleton(transition: .crossDissolve(0.25)) //Hide skeleton cross dissolve transition with 0.25 seconds fade time
|
||||
|
||||
```
|
||||
|
||||
The default value is `crossDissolve(0.25)`
|
||||
|
||||
**Preview**
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<center>None</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>
|
||||
|
||||
|
||||
## ✨ 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.
|
||||
|
||||
Because an image is worth a thousand words:
|
||||
|
||||
> ```ìsSkeletonable```= ☠️
|
||||
In this example we have a `UIViewController` with a `ContainerView` and a `UITableView`. When the view is ready, we show the skeleton using this method:
|
||||
```
|
||||
view.showSkeleton()
|
||||
```
|
||||
|
||||
| Configuration | Result
|
||||
|------- | -------
|
||||
| | 
|
||||
| | 
|
||||
| | 
|
||||
| | 
|
||||
> ```isSkeletonable```= ☠️
|
||||
|
||||
| Configuration | Result|
|
||||
|:-------:|:-------:|
|
||||
|<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"/>|
|
||||
|
||||
|
||||
|
||||
**Hierarchy in collections**
|
||||
|
||||
Here is an illustration that shows how you should specify which elements are skeletonables when you are using an `UITableView`:
|
||||
|
||||
<img src="Assets/tableview_scheme.png" width="700px">
|
||||
|
||||
As you can see, we have to make skeletonable the tableview, the cell and the UI elements, but we don't need to set as skeletonable the `contentView`
|
||||
|
||||
|
||||
|
||||
**Skeleton views layout**
|
||||
|
||||
Sometimes skeleton layout may not fit your layout because the parent view bounds have changed. ~For example, rotating the device.~
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
### 📚 Documentation
|
||||
Coming soon...😅
|
||||
**Update skeleton**
|
||||
|
||||
## 📬 Next steps
|
||||
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
|
||||
```
|
||||
|
||||
**Hiding views when the animation starts**
|
||||
|
||||
Sometimes you wanna hide some view when the animation starts, so there is a quick property that you can use to make this happen:
|
||||
|
||||
```swift
|
||||
view.isHiddenWhenSkeletonIsActive = true // This works only when isSkeletonable = true
|
||||
```
|
||||
|
||||
**Debug**
|
||||
|
||||
To facilitate the debug tasks when something is not working fine. **`SkeletonView`** has some new tools.
|
||||
|
||||
First, `UIView` has available a new property with his skeleton info:
|
||||
```swift
|
||||
var skeletonDescription: String
|
||||
|
||||
```
|
||||
The skeleton representation looks like this:
|
||||
|
||||

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

|
||||
|
||||
Then, when the skeleton appears, you can see the view hierarchy in the Xcode console.
|
||||
|
||||
<details>
|
||||
<summary>Open to see an output example </summary>
|
||||
<img src="Assets/hierarchy_output.png" />
|
||||
</details>
|
||||
|
||||
|
||||
**Supported OS & SDK Versions**
|
||||
|
||||
* iOS 9.0+
|
||||
* tvOS 9.0+
|
||||
* Swift 5
|
||||
|
||||
* [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
|
||||
* [ ] Custom collections compatible
|
||||
* [ ] Add animations when it shows/hides the skeletons
|
||||
* [ ] MacOS and WatchOS compatible
|
||||
|
||||
## ❤️ Contributing
|
||||
This is an open source project, so feel free to contribute. How?
|
||||
@@ -379,7 +531,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/main/CONTRIBUTING.md).
|
||||
|
||||
|
||||
## 📢 Mentions
|
||||
|
||||
@@ -394,17 +547,18 @@ See [all contributors](https://github.com/Juanpe/SkeletonView/graphs/contributor
|
||||
- [Swift Weekly #96](http://digest.swiftweekly.com/issues/swift-weekly-issue-96-81759)
|
||||
- [CocoaControls](https://www.cocoacontrols.com/controls/skeletonview)
|
||||
- [Awesome iOS Newsletter #74](https://ios.libhunt.com/newsletter/74)
|
||||
- [Swift News #36](https://www.youtube.com/watch?v=mAGpsQiy6so)
|
||||
- [Best iOS articles, new tools & more](https://medium.com/flawless-app-stories/best-ios-articles-new-tools-more-fcbe673e10d)
|
||||
|
||||
|
||||
|
||||
## 👨🏻💻 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
|
||||
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "SkeletonView"
|
||||
s.version = "1.3"
|
||||
s.version = "1.13.0"
|
||||
s.summary = "An elegant way to show users that something is happening and also prepare them to which contents he is waiting"
|
||||
s.description = <<-DESC
|
||||
Today almost all apps have async processes, as API requests, long runing processes, etc. And while the processes are working, usually developers place a loading view to show users that something is going on.
|
||||
@@ -12,6 +12,7 @@ Pod::Spec.new do |s|
|
||||
s.social_media_url = "https://twitter.com/JuanpeCatalan"
|
||||
s.ios.deployment_target = "9.0"
|
||||
s.tvos.deployment_target = "9.0"
|
||||
s.swift_version = "5.3"
|
||||
s.source = { :git => "https://github.com/Juanpe/SkeletonView.git", :tag => s.version.to_s }
|
||||
s.source_files = "Sources/**/*"
|
||||
end
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -4,4 +4,4 @@
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
</Workspace>
|
||||
@@ -2,7 +2,7 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>FILEHEADER</key>
|
||||
<string> ___COPYRIGHT___</string>
|
||||
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
</plist>
|
||||
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "17DD0DFF207FB27400C56334"
|
||||
BuildableName = "SkeletonView.framework"
|
||||
BlueprintName = "SkeletonView-tvOS"
|
||||
ReferencedContainer = "container:SkeletonView.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "17DD0DFF207FB27400C56334"
|
||||
BuildableName = "SkeletonView.framework"
|
||||
BlueprintName = "SkeletonView-tvOS"
|
||||
ReferencedContainer = "container:SkeletonView.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "17DD0DFF207FB27400C56334"
|
||||
BuildableName = "SkeletonView.framework"
|
||||
BlueprintName = "SkeletonView-tvOS"
|
||||
ReferencedContainer = "container:SkeletonView.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
LastUpgradeVersion = "9999"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -14,9 +14,9 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "52D6D97B1BEFF229002C0205"
|
||||
BlueprintIdentifier = "SkeletonView::SkeletonView"
|
||||
BuildableName = "SkeletonView.framework"
|
||||
BlueprintName = "SkeletonView-iOS"
|
||||
BlueprintName = "SkeletonView"
|
||||
ReferencedContainer = "container:SkeletonView.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
@@ -28,9 +28,17 @@
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "SkeletonView::SkeletonViewTests"
|
||||
BuildableName = "SkeletonViewTests.xctest"
|
||||
BlueprintName = "SkeletonViewTests"
|
||||
ReferencedContainer = "container:SkeletonView.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -42,17 +50,6 @@
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "52D6D97B1BEFF229002C0205"
|
||||
BuildableName = "SkeletonView.framework"
|
||||
BlueprintName = "SkeletonView-iOS"
|
||||
ReferencedContainer = "container:SkeletonView.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
@@ -60,15 +57,6 @@
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "52D6D97B1BEFF229002C0205"
|
||||
BuildableName = "SkeletonView.framework"
|
||||
BlueprintName = "SkeletonView-iOS"
|
||||
ReferencedContainer = "container:SkeletonView.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -9,19 +9,20 @@ public protocol Appearance {
|
||||
var multilineSpacing: CGFloat { get set }
|
||||
var multilineLastLineFillPercent: Int { get set }
|
||||
var multilineCornerRadius: Int { get set }
|
||||
var renderSingleLineAsView: Bool { get set }
|
||||
}
|
||||
|
||||
public enum SkeletonAppearance {
|
||||
public static var `default`: Appearance = SkeletonViewAppearance.shared
|
||||
}
|
||||
|
||||
// codebeat:disable[TOO_MANY_IVARS]
|
||||
class SkeletonViewAppearance: Appearance {
|
||||
|
||||
static var shared = SkeletonViewAppearance()
|
||||
|
||||
var tintColor: UIColor = .clouds
|
||||
var tintColor: UIColor = .skeletonDefault
|
||||
|
||||
var gradient: SkeletonGradient = SkeletonGradient(baseColor: .clouds)
|
||||
var gradient = SkeletonGradient(baseColor: .skeletonDefault)
|
||||
|
||||
var multilineHeight: CGFloat = 15
|
||||
|
||||
@@ -30,4 +31,7 @@ class SkeletonViewAppearance: Appearance {
|
||||
var multilineLastLineFillPercent: Int = 70
|
||||
|
||||
var multilineCornerRadius: Int = 0
|
||||
|
||||
var renderSingleLineAsView: Bool = false
|
||||
}
|
||||
// codebeat:enable[TOO_MANY_IVARS]
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
|
||||
/// Object that facilitates the creation of skeleton layers,
|
||||
/// based on the builder pattern
|
||||
class SkeletonLayerBuilder {
|
||||
var skeletonType: SkeletonType?
|
||||
var colors: [UIColor] = []
|
||||
var holder: UIView?
|
||||
|
||||
@discardableResult
|
||||
func setSkeletonType(_ type: SkeletonType) -> SkeletonLayerBuilder {
|
||||
self.skeletonType = type
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func addColor(_ color: UIColor) -> SkeletonLayerBuilder {
|
||||
return addColors([color])
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func addColors(_ colors: [UIColor]) -> SkeletonLayerBuilder {
|
||||
self.colors.append(contentsOf: colors)
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func setHolder(_ holder: UIView) -> SkeletonLayerBuilder {
|
||||
self.holder = holder
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func build() -> SkeletonLayer? {
|
||||
guard let type = skeletonType,
|
||||
let holder = holder
|
||||
else { return nil }
|
||||
|
||||
return SkeletonLayer(type: type,
|
||||
colors: colors,
|
||||
skeletonHolder: holder)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
|
||||
/// Object that facilitates the creation of skeleton layers for multiline
|
||||
/// elements, based on the builder pattern
|
||||
class SkeletonMultilineLayerBuilder {
|
||||
var skeletonType: SkeletonType?
|
||||
var index: Int?
|
||||
var height: CGFloat?
|
||||
var width: CGFloat?
|
||||
var cornerRadius: Int?
|
||||
var multilineSpacing: CGFloat = SkeletonAppearance.default.multilineSpacing
|
||||
var paddingInsets: UIEdgeInsets = .zero
|
||||
var isRTL: Bool = false
|
||||
|
||||
@discardableResult
|
||||
func setSkeletonType(_ type: SkeletonType) -> SkeletonMultilineLayerBuilder {
|
||||
self.skeletonType = type
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func setIndex(_ index: Int) -> SkeletonMultilineLayerBuilder {
|
||||
self.index = index
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func setHeight(_ height: CGFloat) -> SkeletonMultilineLayerBuilder {
|
||||
self.height = height
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func setWidth(_ width: CGFloat) -> SkeletonMultilineLayerBuilder {
|
||||
self.width = width
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func setCornerRadius(_ radius: Int) -> SkeletonMultilineLayerBuilder {
|
||||
self.cornerRadius = radius
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func setMultilineSpacing(_ spacing: CGFloat) -> SkeletonMultilineLayerBuilder {
|
||||
self.multilineSpacing = spacing
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func setPadding(_ insets: UIEdgeInsets) -> SkeletonMultilineLayerBuilder {
|
||||
self.paddingInsets = insets
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func setIsRTL(_ isRTL: Bool) -> SkeletonMultilineLayerBuilder {
|
||||
self.isRTL = isRTL
|
||||
return self
|
||||
}
|
||||
|
||||
func build() -> CALayer? {
|
||||
guard let type = skeletonType,
|
||||
let index = index,
|
||||
let width = width,
|
||||
let height = height,
|
||||
let radius = cornerRadius
|
||||
else { return nil }
|
||||
|
||||
let layer = type.layer
|
||||
layer.anchorPoint = .zero
|
||||
layer.name = CALayer.skeletonSubLayersName
|
||||
layer.updateLayerFrame(for: index,
|
||||
size: CGSize(width: width, height: height),
|
||||
multilineSpacing: multilineSpacing,
|
||||
paddingInsets: paddingInsets,
|
||||
isRTL: isRTL)
|
||||
|
||||
layer.cornerRadius = CGFloat(radius)
|
||||
layer.masksToBounds = true
|
||||
|
||||
return layer
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ protocol CollectionSkeleton {
|
||||
var estimatedNumberOfRows: Int { get }
|
||||
|
||||
func addDummyDataSource()
|
||||
func updateDummyDataSource()
|
||||
func removeDummyDataSource(reloadAfter: Bool)
|
||||
func disableUserInteraction()
|
||||
func enableUserInteraction()
|
||||
@@ -28,6 +29,14 @@ extension CollectionSkeleton where Self: UIScrollView {
|
||||
var estimatedNumberOfRows: Int { return 0 }
|
||||
func addDummyDataSource() {}
|
||||
func removeDummyDataSource(reloadAfter: Bool) {}
|
||||
func disableUserInteraction() { isUserInteractionEnabled = false }
|
||||
func enableUserInteraction() { isUserInteractionEnabled = true }
|
||||
|
||||
func disableUserInteraction() {
|
||||
isUserInteractionEnabled = false
|
||||
isScrollEnabled = false
|
||||
}
|
||||
|
||||
func enableUserInteraction() {
|
||||
isUserInteractionEnabled = true
|
||||
isScrollEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,21 +8,25 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
public protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {
|
||||
func numSections(in collectionSkeletonView: UICollectionView) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -> ReusableCellIdentifier?
|
||||
}
|
||||
|
||||
public extension SkeletonCollectionViewDataSource {
|
||||
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return skeletonView.estimatedNumberOfRows
|
||||
}
|
||||
|
||||
func collectionSkeletonView(_ skeletonView: UICollectionView,
|
||||
supplementaryViewIdentifierOfKind: String,
|
||||
at indexPath: IndexPath) -> ReusableCellIdentifier? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func numSections(in collectionSkeletonView: UICollectionView) -> Int { return 1 }
|
||||
}
|
||||
|
||||
public protocol SkeletonCollectionViewDelegate: UICollectionViewDelegate { }
|
||||
|
||||
|
||||
@@ -9,24 +9,23 @@
|
||||
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? {
|
||||
get { return objc_getAssociatedObject(self, &CollectionAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
|
||||
get { return ao_get(pkey: &CollectionAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
|
||||
set {
|
||||
objc_setAssociatedObject(self, &CollectionAssociatedKeys.dummyDataSource, newValue, AssociationPolicy.retain.objc)
|
||||
ao_setOptional(newValue, pkey: &CollectionAssociatedKeys.dummyDataSource)
|
||||
self.dataSource = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var skeletonDelegate: SkeletonCollectionDelegate? {
|
||||
get { return objc_getAssociatedObject(self, &CollectionAssociatedKeys.dummyDelegate) as? SkeletonCollectionDelegate }
|
||||
get { return ao_get(pkey: &CollectionAssociatedKeys.dummyDelegate) as? SkeletonCollectionDelegate }
|
||||
set {
|
||||
objc_setAssociatedObject(self, &CollectionAssociatedKeys.dummyDelegate, newValue, AssociationPolicy.retain.objc)
|
||||
ao_setOptional(newValue, pkey: &CollectionAssociatedKeys.dummyDelegate)
|
||||
self.delegate = newValue
|
||||
}
|
||||
}
|
||||
@@ -41,6 +40,14 @@ extension UICollectionView: CollectionSkeleton {
|
||||
reloadData()
|
||||
}
|
||||
|
||||
func updateDummyDataSource() {
|
||||
if (dataSource as? SkeletonCollectionDataSource) != nil {
|
||||
reloadData()
|
||||
} else {
|
||||
addDummyDataSource()
|
||||
}
|
||||
}
|
||||
|
||||
func removeDummyDataSource(reloadAfter: Bool) {
|
||||
guard let dataSource = self.dataSource as? SkeletonCollectionDataSource else { return }
|
||||
self.skeletonDataSource = nil
|
||||
@@ -63,7 +70,7 @@ public extension UICollectionView {
|
||||
self.skeletonDataSource = dataSource
|
||||
performBatchUpdates({
|
||||
self.reloadData()
|
||||
}) { (done) in
|
||||
}) { done in
|
||||
completion(done)
|
||||
|
||||
}
|
||||
|
||||
@@ -11,51 +11,76 @@ import UIKit
|
||||
public typealias ReusableCellIdentifier = String
|
||||
|
||||
class SkeletonCollectionDataSource: NSObject {
|
||||
|
||||
weak var originalTableViewDataSource: SkeletonTableViewDataSource?
|
||||
weak var originalCollectionViewDataSource: SkeletonCollectionViewDataSource?
|
||||
var rowHeight: CGFloat = 0.0
|
||||
var originalRowHeight: CGFloat = 0.0
|
||||
|
||||
convenience init(tableViewDataSource: SkeletonTableViewDataSource? = nil, collectionViewDataSource: SkeletonCollectionViewDataSource? = nil, rowHeight: CGFloat = 0.0) {
|
||||
convenience init(tableViewDataSource: SkeletonTableViewDataSource? = nil, collectionViewDataSource: SkeletonCollectionViewDataSource? = nil, rowHeight: CGFloat = 0.0, originalRowHeight: CGFloat = 0.0) {
|
||||
self.init()
|
||||
self.originalTableViewDataSource = tableViewDataSource
|
||||
self.originalCollectionViewDataSource = collectionViewDataSource
|
||||
self.rowHeight = rowHeight
|
||||
self.originalRowHeight = originalRowHeight
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
extension SkeletonCollectionDataSource: UITableViewDataSource {
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return originalTableViewDataSource?.numSections(in:tableView) ?? 0
|
||||
originalTableViewDataSource?.numSections(in: tableView) ?? 0
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return originalTableViewDataSource?.collectionSkeletonView(tableView, numberOfRowsInSection:section) ?? 0
|
||||
originalTableViewDataSource?.collectionSkeletonView(tableView, numberOfRowsInSection: section) ?? 0
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cellIdentifier = originalTableViewDataSource?.collectionSkeletonView(tableView, cellIdentifierForRowAt: indexPath) ?? ""
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
|
||||
skeletonViewIfContainerSkeletonIsActive(container: tableView, view: cell)
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDataSource
|
||||
extension SkeletonCollectionDataSource: UICollectionViewDataSource {
|
||||
|
||||
func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||
return originalCollectionViewDataSource?.numSections(in: collectionView) ?? 0
|
||||
originalCollectionViewDataSource?.numSections(in: collectionView) ?? 0
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return originalCollectionViewDataSource?.collectionSkeletonView(collectionView, numberOfItemsInSection: section) ?? 0
|
||||
originalCollectionViewDataSource?.collectionSkeletonView(collectionView, numberOfItemsInSection: section) ?? 0
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cellIdentifier = originalCollectionViewDataSource?.collectionSkeletonView(collectionView, cellIdentifierForItemAt: indexPath) ?? ""
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath)
|
||||
skeletonViewIfContainerSkeletonIsActive(container: collectionView, view: cell)
|
||||
return cell
|
||||
}
|
||||
|
||||
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)
|
||||
skeletonViewIfContainerSkeletonIsActive(container: collectionView, view: view)
|
||||
return view
|
||||
}
|
||||
|
||||
return UICollectionReusableView()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SkeletonCollectionDataSource {
|
||||
private func skeletonViewIfContainerSkeletonIsActive(container: UIView, view: UIView) {
|
||||
guard container.isSkeletonActive,
|
||||
let skeletonConfig = container.currentSkeletonConfig else {
|
||||
return
|
||||
}
|
||||
|
||||
view.showSkeleton(skeletonConfig: skeletonConfig)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
import UIKit
|
||||
|
||||
class SkeletonCollectionDelegate: NSObject {
|
||||
|
||||
weak var originalTableViewDelegate: SkeletonTableViewDelegate?
|
||||
weak var originalCollectionViewDelegate: SkeletonCollectionViewDelegate?
|
||||
|
||||
@@ -19,8 +18,48 @@ class SkeletonCollectionDelegate: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
extension SkeletonCollectionDelegate: UITableViewDelegate { }
|
||||
// MARK: - UITableViewDelegate
|
||||
extension SkeletonCollectionDelegate: UITableViewDelegate {
|
||||
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
headerOrFooterView(tableView, for: originalTableViewDelegate?.collectionSkeletonView(tableView, identifierForHeaderInSection: section))
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDataSource
|
||||
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
||||
headerOrFooterView(tableView, for: originalTableViewDelegate?.collectionSkeletonView(tableView, identifierForHeaderInSection: section))
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didEndDisplayingHeaderView view: UIView, forSection section: Int) {
|
||||
view.hideSkeleton()
|
||||
originalTableViewDelegate?.tableView?(tableView, didEndDisplayingHeaderView: view, forSection: section)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didEndDisplayingFooterView view: UIView, forSection section: Int) {
|
||||
view.hideSkeleton()
|
||||
originalTableViewDelegate?.tableView?(tableView, didEndDisplayingFooterView: view, forSection: section)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||
cell.hideSkeleton()
|
||||
originalTableViewDelegate?.tableView?(tableView, didEndDisplaying: cell, forRowAt: indexPath)
|
||||
}
|
||||
|
||||
private func headerOrFooterView(_ tableView: UITableView, for viewIdentifier: String? ) -> UIView? {
|
||||
guard let viewIdentifier = viewIdentifier, let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: viewIdentifier) else { return nil }
|
||||
skeletonViewIfContainerSkeletonIsActive(container: tableView, view: header)
|
||||
return header
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDelegate
|
||||
extension SkeletonCollectionDelegate: UICollectionViewDelegate { }
|
||||
|
||||
extension SkeletonCollectionDelegate {
|
||||
private func skeletonViewIfContainerSkeletonIsActive(container: UIView, view: UIView) {
|
||||
guard container.isSkeletonActive,
|
||||
let skeletonConfig = container.currentSkeletonConfig else {
|
||||
return
|
||||
}
|
||||
|
||||
view.showSkeleton(skeletonConfig: skeletonConfig)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ public protocol SkeletonTableViewDataSource: UITableViewDataSource {
|
||||
}
|
||||
|
||||
public extension SkeletonTableViewDataSource {
|
||||
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return skeletonView.estimatedNumberOfRows
|
||||
}
|
||||
@@ -31,4 +30,16 @@ public extension SkeletonTableViewDataSource {
|
||||
}
|
||||
|
||||
public protocol SkeletonTableViewDelegate: UITableViewDelegate {
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -> ReusableHeaderFooterIdentifier?
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -> ReusableHeaderFooterIdentifier?
|
||||
}
|
||||
|
||||
public extension SkeletonTableViewDelegate {
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -> ReusableHeaderFooterIdentifier? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -> ReusableHeaderFooterIdentifier? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,24 +8,25 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
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? {
|
||||
get { return objc_getAssociatedObject(self, &CollectionAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
|
||||
get { return ao_get(pkey: &CollectionAssociatedKeys.dummyDataSource) as? SkeletonCollectionDataSource }
|
||||
set {
|
||||
objc_setAssociatedObject(self, &CollectionAssociatedKeys.dummyDataSource, newValue, AssociationPolicy.retain.objc)
|
||||
ao_setOptional(newValue, pkey: &CollectionAssociatedKeys.dummyDataSource)
|
||||
self.dataSource = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var skeletonDelegate: SkeletonCollectionDelegate? {
|
||||
get { return objc_getAssociatedObject(self, &CollectionAssociatedKeys.dummyDelegate) as? SkeletonCollectionDelegate }
|
||||
get { return ao_get(pkey: &CollectionAssociatedKeys.dummyDelegate) as? SkeletonCollectionDelegate }
|
||||
set {
|
||||
objc_setAssociatedObject(self, &CollectionAssociatedKeys.dummyDelegate, newValue, AssociationPolicy.retain.objc)
|
||||
ao_setOptional(newValue, pkey: &CollectionAssociatedKeys.dummyDelegate)
|
||||
self.delegate = newValue
|
||||
}
|
||||
}
|
||||
@@ -34,27 +35,51 @@ extension UITableView: CollectionSkeleton {
|
||||
guard let originalDataSource = self.dataSource as? SkeletonTableViewDataSource,
|
||||
!(originalDataSource is SkeletonCollectionDataSource)
|
||||
else { return }
|
||||
let dataSource = SkeletonCollectionDataSource(tableViewDataSource: originalDataSource, rowHeight: calculateRowHeight())
|
||||
let calculatedRowHeight = calculateRowHeight()
|
||||
let dataSource = SkeletonCollectionDataSource(tableViewDataSource: originalDataSource,
|
||||
rowHeight: rowHeight,
|
||||
originalRowHeight: self.rowHeight)
|
||||
rowHeight = calculatedRowHeight
|
||||
self.skeletonDataSource = dataSource
|
||||
|
||||
if let originalDelegate = self.delegate as? SkeletonTableViewDelegate,
|
||||
!(originalDelegate is SkeletonCollectionDelegate) {
|
||||
let delegate = SkeletonCollectionDelegate(tableViewDelegate: originalDelegate)
|
||||
self.skeletonDelegate = delegate
|
||||
}
|
||||
|
||||
reloadData()
|
||||
}
|
||||
|
||||
func updateDummyDataSource() {
|
||||
if (dataSource as? SkeletonCollectionDataSource) != nil {
|
||||
reloadData()
|
||||
} else {
|
||||
addDummyDataSource()
|
||||
}
|
||||
}
|
||||
|
||||
func removeDummyDataSource(reloadAfter: Bool) {
|
||||
guard let dataSource = self.dataSource as? SkeletonCollectionDataSource else { return }
|
||||
restoreRowHeight()
|
||||
self.skeletonDataSource = nil
|
||||
self.dataSource = dataSource.originalTableViewDataSource
|
||||
|
||||
if let delegate = self.delegate as? SkeletonCollectionDelegate {
|
||||
self.skeletonDelegate = nil
|
||||
self.delegate = delegate.originalTableViewDelegate
|
||||
}
|
||||
|
||||
if reloadAfter { self.reloadData() }
|
||||
}
|
||||
|
||||
private func restoreRowHeight() {
|
||||
guard let dataSource = self.dataSource as? SkeletonCollectionDataSource else { return }
|
||||
rowHeight = dataSource.rowHeight
|
||||
rowHeight = dataSource.originalRowHeight
|
||||
}
|
||||
|
||||
private func calculateRowHeight() -> CGFloat {
|
||||
guard rowHeight == UITableViewAutomaticDimension else { return rowHeight }
|
||||
rowHeight = estimatedRowHeight
|
||||
guard rowHeight == UITableView.automaticDimension else { return rowHeight }
|
||||
return estimatedRowHeight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,23 @@ import UIKit
|
||||
|
||||
extension UIView {
|
||||
func addDummyDataSourceIfNeeded() {
|
||||
guard let collection = self as? CollectionSkeleton else { return }
|
||||
guard let collection = self as? CollectionSkeleton,
|
||||
!ProcessInfo.isRunningXCTest else { return }
|
||||
status = .on
|
||||
collection.addDummyDataSource()
|
||||
collection.disableUserInteraction()
|
||||
}
|
||||
|
||||
func updateDummyDataSourceIfNeeded() {
|
||||
guard let collection = self as? CollectionSkeleton,
|
||||
!ProcessInfo.isRunningXCTest else { return }
|
||||
collection.updateDummyDataSource()
|
||||
}
|
||||
|
||||
func removeDummyDataSourceIfNeeded(reloadAfter reload: Bool = true) {
|
||||
guard let collection = self as? CollectionSkeleton else { return }
|
||||
guard let collection = self as? CollectionSkeleton,
|
||||
!ProcessInfo.isRunningXCTest else { return }
|
||||
status = .off
|
||||
collection.removeDummyDataSource(reloadAfter: reload)
|
||||
collection.enableUserInteraction()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
enum SkeletonEnvironmentKey: String {
|
||||
case debugMode = "SKELETON_DEBUG"
|
||||
}
|
||||
|
||||
extension Dictionary {
|
||||
subscript (_ key: SkeletonEnvironmentKey) -> Value? {
|
||||
// swiftlint:disable:next force_cast
|
||||
return self[key.rawValue as! Key]
|
||||
}
|
||||
}
|
||||
|
||||
func printSkeletonHierarchy(in view: UIView) {
|
||||
skeletonLog(view.skeletonHierarchy())
|
||||
}
|
||||
|
||||
func skeletonLog(_ message: String) {
|
||||
if ProcessInfo.processInfo.environment[.debugMode] != nil {
|
||||
print(message)
|
||||
}
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
public var skeletonDescription: String {
|
||||
var description = "<\(type(of: self)): \(Unmanaged.passUnretained(self).toOpaque())"
|
||||
let subSkeletons = subviewsSkeletonables
|
||||
if !subSkeletons.isEmpty {
|
||||
description += " | (\(subSkeletons.count)) subSkeletons"
|
||||
}
|
||||
if isSkeletonable {
|
||||
description += " | ☠️ "
|
||||
}
|
||||
return description + ">"
|
||||
}
|
||||
|
||||
public func skeletonHierarchy(index: Int = 0) -> String {
|
||||
var description = index == 0 ? "\n ⬇⬇ ☠️ Root view hierarchy with Skeletons ⬇⬇ \n" : ""
|
||||
description += "\(index == 0 ? "\n" : 3.whitespaces) \(skeletonDescription) \n"
|
||||
subviewsToSkeleton.forEach {
|
||||
description += (index + 2).whitespaces
|
||||
description += $0.skeletonHierarchy(index: index + 1)
|
||||
}
|
||||
return description
|
||||
}
|
||||
}
|
||||
@@ -10,97 +10,189 @@ import UIKit
|
||||
|
||||
extension CALayer {
|
||||
@objc func tint(withColors colors: [UIColor]) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { backgroundColor = colors.first?.cgColor }) {
|
||||
$0.tint(withColors: colors)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
backgroundColor = colors.first?.cgColor
|
||||
}) {
|
||||
$0.tint(withColors: colors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CAGradientLayer {
|
||||
override func tint(withColors colors: [UIColor]) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { self.colors = colors.map { $0.cgColor } }) {
|
||||
$0.tint(withColors: colors)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
self.colors = colors.map { $0.cgColor }
|
||||
}) {
|
||||
$0.tint(withColors: colors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SkeletonMultilinesLayerConfig {
|
||||
var lines: Int
|
||||
var lineHeight: CGFloat
|
||||
var type: SkeletonType
|
||||
var lastLineFillPercent: Int
|
||||
var multilineCornerRadius: Int
|
||||
var multilineSpacing: CGFloat
|
||||
var paddingInsets: UIEdgeInsets
|
||||
var isRTL: Bool
|
||||
|
||||
/// Returns padding insets taking into account if the RTL is activated
|
||||
var calculatedPaddingInsets: UIEdgeInsets {
|
||||
UIEdgeInsets(top: paddingInsets.top,
|
||||
left: isRTL ? paddingInsets.right : paddingInsets.left,
|
||||
bottom: paddingInsets.bottom,
|
||||
right: isRTL ? paddingInsets.left : paddingInsets.right)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Skeleton sublayers
|
||||
extension CALayer {
|
||||
|
||||
static let skeletonSubLayersName = "SkeletonSubLayersName"
|
||||
|
||||
var skeletonSublayers: [CALayer] {
|
||||
return sublayers?.filter { $0.name == CALayer.skeletonSubLayersName } ?? [CALayer]()
|
||||
}
|
||||
|
||||
func addMultilinesLayers(lines: Int, type: SkeletonType, lastLineFillPercent: Int, multilineCornerRadius: Int) {
|
||||
let numberOfSublayers = calculateNumLines(maxLines: lines)
|
||||
for index in 0..<numberOfSublayers {
|
||||
var width = bounds.width
|
||||
|
||||
if index == numberOfSublayers-1 && numberOfSublayers != 1 {
|
||||
width = width * CGFloat(lastLineFillPercent)/100;
|
||||
func addMultilinesLayers(for config: SkeletonMultilinesLayerConfig) {
|
||||
let numberOfSublayers = config.lines > 0 ? config.lines : calculateNumLines(for: config)
|
||||
var height = config.lineHeight
|
||||
|
||||
if numberOfSublayers == 1 && SkeletonAppearance.default.renderSingleLineAsView {
|
||||
height = bounds.height
|
||||
}
|
||||
|
||||
let layerBuilder = SkeletonMultilineLayerBuilder()
|
||||
.setSkeletonType(config.type)
|
||||
.setCornerRadius(config.multilineCornerRadius)
|
||||
.setMultilineSpacing(config.multilineSpacing)
|
||||
.setPadding(config.paddingInsets)
|
||||
.setHeight(height)
|
||||
.setIsRTL(config.isRTL)
|
||||
|
||||
(0..<numberOfSublayers).forEach { index in
|
||||
let width = calculatedWidthForLine(at: index, totalLines: numberOfSublayers, lastLineFillPercent: config.lastLineFillPercent, paddingInsets: config.paddingInsets)
|
||||
if let layer = layerBuilder
|
||||
.setIndex(index)
|
||||
.setWidth(width)
|
||||
.build() {
|
||||
addSublayer(layer)
|
||||
}
|
||||
|
||||
let layer = SkeletonLayerFactory().makeMultilineLayer(withType: type, for: index, width: width, multilineCornerRadius: multilineCornerRadius)
|
||||
addSublayer(layer)
|
||||
}
|
||||
}
|
||||
|
||||
func updateMultilinesLayers(for config: SkeletonMultilinesLayerConfig) {
|
||||
let currentSkeletonSublayers = skeletonSublayers
|
||||
let numberOfSublayers = currentSkeletonSublayers.count
|
||||
let lastLineFillPercent = config.lastLineFillPercent
|
||||
let paddingInsets = config.calculatedPaddingInsets
|
||||
let multilineSpacing = config.multilineSpacing
|
||||
var height = config.lineHeight
|
||||
|
||||
if numberOfSublayers == 1 && SkeletonAppearance.default.renderSingleLineAsView {
|
||||
height = bounds.height
|
||||
}
|
||||
|
||||
for (index, layer) in currentSkeletonSublayers.enumerated() {
|
||||
let width = calculatedWidthForLine(at: index, totalLines: numberOfSublayers, lastLineFillPercent: lastLineFillPercent, paddingInsets: paddingInsets)
|
||||
layer.updateLayerFrame(for: index,
|
||||
size: CGSize(width: width, height: height),
|
||||
multilineSpacing: multilineSpacing,
|
||||
paddingInsets: paddingInsets,
|
||||
isRTL: config.isRTL)
|
||||
}
|
||||
}
|
||||
|
||||
private func calculatedWidthForLine(at index: Int, totalLines: Int, lastLineFillPercent: Int, paddingInsets: UIEdgeInsets) -> CGFloat {
|
||||
var width = bounds.width - paddingInsets.left - paddingInsets.right
|
||||
if index == totalLines - 1 && totalLines != 1 {
|
||||
width = width * CGFloat(lastLineFillPercent) / 100
|
||||
}
|
||||
return width
|
||||
}
|
||||
|
||||
func updateLayerFrame(for index: Int, size: CGSize, multilineSpacing: CGFloat, paddingInsets: UIEdgeInsets, isRTL: Bool) {
|
||||
let spaceRequiredForEachLine = size.height + multilineSpacing
|
||||
let newFrame = CGRect(x: paddingInsets.left,
|
||||
y: CGFloat(index) * spaceRequiredForEachLine + paddingInsets.top,
|
||||
width: size.width,
|
||||
height: size.height)
|
||||
|
||||
frame = flipRectForRTLIfNeeded(newFrame, isRTL: isRTL)
|
||||
}
|
||||
|
||||
private func calculateNumLines(maxLines: Int) -> Int {
|
||||
let spaceRequitedForEachLine = SkeletonAppearance.default.multilineHeight + SkeletonAppearance.default.multilineSpacing
|
||||
var numberOfSublayers = Int(round(CGFloat(bounds.height)/CGFloat(spaceRequitedForEachLine)))
|
||||
if maxLines != 0, maxLines <= numberOfSublayers { numberOfSublayers = maxLines }
|
||||
return numberOfSublayers
|
||||
private func calculateNumLines(for config: SkeletonMultilinesLayerConfig) -> Int {
|
||||
let definedNumberOfLines = config.lines
|
||||
let requiredSpaceForEachLine = config.lineHeight + config.multilineSpacing
|
||||
let calculatedNumberOfLines = Int(round(CGFloat(bounds.height - config.paddingInsets.top - config.paddingInsets.bottom) / CGFloat(requiredSpaceForEachLine)))
|
||||
|
||||
guard calculatedNumberOfLines > 0 else {
|
||||
return 1
|
||||
}
|
||||
|
||||
if definedNumberOfLines > 0, definedNumberOfLines <= calculatedNumberOfLines {
|
||||
return definedNumberOfLines
|
||||
}
|
||||
|
||||
return calculatedNumberOfLines
|
||||
}
|
||||
|
||||
private func flipRectForRTLIfNeeded(_ rect: CGRect, isRTL: Bool) -> CGRect {
|
||||
var newRect = rect
|
||||
if isRTL {
|
||||
newRect.origin.x = (superlayer?.bounds.width ?? 0) - rect.origin.x - rect.width
|
||||
}
|
||||
return newRect
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Animations
|
||||
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: kCAMediaTimingFunctionEaseInEaseOut)
|
||||
pulseAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
|
||||
pulseAnimation.autoreverses = true
|
||||
pulseAnimation.repeatCount = .infinity
|
||||
pulseAnimation.isRemovedOnCompletion = false
|
||||
return pulseAnimation
|
||||
}
|
||||
|
||||
var sliding: CAAnimation {
|
||||
let startPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.startPoint))
|
||||
startPointAnim.fromValue = CGPoint(x: -1, y: 0.5)
|
||||
startPointAnim.toValue = CGPoint(x:1, y: 0.5)
|
||||
|
||||
let endPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.endPoint))
|
||||
endPointAnim.fromValue = CGPoint(x: 0, y: 0.5)
|
||||
endPointAnim.toValue = CGPoint(x:2, y: 0.5)
|
||||
|
||||
let animGroup = CAAnimationGroup()
|
||||
animGroup.animations = [startPointAnim, endPointAnim]
|
||||
animGroup.duration = 1.5
|
||||
animGroup.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
|
||||
animGroup.repeatCount = .infinity
|
||||
|
||||
return animGroup
|
||||
}
|
||||
|
||||
func playAnimation(_ anim: SkeletonLayerAnimation, key: String) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { add(anim(self), forKey: key) }) {
|
||||
$0.playAnimation(anim, key: key)
|
||||
func playAnimation(_ anim: SkeletonLayerAnimation, key: String, completion: (() -> Void)? = nil) {
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
DispatchQueue.main.async { CATransaction.begin() }
|
||||
DispatchQueue.main.async { CATransaction.setCompletionBlock(completion) }
|
||||
add(anim(self), forKey: key)
|
||||
DispatchQueue.main.async { CATransaction.commit() }
|
||||
}) {
|
||||
$0.playAnimation(anim, key: key, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
func stopAnimation(forKey key: String) {
|
||||
recursiveSearch(inArray: skeletonSublayers,
|
||||
leafBlock: { removeAnimation(forKey: key) }) {
|
||||
$0.stopAnimation(forKey: key)
|
||||
skeletonSublayers.recursiveSearch(leafBlock: {
|
||||
removeAnimation(forKey: key)
|
||||
}) {
|
||||
$0.stopAnimation(forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CALayer {
|
||||
func setOpacity(from: Int, to: Int, duration: TimeInterval, completion: (() -> Void)?) {
|
||||
DispatchQueue.main.async { CATransaction.begin() }
|
||||
let animation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))
|
||||
animation.fromValue = from
|
||||
animation.toValue = to
|
||||
animation.duration = duration
|
||||
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
|
||||
DispatchQueue.main.async { CATransaction.setCompletionBlock(completion) }
|
||||
add(animation, forKey: "setOpacityAnimation")
|
||||
DispatchQueue.main.async { CATransaction.commit() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Int {
|
||||
var whitespace: String {
|
||||
whitespaces
|
||||
}
|
||||
|
||||
var whitespaces: String {
|
||||
String(repeating: " ", count: self)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright © 2020 SkeletonView. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension ProcessInfo {
|
||||
enum Constants {
|
||||
static let testConfigurationFilePathKey = "XCTestConfigurationFilePath"
|
||||
}
|
||||
|
||||
static var isRunningXCTest: Bool {
|
||||
return processInfo.environment[Constants.testConfigurationFilePathKey] != nil
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,9 @@
|
||||
//
|
||||
// UIColor+Skeleton.swift
|
||||
// SkeletonView-iOS
|
||||
//
|
||||
// Created by Juanpe Catalán on 03/11/2017.
|
||||
// Copyright © 2017 SkeletonView. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
// codebeat:disable[TOO_MANY_IVARS]
|
||||
extension UIColor {
|
||||
|
||||
convenience init(_ hex: UInt) {
|
||||
self.init(
|
||||
red: CGFloat((hex & 0xFF0000) >> 16) / 255.0,
|
||||
@@ -20,23 +14,28 @@ extension UIColor {
|
||||
}
|
||||
|
||||
func isLight() -> Bool {
|
||||
// algorithm from: http://www.w3.org/WAI/ER/WD-AERT/#color-contrast
|
||||
guard let components = cgColor.components,
|
||||
components.count >= 3 else { return false }
|
||||
components.count >= 3 else { return false }
|
||||
let brightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000
|
||||
return !(brightness < 0.5)
|
||||
}
|
||||
|
||||
public var complementaryColor: UIColor {
|
||||
return isLight() ? darker : lighter
|
||||
if #available(iOS 13, tvOS 13, *) {
|
||||
return UIColor { _ in
|
||||
return self.isLight() ? self.darker : self.lighter
|
||||
}
|
||||
} else {
|
||||
return isLight() ? darker : lighter
|
||||
}
|
||||
}
|
||||
|
||||
public var lighter: UIColor {
|
||||
return adjust(by: 1.35)
|
||||
adjust(by: 1.35)
|
||||
}
|
||||
|
||||
public var darker: UIColor {
|
||||
return adjust(by: 0.94)
|
||||
adjust(by: 0.94)
|
||||
}
|
||||
|
||||
func adjust(by percent: CGFloat) -> UIColor {
|
||||
@@ -46,11 +45,12 @@ extension UIColor {
|
||||
}
|
||||
|
||||
func makeGradient() -> [UIColor] {
|
||||
return [self, self.complementaryColor, self]
|
||||
[self, self.complementaryColor, self]
|
||||
}
|
||||
}
|
||||
|
||||
public extension UIColor {
|
||||
// swiftlint:disable operator_usage_whitespace
|
||||
static var greenSea = UIColor(0x16a085)
|
||||
static var turquoise = UIColor(0x1abc9c)
|
||||
static var emerald = UIColor(0x2ecc71)
|
||||
@@ -65,11 +65,28 @@ public extension UIColor {
|
||||
static var carrot = UIColor(0xe67e22)
|
||||
static var alizarin = UIColor(0xe74c3c)
|
||||
static var clouds = UIColor(0xecf0f1)
|
||||
static var darkClouds = UIColor(0x1c2325)
|
||||
static var concrete = UIColor(0x95a5a6)
|
||||
static var flatOrange = UIColor(0xf39c12)
|
||||
static var pumpkin = UIColor(0xd35400)
|
||||
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
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .clouds
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// codebeat:enable[TOO_MANY_IVARS]
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright © 2020 SkeletonView. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UITableView {
|
||||
var indexesOfVisibleSections: [Int] {
|
||||
(0..<numberOfSections).reduce([]) {
|
||||
let headerRect: CGRect?
|
||||
|
||||
if self.style == .plain {
|
||||
headerRect = rect(forSection: $1)
|
||||
} else {
|
||||
headerRect = rectForHeader(inSection: $1)
|
||||
}
|
||||
|
||||
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) {
|
||||
return $0 + [$1]
|
||||
}
|
||||
}
|
||||
|
||||
return $0
|
||||
}
|
||||
}
|
||||
|
||||
var visibleSectionHeaders: [UITableViewHeaderFooterView] {
|
||||
indexesOfVisibleSections.compactMap { headerView(forSection: $0) }
|
||||
}
|
||||
|
||||
var visibleSectionFooters: [UITableViewHeaderFooterView] {
|
||||
indexesOfVisibleSections.compactMap { footerView(forSection: $0) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright © 2020 SkeletonView. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
|
||||
// MARK: Frame
|
||||
extension UIView {
|
||||
var widthConstraints: [NSLayoutConstraint] {
|
||||
nonContentSizeLayoutConstraints.filter { $0.firstAttribute == NSLayoutConstraint.Attribute.width }
|
||||
}
|
||||
|
||||
var heightConstraints: [NSLayoutConstraint] {
|
||||
nonContentSizeLayoutConstraints.filter { $0.firstAttribute == NSLayoutConstraint.Attribute.height }
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func setHeight(equalToConstant constant: CGFloat) -> NSLayoutConstraint {
|
||||
let heightConstraint = heightAnchor.constraint(equalToConstant: constant)
|
||||
NSLayoutConstraint.activate([heightConstraint])
|
||||
return heightConstraint
|
||||
}
|
||||
|
||||
var nonContentSizeLayoutConstraints: [NSLayoutConstraint] {
|
||||
constraints.filter({ "\(type(of: $0))" != "NSContentSizeLayoutConstraint" })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright © 2018 SkeletonView. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
|
||||
// codebeat:disable[TOO_MANY_IVARS]
|
||||
enum ViewAssociatedKeys {
|
||||
static var skeletonable = "skeletonable"
|
||||
static var hiddenWhenSkeletonIsActive = "hiddenWhenSkeletonIsActive"
|
||||
static var status = "status"
|
||||
static var skeletonLayer = "layer"
|
||||
static var flowDelegate = "flowDelegate"
|
||||
static var isSkeletonAnimated = "isSkeletonAnimated"
|
||||
static var viewState = "viewState"
|
||||
static var labelViewState = "labelViewState"
|
||||
static var imageViewState = "imageViewState"
|
||||
static var buttonViewState = "buttonViewState"
|
||||
static var currentSkeletonConfig = "currentSkeletonConfig"
|
||||
static var skeletonCornerRadius = "skeletonCornerRadius"
|
||||
}
|
||||
// codebeat:enable[TOO_MANY_IVARS]
|
||||
|
||||
extension UIView {
|
||||
enum Status {
|
||||
case on
|
||||
case off
|
||||
}
|
||||
|
||||
var flowDelegate: SkeletonFlowDelegate? {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.flowDelegate) as? SkeletonFlowDelegate }
|
||||
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.flowDelegate) }
|
||||
}
|
||||
|
||||
var skeletonLayer: SkeletonLayer? {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.skeletonLayer) as? SkeletonLayer }
|
||||
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.skeletonLayer) }
|
||||
}
|
||||
|
||||
var currentSkeletonConfig: SkeletonConfig? {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.currentSkeletonConfig) as? SkeletonConfig }
|
||||
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.currentSkeletonConfig) }
|
||||
}
|
||||
|
||||
var status: Status {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.status) as? Status ?? .off }
|
||||
set { ao_set(newValue, pkey: &ViewAssociatedKeys.status) }
|
||||
}
|
||||
|
||||
var isSkeletonAnimated: Bool {
|
||||
get { return ao_get(pkey: &ViewAssociatedKeys.isSkeletonAnimated) as? Bool ?? false }
|
||||
set { ao_set(newValue, pkey: &ViewAssociatedKeys.isSkeletonAnimated) }
|
||||
}
|
||||
}
|
||||
@@ -10,35 +10,38 @@ import UIKit
|
||||
|
||||
// MARK: Frame
|
||||
extension UIView {
|
||||
|
||||
var maxBoundsEstimated: CGRect {
|
||||
var definedMaxBounds: CGRect {
|
||||
if let parentStackView = (superview as? UIStackView) {
|
||||
var origin: CGPoint = .zero
|
||||
switch parentStackView.alignment {
|
||||
case .center:
|
||||
origin.x = maxWidthEstimated / 2
|
||||
case .trailing:
|
||||
origin.x = maxWidthEstimated
|
||||
origin.x = definedMaxWidth
|
||||
default:
|
||||
break
|
||||
}
|
||||
return CGRect(origin: origin, size: maxSizeEstimated)
|
||||
return CGRect(origin: origin, size: definedMaxSize)
|
||||
}
|
||||
return CGRect(origin: .zero, size: maxSizeEstimated)
|
||||
return CGRect(origin: .zero, size: definedMaxSize)
|
||||
}
|
||||
|
||||
var maxSizeEstimated: CGSize {
|
||||
return CGSize(width: maxWidthEstimated, height: maxHeightEstimated)
|
||||
var definedMaxSize: CGSize {
|
||||
CGSize(width: definedMaxWidth, height: definedMaxHeight)
|
||||
}
|
||||
|
||||
var maxWidthEstimated: CGFloat {
|
||||
let constraintsWidth = nonContentSizeLayoutConstraints.filter({ $0.firstAttribute == NSLayoutAttribute.width })
|
||||
return max(between: frame.size.width, andContantsOf: constraintsWidth)
|
||||
var definedMaxWidth: CGFloat {
|
||||
max(between: frame.size.width, andContantsOf: widthConstraints)
|
||||
}
|
||||
|
||||
var maxHeightEstimated: CGFloat {
|
||||
let constraintsHeight = nonContentSizeLayoutConstraints.filter({ $0.firstAttribute == NSLayoutAttribute.height })
|
||||
return max(between: frame.size.height, andContantsOf: constraintsHeight)
|
||||
var definedMaxHeight: CGFloat {
|
||||
max(between: frame.size.height, andContantsOf: heightConstraints)
|
||||
}
|
||||
|
||||
var isRTL: Bool {
|
||||
if #available(iOS 10.0, *), #available(tvOS 10.0, *) {
|
||||
return effectiveUserInterfaceLayoutDirection == .rightToLeft
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func max(between value: CGFloat, andContantsOf constraints: [NSLayoutConstraint]) -> CGFloat {
|
||||
@@ -49,8 +52,4 @@ extension UIView {
|
||||
})
|
||||
return max
|
||||
}
|
||||
|
||||
var nonContentSizeLayoutConstraints: [NSLayoutConstraint] {
|
||||
return constraints.filter({ "\(type(of: $0))" != "NSContentSizeLayoutConstraint" })
|
||||
}
|
||||
}
|
||||
|
||||