{"id":2284,"url":"https://github.com/Juanpe/SkeletonView","last_synced_at":"2025-08-06T15:30:39.595Z","repository":{"id":37686693,"uuid":"109878485","full_name":"Juanpe/SkeletonView","owner":"Juanpe","description":"☠️ An elegant way to show users that something is happening and also prepare them to which contents they are awaiting","archived":false,"fork":false,"pushed_at":"2024-08-06T18:38:09.000Z","size":6491,"stargazers_count":12626,"open_issues_count":88,"forks_count":1118,"subscribers_count":125,"default_branch":"main","last_synced_at":"2024-11-29T20:51:15.731Z","etag":null,"topics":["animation","carthage","facebook","facebook-animation","gradients","hacktoberfest","ios","ios-animation","ios-uiview","loading","loading-animation","loading-animations","placeholder","redacted","shimmer","skeleton","swift","swift-package-manager","uicollectionview","uitableview"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Juanpe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["juanpe"]}},"created_at":"2017-11-07T19:05:28.000Z","updated_at":"2024-11-28T09:56:24.000Z","dependencies_parsed_at":"2023-11-08T04:06:40.072Z","dependency_job_id":"dbf01285-853e-4217-9c40-74f53938ca68","html_url":"https://github.com/Juanpe/SkeletonView","commit_stats":{"total_commits":733,"total_committers":81,"mean_commits":9.049382716049383,"dds":0.5252387448840382,"last_synced_commit":"30c92f0992888e7b249e788405ac31e2103f5c69"},"previous_names":[],"tags_count":74,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Juanpe%2FSkeletonView","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Juanpe%2FSkeletonView/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Juanpe%2FSkeletonView/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Juanpe%2FSkeletonView/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Juanpe","download_url":"https://codeload.github.com/Juanpe/SkeletonView/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228879603,"owners_count":17985713,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","carthage","facebook","facebook-animation","gradients","hacktoberfest","ios","ios-animation","ios-uiview","loading","loading-animation","loading-animations","placeholder","redacted","shimmer","skeleton","swift","swift-package-manager","uicollectionview","uitableview"],"created_at":"2024-01-05T20:16:09.804Z","updated_at":"2024-12-09T15:30:52.849Z","avatar_url":"https://github.com/Juanpe.png","language":"Swift","readme":"![](Assets/header2.jpg)\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/Juanpe/SkeletonView/actions?query=workflow%3ACI\"\u003e\n      \u003cimg src=\"https://github.com/Juanpe/SkeletonView/workflows/CI/badge.svg\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://codebeat.co/projects/github-com-juanpe-skeletonview-main\"\u003e\u003cimg alt=\"codebeat badge\" src=\"https://codebeat.co/badges/1f37bbab-a1c8-4a4a-94d7-f21740d461e9\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://cocoapods.org/pods/SkeletonView\"\u003e\u003cimg src=\"https://img.shields.io/cocoapods/v/SkeletonView.svg?style=flat\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/Carthage/Carthage/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://swift.org/package-manager/\"\u003e\u003cimg src=\"https://img.shields.io/badge/SPM-supported-Green.svg?style=flat\"\u003e\u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FJuanpe%2FSkeletonView%2Fbadge%3Ftype%3Dplatforms\"/\u003e\n    \u003ca href=\"https://badge.bow-swift.io/recipe?name=SkeletonView\u0026description=An%20elegant%20way%20to%20show%20users%20that%20something%20is%20happening%20and%20also%20prepare%20them%20to%20which%20contents%20he%20is%20waiting\u0026url=https://github.com/juanpe/skeletonview\u0026owner=Juanpe\u0026avatar=https://avatars0.githubusercontent.com/u/1409041?v=4\u0026tag=1.20.0\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/bow-swift/bow-art/master/badges/nef-playgrounds-badge.svg\" alt=\"SkeletonView Playground\" style=\"height:20px\"\u003e\u003c/a\u003e   \n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"#-features\"\u003eFeatures\u003c/a\u003e\n  • \u003ca href=\"#-guides\"\u003eGuides\u003c/a\u003e\n  • \u003ca href=\"#-installation\"\u003eInstallation\u003c/a\u003e\n  • \u003ca href=\"#-usage\"\u003eUsage\u003c/a\u003e\n  • \u003ca href=\"#-miscellaneous\"\u003eMiscellaneous\u003c/a\u003e\n  • \u003ca href=\"#️-contributing\"\u003eContributing\u003c/a\u003e\n\u003c/p\u003e\n\n**🌎 README is available in other languages:  [🇪🇸](Translations/README_es.md) . [🇨🇳](Translations/README_zh.md) . [🇧🇷](Translations/README_pt-br.md) . [🇰🇷](Translations/README_ko.md) . [🇫🇷](Translations/README_fr.md) . [🇩🇪](Translations/README_de.md)**\n\nToday 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.\n\n**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.\n\nEnjoy it! 🙂\n\n\n##\n- [🌟 Features](#-features)\n- [🎬 Guides](#-guides)\n- [📲 Installation](#-installation)\n- [🐒 Usage](#-usage)\n  - [🌿 Collections](#-collections)\n  - [🔠 Texts](#-texts)\n  - [🦋 Appearance](#-appearance)\n  - [🎨 Custom colors](#-custom-colors)\n  - [🏃‍♀️ Animations](#️-animations)\n  - [🏄 Transitions](#-transitions)\n- [✨ Miscellaneous](#-miscellaneous)\n- [❤️ Contributing](#️-contributing)\n- [📢 Mentions](#-mentions)\n- [🏆 Sponsors](#-sponsors)\n- [👨🏻‍💻 Author](#-author)\n- [👮🏻 License](#-license)\n\n\n\n## 🌟 Features\n\n* Easy to use\n* All UIViews are skeletonables\n* Fully customizable\n* Universal (iPhone \u0026 iPad)\n* Interface Builder friendly\n* Simple Swift syntax\n* Lightweight readable codebase\n\n\n## 🎬 Guides\n\n| [![](https://img.youtube.com/vi/75kgOhWsPNA/maxresdefault.jpg)](https://youtu.be/75kgOhWsPNA)|[![](https://img.youtube.com/vi/MVCiM_VdxVA/maxresdefault.jpg)](https://youtu.be/MVCiM_VdxVA)|[![](https://img.youtube.com/vi/Qq3Evspeea8/maxresdefault.jpg)](https://youtu.be/Qq3Evspeea8)|[![](https://img.youtube.com/vi/Zx1Pg1gPfxA/maxresdefault.jpg)](https://www.youtube.com/watch?v=Zx1Pg1gPfxA)\n|:---:  | :---:  | :---: | :---:\n|[**SkeletonView Guides - Getting started**](https://youtu.be/75kgOhWsPNA)|[**How to Create Loading View with Skeleton View in Swift 5.2**](https://youtu.be/MVCiM_VdxVA)    by iKh4ever Studio|[**Create Skeleton Loading View in App (Swift 5) - Xcode 11, 2020**](https://youtu.be/Qq3Evspeea8)    by iOS Academy| [**Cómo crear una ANIMACIÓN de CARGA de DATOS en iOS**](https://www.youtube.com/watch?v=Zx1Pg1gPfxA) by MoureDev\n\n\n## 📲 Installation\n\n* [CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html):\n\n```ruby\npod 'SkeletonView'\n```\n\n* [Carthage](https://github.com/Carthage/Carthage):\n\n```ruby\ngithub \"Juanpe/SkeletonView\"\n```\n\n* [Swift Package Manager](https://swift.org/package-manager/):\n\n```swift\ndependencies: [\n  .package(url: \"https://github.com/Juanpe/SkeletonView.git\", from: \"1.7.0\")\n]\n```\n\n\u003e 📣 **IMPORTANT!** \n\u003e\n\u003e Since version 1.30.0, `SkeletonView` supports **XCFrameworks**, so if you want to install it as a **XCFramework**, please use [this repo](https://github.com/Juanpe/SkeletonView-XCFramework.git) instead.\n\n\n## 🐒 Usage\n\nOnly **3** steps needed to use `SkeletonView`:\n\n1️⃣ Import SkeletonView in proper place.\n```swift\nimport SkeletonView\n```\n\n2️⃣ Now, set which views will be `skeletonables`. You achieve this in two ways:\n\n**Using code:**\n```swift\navatarImageView.isSkeletonable = true\n```\n**Using IB/Storyboards:**\n\n![](Assets/storyboard.png)\n\n3️⃣ Once you've set the views, you can show the **skeleton**. To do so, you have **4** choices:\n\n```swift\n(1) view.showSkeleton()                 // Solid\n(2) view.showGradientSkeleton()         // Gradient\n(3) view.showAnimatedSkeleton()         // Solid animated\n(4) view.showAnimatedGradientSkeleton() // Gradient animated\n```\n\n**Preview**\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd width=\"25%\"\u003e\n\u003ccenter\u003eSolid\u003c/center\u003e\n\u003c/td\u003e\n\u003ctd width=\"25%\"\u003e\n\u003ccenter\u003eGradient\u003c/center\u003e\n\u003c/td\u003e\n\u003ctd width=\"25%\"\u003e\n\u003ccenter\u003eSolid Animated\u003c/center\u003e\n\u003c/td\u003e\n\u003ctd width=\"25%\"\u003e\n\u003ccenter\u003eGradient Animated\u003c/center\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd width=\"25%\"\u003e\n\u003cimg src=\"Assets/solid.png\"\u003e\u003c/img\u003e\n\u003c/td\u003e\n\u003ctd width=\"25%\"\u003e\n\u003cimg src=\"Assets/gradient.png\"\u003e\u003c/img\u003e\n\u003c/td\u003e\n\u003ctd width=\"25%\"\u003e\n\u003cimg src=\"Assets/solid_animated.gif\"\u003e\u003c/img\u003e\n\u003c/td\u003e\n\u003ctd width=\"25%\"\u003e\n\u003cimg src=\"Assets/gradient_animated.gif\"\u003e\u003c/img\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n\n\u003e 📣 **IMPORTANT!** \n\u003e\n\u003e `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`.\n\n  \n\n\n### 🌿 Collections\n\n```SkeletonView``` is compatible with ```UITableView``` and ```UICollectionView```.\n\n\n**UITableView**\n\nIf you want to show the skeleton in a ```UITableView```, you need to conform to ```SkeletonTableViewDataSource``` protocol.\n\n``` swift\npublic protocol SkeletonTableViewDataSource: UITableViewDataSource {\n    func numSections(in collectionSkeletonView: UITableView) -\u003e Int // Default: 1\n    func collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -\u003e Int\n    func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -\u003e ReusableCellIdentifier\n    func collectionSkeletonView(_ skeletonView: UITableView, skeletonCellForRowAt indexPath: IndexPath) -\u003e UITableViewCell? // Default: nil\n    func collectionSkeletonView(_ skeletonView: UITableView, prepareCellForSkeleton cell: UITableViewCell, at indexPath: IndexPath)\n}\n```\nAs you can see, this protocol inherits from ```UITableViewDataSource```, so you can replace this protocol with the skeleton protocol.\n\nThis protocol has a default implementation for some methods. For example, the number of rows for each section is calculated in runtime:\n\n``` swift\nfunc collectionSkeletonView(_ skeletonView: UITableView, numberOfRowsInSection section: Int) -\u003e Int\n// Default:\n// It calculates how many cells need to populate whole tableview\n```\n\n\u003e 📣 **IMPORTANT!** \n\u003e\n\u003e If you return `UITableView.automaticNumberOfSkeletonRows` in the above method, it acts like the default behavior (i.e. it calculates how many cells needed to populate the whole tableview).\n\nThere is only one method you need to implement to let Skeleton know the cell identifier. This method doesn't have default implementation:\n ``` swift\n func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -\u003e ReusableCellIdentifier {\n    return \"CellIdentifier\"\n}\n ```\n \n By default, the library dequeues the cells from each indexPath, but you can also do this if you want to make some changes before the skeleton appears:\n ``` swift\n func collectionSkeletonView(_ skeletonView: UITableView, skeletonCellForRowAt indexPath: IndexPath) -\u003e UITableViewCell? {\n     let cell = skeletonView.dequeueReusableCell(withIdentifier: \"CellIdentifier\", for: indexPath) as? Cell\n     cell?.textField.isHidden = indexPath.row == 0\n     return cell\n }\n ```\n \nIf you prefer to leave the deque part to the library you can configure the cell using this method:\n ``` swift\n func collectionSkeletonView(_ skeletonView: UITableView, prepareCellForSkeleton cell: UITableViewCell, at indexPath: IndexPath) {\n     let cell = cell as? Cell\n     cell?.textField.isHidden = indexPath.row == 0\n }\n ```\n\n \nBesides, you can skeletonize both the headers and footers. You need to conform to `SkeletonTableViewDelegate` protocol.\n\n```swift\npublic protocol SkeletonTableViewDelegate: UITableViewDelegate {\n    func collectionSkeletonView(_ skeletonView: UITableView, identifierForHeaderInSection section: Int) -\u003e ReusableHeaderFooterIdentifier? // default: nil\n    func collectionSkeletonView(_ skeletonView: UITableView, identifierForFooterInSection section: Int) -\u003e ReusableHeaderFooterIdentifier? // default: nil\n}\n```\n\n\u003e 📣 **IMPORTANT!** \n\u003e \n\u003e 1️⃣ If you are using resizable cells (**`tableView.rowHeight = UITableViewAutomaticDimension`**), it's mandatory define the **`estimatedRowHeight`**.\n\u003e \n\u003e 2️⃣ When you add elements in a **`UITableViewCell`** you should add it to **`contentView`** and not to the cell directly.\n\u003e ```swift\n\u003e self.contentView.addSubview(titleLabel) ✅         \n\u003e self.addSubview(titleLabel) ❌\n\u003e ```\n\n  \n\n**UICollectionView**\n\nFor `UICollectionView`, you need to conform to `SkeletonCollectionViewDataSource` protocol.\n\n``` swift\npublic protocol SkeletonCollectionViewDataSource: UICollectionViewDataSource {\n    func numSections(in collectionSkeletonView: UICollectionView) -\u003e Int  // default: 1\n    func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -\u003e Int\n    func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -\u003e ReusableCellIdentifier\n    func collectionSkeletonView(_ skeletonView: UICollectionView, supplementaryViewIdentifierOfKind: String, at indexPath: IndexPath) -\u003e ReusableCellIdentifier? // default: nil\n    func collectionSkeletonView(_ skeletonView: UICollectionView, skeletonCellForItemAt indexPath: IndexPath) -\u003e UICollectionViewCell?  // default: nil\n    func collectionSkeletonView(_ skeletonView: UICollectionView, prepareCellForSkeleton cell: UICollectionViewCell, at indexPath: IndexPath)\n    func collectionSkeletonView(_ skeletonView: UICollectionView, prepareViewForSkeleton view: UICollectionReusableView, at indexPath: IndexPath)\n}\n```\n\nThe rest of the process is the same as ```UITableView```\n\n\n### 🔠 Texts\n\n![](Assets/multilines2.png)\n\nWhen using elements with text, ```SkeletonView``` draws lines to simulate text.\n\nYou can set some properties for multilines elements.\n\n| Property | Type | Default | Preview\n| ------- | ------- |------- | -------\n| **lastLineFillPercent**  | `CGFloat` | `70`| ![](Assets/multiline_lastline.png)\n| **linesCornerRadius**  | `Int` | `0` | ![](Assets/multiline_corner.png)\n| **skeletonLineSpacing**  | `CGFloat` | `10` | ![](Assets/multiline_lineSpacing.png)\n| **skeletonPaddingInsets**  | `UIEdgeInsets` | `.zero` | ![](Assets/multiline_insets.png)\n| **skeletonTextLineHeight**  | `SkeletonTextLineHeight` | `.fixed(15)` | ![](Assets/multiline_lineHeight.png)\n| **skeletonTextNumberOfLines**  | `SkeletonTextNumberOfLines` | `.inherited` | ![](Assets/multiline_corner.png)\n\n\u003cbr /\u003e\n\nTo modify the percent or radius **using code**, set the properties:\n```swift\ndescriptionTextView.lastLineFillPercent = 50\ndescriptionTextView.linesCornerRadius = 5\n```\n\nOr, if you prefer use **IB/Storyboard**:\n\n![](Assets/multiline_customize.png)\n\n\u003cbr /\u003e\n\n**How to define the number of lines?**\n\n\nBy default, the number of lines is the same as the value of the `numberOfLines` property. And, if it's set to **zero**, it'll calculate how many lines are needed to populate the whole skeleton and draw it.\n\nHowever, if you want to set a specific number of skeleton lines you can do it by setting the `skeletonTextNumberOfLines` property. This property has two possible values, `inherited` which returns `numberOfLines` value and `custom(Int)` which returns the specific number of lines specified as the associated value. \n\nFor example:\n\n```swift\nlabel.skeletonTextNumberOfLines = 3   // .custom(3)\n``` \n\n\u003cbr /\u003e\n\n\u003e **⚠️ DEPRECATED!**\n\u003e\n\u003e **useFontLineHeight** has been deprecated. You can use **skeletonTextLineHeight** instead:\n\u003e ```swift\n\u003e descriptionTextView.skeletonTextLineHeight = .relativeToFont\n\u003e ```\n\n\u003e **📣 IMPORTANT!**\n\u003e\n\u003e Please note that for views without multiple lines, the single line will be considered \n\u003e as the last line.\n\n\n\n### 🦋 Appearance\n\nThe skeletons have a default appearance. So, when you don't specify the color, gradient or multilines properties, `SkeletonView` uses the default values.\n\nDefault values:\n- **tintColor**: `UIColor`\n    - *default: `.skeletonDefault` (same as `.clouds` but adaptive to dark mode)*\n- **gradient**: SkeletonGradient\n  - *default: `SkeletonGradient(baseColor: .skeletonDefault)`*\n- **multilineHeight**: `CGFloat`\n  - *default: 15*\n- **multilineSpacing**: `CGFloat`\n  - *default: 10*\n- **multilineLastLineFillPercent**: `Int`\n  - *default: 70*\n- **multilineCornerRadius**: `Int`\n  - *default: 0*\n- **skeletonCornerRadius**: `CGFloat` (IBInspectable)  (Make your skeleton view with corner)\n  - *default: 0*\n\nTo get these default values you can use `SkeletonAppearance.default`. Using this property you can set the values as well:\n```swift\nSkeletonAppearance.default.multilineHeight = 20\nSkeletonAppearance.default.tintColor = .green\n```\n\n\u003e **⚠️ DEPRECATED!**\n\u003e\n\u003e **useFontLineHeight** has been deprecated. You can use **textLineHeight** instead:\n\u003e ```swift\n\u003e SkeletonAppearance.default.textLineHeight = .relativeToFont\n\u003e ```\n\n\n### 🎨 Custom colors\n\nYou can decide which color the skeleton is tinted with. You only need to pass as a parameter the color or gradient you want.\n\n**Using solid colors**\n```swift\nview.showSkeleton(usingColor: UIColor.gray) // Solid\n// or\nview.showSkeleton(usingColor: UIColor(red: 25.0, green: 30.0, blue: 255.0, alpha: 1.0))\n```\n**Using gradients**\n``` swift\nlet gradient = SkeletonGradient(baseColor: UIColor.midnightBlue)\nview.showGradientSkeleton(usingGradient: gradient) // Gradient\n```\n\nBesides, **SkeletonView** features 20 flat colors 🤙🏼\n\n```UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange  ...```\n\n![](Assets/flatcolors.png)\n###### Image captured from website [https://flatuicolors.com](https://flatuicolors.com)\n\n\n### 🏃‍♀️ Animations\n\n**SkeletonView** has two built-in animations, *pulse* for solid skeletons and *sliding* for gradients.\n\nBesides, if you want to do your own skeleton animation, it's really easy.\n\n\nSkeleton provides the `showAnimatedSkeleton` function which has a ```SkeletonLayerAnimation``` closure where you can define your custom animation.\n\n```swift\npublic typealias SkeletonLayerAnimation = (CALayer) -\u003e CAAnimation\n```\n\nYou can call the function like this:\n\n```swift\nview.showAnimatedSkeleton { (layer) -\u003e CAAnimation in\n  let animation = CAAnimation()\n  // Customize here your animation\n\n  return animation\n}\n```\n\nIt's available ```SkeletonAnimationBuilder```. It's a builder to make ```SkeletonLayerAnimation```.\n\nToday, you can create **sliding animations** for gradients, deciding the **direction** and setting the **duration** of the animation (default = 1.5s).\n\n```swift\n// func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5) -\u003e SkeletonLayerAnimation\n\nlet animation = SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: .leftToRight)\nview.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)\n\n```\n\n```GradientDirection``` is an enum, with theses cases:\n\n|  Direction | Preview\n|------- | -------\n| .leftRight | ![](Assets/sliding_left_to_right.gif)\n| .rightLeft | ![](Assets/sliding_right_to_left.gif)\n| .topBottom | ![](Assets/sliding_top_to_bottom.gif)\n| .bottomTop | ![](Assets/sliding_bottom_to_top.gif)\n| .topLeftBottomRight | ![](Assets/sliding_topLeft_to_bottomRight.gif)\n| .bottomRightTopLeft | ![](Assets/sliding_bottomRight_to_topLeft.gif)\n\n\u003e **😉 TRICK!**\n\u003e\n\u003e Exist another way to create sliding animations, just using this shortcut:\n\u003e ```swift\n\u003e let animation = GradientDirection.leftToRight.slidingAnimation()\n\u003e ```\n\n  \n\n### 🏄 Transitions\n\n**SkeletonView** has built-in transitions to **show** or **hide** the skeletons in a *smoother* way 🤙\n\nTo use the transition, simply add the ```transition``` parameter to your ```showSkeleton()``` or ```hideSkeleton()``` function with the transition time, like this:\n\n```swift\nview.showSkeleton(transition: .crossDissolve(0.25))     //Show skeleton cross dissolve transition with 0.25 seconds fade time\nview.hideSkeleton(transition: .crossDissolve(0.25))     //Hide skeleton cross dissolve transition with 0.25 seconds fade time\n\n```\n\nThe default value is  `crossDissolve(0.25)`\n\n**Preview**\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd width=\"50%\"\u003e\n\u003ccenter\u003eNone\u003c/center\u003e\n\u003c/td\u003e\n\u003ctd width=\"50%\"\u003e\n\u003ccenter\u003eCross dissolve\u003c/center\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cimg src=\"Assets/skeleton_transition_nofade.gif\"\u003e\u003c/img\u003e\n\u003c/td\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cimg src=\"Assets/skeleton_transition_fade.gif\"\u003e\u003c/img\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n\n## ✨ Miscellaneous \n\n  \n\n**Hierarchy**\n\nSince ```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.\n\nBecause an image is worth a thousand words:\n\nIn this example we have a `UIViewController` with a `ContainerView` and a `UITableView`. When the view is ready, we show the skeleton using this method:\n```\nview.showSkeleton()\n```\n\n\u003e ```isSkeletonable```= ☠️\n\n| Configuration | Result|\n|:-------:|:-------:|\n|\u003cimg src=\"Assets/no_skeletonable.jpg\" width=\"350\"/\u003e | \u003cimg src=\"Assets/no_skeletonables_result.png\" width=\"350\"/\u003e|\n|\u003cimg src=\"Assets/container_no_skeletonable.jpg\" width=\"350\"/\u003e | \u003cimg src=\"Assets/no_skeletonables_result.png\" width=\"350\"/\u003e|\n|\u003cimg src=\"Assets/container_skeletonable.jpg\" width=\"350\"/\u003e | \u003cimg src=\"Assets/container_skeletonable_result.png\" width=\"350\"/\u003e|\n|\u003cimg src=\"Assets/all_skeletonables.jpg\" width=\"350\"/\u003e| \u003cimg src=\"Assets/all_skeletonables_result.png\" width=\"350\"/\u003e|\n|\u003cimg src=\"Assets/tableview_no_skeletonable.jpg\" width=\"350\"/\u003e | \u003cimg src=\"Assets/tableview_no_skeletonable_result.png\" height=\"350\"/\u003e|\n|\u003cimg src=\"Assets/tableview_skeletonable.jpg\" width=\"350\"/\u003e | \u003cimg src=\"Assets/tableview_skeletonable_result.png\" height=\"350\"/\u003e|\n\n  \n\n**Skeleton views layout**\n\nSometimes skeleton layout may not fit your layout because the parent view bounds have changed. ~For example, rotating the device.~\n\nYou can relayout the skeleton views like so:\n\n```swift\noverride func viewDidLayoutSubviews() {\n    view.layoutSkeletonIfNeeded()\n}\n```\n\n\u003e 📣 **IMPORTANT!** \n\u003e \n\u003e 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.\n\n\n  \n\n**Update skeleton**\n\nYou can change the skeleton configuration at any time like its colour, animation, etc. with the following methods:\n\n```swift\n(1) view.updateSkeleton()                 // Solid\n(2) view.updateGradientSkeleton()         // Gradient\n(3) view.updateAnimatedSkeleton()         // Solid animated\n(4) view.updateAnimatedGradientSkeleton() // Gradient animated\n```\n\n**Hiding views when the animation starts**\n\nSometimes you wanna hide some view when the animation starts, so there is a quick property that you can use to make this happen:\n\n```swift\nview.isHiddenWhenSkeletonIsActive = true  // This works only when isSkeletonable = true\n```\n\n**Don't modify user interaction when the skeleton is active**\n\n\nBy default, the user interaction is disabled for skeletonized items, but if you don't want to modify the user interaction indicator when skeleton is active, you can use the `isUserInteractionDisabledWhenSkeletonIsActive` property:\n\n```swift\nview.isUserInteractionDisabledWhenSkeletonIsActive = false  // The view will be active when the skeleton will be active.\n```\n\n**Don't use the font line height for the skeleton lines in labels**\n\nFalse to disable skeleton to auto-adjust to font height for a `UILabel` or `UITextView`. By default, the skeleton lines height is auto-adjusted to font height to more accurately reflect the text in the label rect rather than using the bounding box.\n\n```swift\nlabel.useFontLineHeight = false\n```\n\n**Delayed show skeleton**\n\nYou can delay the presentation of the skeleton if the views update quickly.\n\n```swift\nfunc showSkeleton(usingColor: UIColor,\n                  animated: Bool,\n                  delay: TimeInterval,\n                  transition: SkeletonTransitionStyle)\n```\n\n```swift\nfunc showGradientSkeleton(usingGradient: SkeletonGradient,\n                          animated: Bool,\n                          delay: TimeInterval,\n                          transition: SkeletonTransitionStyle)\n```\n\n**Debug**\n\nTo facilitate the debug tasks when something is not working fine. **`SkeletonView`** has some new tools.\n\nFirst, `UIView` has available a property with his skeleton info:\n```swift\nvar sk.skeletonTreeDescription: String\n\n```\n\nBesides, you can activate the new **debug mode**. You just add the environment variable `SKELETON_DEBUG` and activate it.\n\n![](Assets/debug_mode.png)\n\nThen, when the skeleton appears, you can see the view hierarchy in the Xcode console.\n\n```\n{ \n  \"type\" : \"UIView\", // UITableView, UILabel...\n  \"isSkeletonable\" : true,\n  \"reference\" : \"0x000000014751ce30\",\n  \"children\" : [\n    {\n      \"type\" : \"UIView\",\n      \"isSkeletonable\" : true,\n      \"children\" : [ ... ],\n      \"reference\" : \"0x000000014751cfa0\"\n    }\n  ]\n}\n```\n  \n**Supported OS \u0026 SDK Versions**\n\n* iOS 9.0+\n* tvOS 9.0+\n* Swift 5.3\n\n## ❤️ Contributing\nThis is an open source project, so feel free to contribute. How?\n\n- Open an [issue](https://github.com/Juanpe/SkeletonView/issues/new).\n- Send feedback via [email](mailto://juanpecatalan.com).\n- Propose your own fixes, suggestions and open a pull request with the changes.\n\nSee [all contributors](https://github.com/Juanpe/SkeletonView/graphs/contributors)\n\nFor more information, please read the [contributing guidelines](https://github.com/Juanpe/SkeletonView/blob/main/CONTRIBUTING.md).\n\n\n## 📢 Mentions\n\n- [iOS Dev Weekly #327](https://iosdevweekly.com/issues/327#start)\n- [Hacking with Swift Articles](https://www.hackingwithswift.com/articles/40/skeletonview-makes-loading-content-beautiful)\n- [Top 10 Swift Articles November](https://medium.mybridge.co/swift-top-10-articles-for-the-past-month-v-nov-2017-dfed7861cd65)\n- [30 Amazing iOS Swift Libraries (v2018)](https://medium.mybridge.co/30-amazing-ios-swift-libraries-for-the-past-year-v-2018-7cf15027eee9)\n- [AppCoda Weekly #44](http://digest.appcoda.com/issues/appcoda-weekly-issue-44-81899)\n- [iOS Cookies Newsletter #103](https://us11.campaign-archive.com/?u=cd1f3ed33c6527331d82107ba\u0026id=48131a516d)\n- [Swift Developments Newsletter #113](https://andybargh.com/swiftdevelopments-113/)\n- [iOS Goodies #204](http://ios-goodies.com/post/167557280951/week-204)\n- [Swift Weekly #96](http://digest.swiftweekly.com/issues/swift-weekly-issue-96-81759)\n- [CocoaControls](https://www.cocoacontrols.com/controls/skeletonview)\n- [Awesome iOS Newsletter #74](https://ios.libhunt.com/newsletter/74)\n- [Swift News #36](https://www.youtube.com/watch?v=mAGpsQiy6so)\n- [Best iOS articles, new tools \u0026 more](https://medium.com/flawless-app-stories/best-ios-articles-new-tools-more-fcbe673e10d)\n\n## 🏆 Sponsors\n\nOpen-source projects cannot live long without your help. If you find **SkeletonView** is useful, please consider supporting this \nproject by becoming a sponsor. \n\nBecome a sponsor through [GitHub Sponsors](https://github.com/sponsors/Juanpe) :heart:\n\n## 👨🏻‍💻 Author\n\n[Juanpe Catalán](http://www.twitter.com/JuanpeCatalan)\n\n\u003ca class=\"bmc-button\" target=\"_blank\" href=\"https://www.buymeacoffee.com/CDou4xtIK\"\u003e\u003cimg 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;\"\u003e\u003cspan style=\"margin-left:5px\"\u003e\u003c/span\u003e\u003c/a\u003e\n\n\n## 👮🏻 License\n\n```\nMIT License\n\nCopyright (c) 2017 Juanpe Catalán\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","funding_links":["https://github.com/sponsors/juanpe","https://github.com/sponsors/Juanpe","https://www.buymeacoffee.com/CDou4xtIK"],"categories":["UI","Libs","Swift","Uncategorized","UI Components","HarmonyOS","\u003ca name=\"for-projects\"\u003e\u003c/a\u003e For Projects","UI [🔝](#readme)","前端开发框架及项目","Content","Minor","UI/UX"],"sub_categories":["Activity Indicator","UI","Uncategorized","Other free courses","Windows Manager","\u003ca name=\"for-projects-example-projects\"\u003e\u003c/a\u003e Example Projects","其他_文本生成、文本对话","Skeleton","Placeholder"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJuanpe%2FSkeletonView","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FJuanpe%2FSkeletonView","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJuanpe%2FSkeletonView/lists"}