☠️SkeletonUI aims to bring an elegant, declarative syntax to skeleton loading animations.

Overview

SkeletonUI aims to bring an elegant, declarative syntax to skeleton loading animations. Get rid of loading screens or spinners and start using skeletons to represent final content shapes.

Requirements ⚙️

  • macOS 10.15.
  • Xcode 11.0.
  • Swift 5.0.

Supported Platforms 📱

  • iOS 13.0.
  • tvOS 13.0.
  • watchOS 6.0.
  • macOS 10.15.

Installation 💻

Swift Package Manager

Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler. Once you have your Swift package set up, adding SkeletonUI as a dependency is as easy as adding it to the dependencies value of your Package.swift.

  dependencies: [
  .package(url: "https://github.com/CSolanaM/SkeletonUI.git", .branch("master"))
  ]

CocoaPods

CocoaPods is a centralized dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate SkeletonUI into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'SkeletonUI'

Features

  • SwiftUI simple, declarative syntax.
  • Super easy and simple to set up.
  • All Views are skeletonables.
  • Fully customizable.
  • Universal (iPhone, iPad, iPod, Apple TV, Apple Watch, Mac).
  • SwiftUI ViewModifier power.
  • Lightweight codebase.

Usage 🚀

Basic one-liner:

import SkeletonUI
import SwiftUI

struct UsersView: View {
    @State var users = [String]()

    var body: some View {
        Text("Finished requesting \(users.count) users!")
            .skeleton(with: users.isEmpty)
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                    self.users = ["John Doe", "Jane Doe", "James Doe", "Judy Doe"]
                }
        }
    }
}

Advanced customization:

import SkeletonUI
import SwiftUI

struct User: Identifiable {
    let id = UUID()
    let name: String
}

struct UsersView: View {
    @State var users = [User]()

    var body: some View {
        SkeletonList(with: users, quantity: 6) { loading, user in
            Text(user?.name)
                .skeleton(with: loading)
                .shape(type: .rectangle)
                .appearance(type: .solid(color: .red, background: .blue))
                .multiline(lines: 3, scales: [1: 0.5])
                .animation(type: .pulse())
        }
        .onAppear {
            DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                self.users = [User(name: "John Doe"),
                              User(name: "Jane Doe"),
                              User(name: "James Doe"),
                              User(name: "Judy Doe")]
            }
        }
    }
}

Change Log 📆

See CHANGELOG.md for details.

Contributing 🎉

  • Suggest your idea as a feature request for this project.
  • Create a bug report to help us improve.
  • Propose your own fixes, suggestions and open a pull request with the changes.

See CONTRIBUTING.md for details.

Code of Conduct 💬

See CODE_OF_CONDUCT.md for details.

Credits 🙊

SkeletonUI is owned and maintained by CSolanaM. You can follow me on Twitter at @CSolanaM or contact me via email for project updates and releases.

License 🎓

SkeletonUI is released under the MIT license. See LICENSE for details.

Comments
  • Skeleton fills full height

    Skeleton fills full height

    Describe the bug Skeleton element uses full available height even in basic example. Occures on both, device and XCode preview.

    To Reproduce Screenshot 2020-11-14 at 18 54 11

    Expected behavior Skeleton uses height of one line of text

    Screenshots Uploaded in reproduction section

    Desktop (please complete the following information):

    • OS: macOS
    • Version: 11.0.1 (20B29)

    Smartphone (please complete the following information):

    • Device: iPhone 8 Plus & XCode Preview
    • OS: iOS 14.2 (18B92) Additional context
    enhancement 
    opened by maxtomczyk 6
  • Support iOS15

    Support iOS15

    Issue Link :link:

    The extension for TextField is causing an infinity loop in iOS15

    Goals :soccer:

    Make it work for iOS 15

    Implementation Details :construction:

    • Removing the extension and updating the tests
    enhancement 
    opened by batschz 3
  • Fix color extension

    Fix color extension

    Issue Link :link:

    #18 .primary color extension

    Goals :soccer:

    As the related issue mentions, the current implementation clashes with the built-in Color, so the goal of this PR is to address that.

    Implementation Details :construction:

    For what I can tell, the current usage is simple enough to warrant a simple struct instead of an extension, as one should be wary of extending core functionality inside a library.

    Testing Details :mag:

    No tests were added or removed in this PR.

    opened by alexandrethsilva 3
  • Skeleton animation of some parent view is stoped if body of parent view is refreshed.

    Skeleton animation of some parent view is stoped if body of parent view is refreshed.

    Describe the bug Hi @CSolanaM . First of all, I would like to say thanks for your framework but, unfortunately, I've found one issue that blocks me from submitting my app to App Store. I would like to describe it. I have a screen with two main elements: some card that may be flipped by the user and a list of data for which I use SkeletonList. Both views inside the body of ContentView. Not more. SkeletonList is animated when the screen is appeared to start loading content, but when the user flipped a card SkeletonList stops its animation. The same issue for SkeletonForEach.

    To Reproduce I put here the small piece of code that simulates my screen:

    import SwiftUI
    import SkeletonUI
    
    struct CardContentView<Content>: View where Content: View {
        var content: () -> Content
        var body: some View {
            content()
        }
    }
    
    struct TopCardFronView: View {
        @Binding var anotherLoading: Bool
        var body: some View {
            VStack {
                Text("Tap me")
                    .foregroundColor(.white)
                    .font(.largeTitle)
                    .onTapGesture {
                        anotherLoading.toggle()
                    }
            }
            .frame(width: 150, height: 150)
            .background(Color.black)
        }
    }
    
    struct TopCardBackView: View {
        var body: some View {
            VStack {
                Text("Another text")
                    .foregroundColor(.white)
                    .font(.largeTitle)
            }
            .frame(width: 150, height: 150)
            .background(Color.black)
        }
    }
    
    struct User: Identifiable {
        let id = UUID()
        let name: String
    }
    
    struct ContentView: View {
        @State private var rotationAngle: Double = 0
        @State private var flipped = false
        @State private var anotherLoading = false
        @State var users = [User]()
        var body: some View {
            VStack {
                CardContentView {
                    VStack {
                        Group {
                            if flipped {
                                TopCardBackView()
                                    .rotation3DEffect(.degrees(rotationAngle),
                                                          axis: (x: 0.0, y: 1.0, z: 0.0))
                            } else {
                                TopCardFronView(anotherLoading: $anotherLoading)
                            }
                        }
                    }
                }
                .rotation3DEffect(.degrees(rotationAngle),
                                      axis: (x: 0.0, y: 1.0, z: 0.0))
                .onChange(of: anotherLoading, perform: { value in
                    withAnimation {
                        flipped.toggle()
                        rotationAngle += 180
                    }
                })
                SkeletonList(with: users, quantity: 6) { loading, user in
                            Text(user?.name)
                                .skeleton(with: loading)
                                .shape(type: .rectangle)
                                .appearance(type: .solid(color: .red, background: .blue))
                                .multiline(lines: 3, scales: [1: 0.5])
                                .animation(type: .pulse())
                        }
                        .onAppear {
                            DispatchQueue.main.asyncAfter(deadline: .now() + 20) {
                                self.users = [User(name: "John Doe"),
                                              User(name: "Jane Doe"),
                                              User(name: "James Doe"),
                                              User(name: "Judy Doe")]
                            }
                        }
            }
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    

    Expected behavior SkeletonList should continue to animate.

    Screenshots Screen Recording 2021-02-26 at 20 38 12 2021-02-26 20_44_38

    Desktop (please complete the following information):

    • MacOS Catalina
    • Version 10.15.7

    Smartphone (please complete the following information):

    • Device: iPhone SE 1st GEN & XCode Preview
    • iOS 14.4

    Additional context Add any other context about the problem here.

    bug 
    opened by SavinovJr 2
  • Unable to install pod

    Unable to install pod

    Thank you for starting this project! I'm excited to check it out!

    Describe the bug While trying to do a new install of SkeletonUI, the pod install fails with the following error:

    [!] Error installing SkeletonUI
    [!] /usr/bin/git clone https://github.com/CSolanaM/SkeletonUI.git /var/folders/st/3lb8mpm938xfqktsrb3b62g80000gn/T/d20191029-96400-wf7mcw --template= --single-branch --depth 1 --branch 0.1.1
    
    Cloning into '/var/folders/st/3lb8mpm938xfqktsrb3b62g80000gn/T/d20191029-96400-wf7mcw'...
    warning: Could not find remote branch 0.1.1 to clone.
    fatal: Remote branch 0.1.1 not found in upstream origin
    

    To Reproduce Steps to reproduce the behavior:

    1. Start with a fresh project that does not have SkeletonUI installed
    2. Add SkeletonUI to the podfile
    3. Attempt to install the pods with pod install
    4. See error

    Expected behavior SkeletonUI is installed.

    Screenshots It's just the text above.

    Desktop (please complete the following information):

    • n/a

    Smartphone (please complete the following information):

    • n/a

    Additional context none

    bug good first issue 
    opened by JulianRamirez 2
  • Animation Is not trigger

    Animation Is not trigger

    Hi There,

    I'm trying to use the example to animate my skeleton. However, it's not getting animated.

    To Reproduce Steps to reproduce the behavior:

    1. Use the following Code:
    Text("Finished requesting users!")
                        .skeleton(with: true)
                        .appearance(type: .solid(color: .red, background: .blue))
                        .animation(type: .pulse())
                        .background(Color.black)
    

    Expected behavior It should be animated

    Screenshots Captura de Pantalla 2022-08-08 a la(s) 19 01 12

    What could be happening?

    Best Regards

    opened by aluco100 1
  • Animation failed when pushing the new page via NavigationLink

    Animation failed when pushing the new page via NavigationLink

    If just normally presenting the view it works find, but if push the view using NavigationLink the animation effect would not working and only display a plain censored gray bar.

    • iOS simulator: 15.2

    Screenshots IMG_0285

    opened by hsing0527 1
  • skeletton foreach

    skeletton foreach

    Describe the bug bug when use scrollview with skeletonForeach.

    To Reproduce Steps to reproduce the behavior:

    1. in example project
    2. change skeletonList to skeletonForeach
    3. embed in scroolView
    4. See error

    Expected behavior working as skeletonList

    opened by tannhuot 1
  • navigationBarHidden triggers unwanted up and down bounce.

    navigationBarHidden triggers unwanted up and down bounce.

    Describe the bug I'm using SkeletonUI in my app and in one of the views I was having a bug that apparently was related to displaying the SkeletonUI View. The problem, after hours of debugging, was apparently caused by .navigationBarHidden(true) that was applied to a ZStack witch contained the Text View displaying the skeleton to prevent a UIHostingController from displaying the nav bar.

    To Reproduce This is the main view.

        var body: some View {
            ZStack(alignment: .center) {
                Text("")
                    .skeleton(with: true)
                    .shape(type: .rectangle)
                    .multiline(lines: 2, scales: [0: 0.8, 1: 0.6], spacing: 2.0)
                    .appearance(type: .gradient(GradientType.linear, color: Color(UIColor(hex: 0xbdcbdb)), background: .white, radius: 0.7, angle: 0.0))
                    .animation(type: .linear(delay: 0.0))
                    .padding(.bottom, 20.0)
            }
            // Removing the next 2 lines will remove the bug.
            .navigationBarTitle("")
            .navigationBarHidden(true)
        }
    

    Note: To reproduce this code you need to put this view in a UIHostingController.

    Expected behavior A normal 2 lines gradient animation that does not move.

    Screenshots Note: Updated Video. Screenshots

    Additional context The Swift UI view is presented in a UIHostingController.

    opened by JCTec 1
  • .primary color extension

    .primary color extension

    In the AppearenceInteractor file you declare an extension to the Color type. However this creates an error when I import this library in a file and in the same file use the stock Color.primary by Apple as there are two Color.primary and it is ambiguous. Please rename it.

    public static var primary: Color {
            #if os(iOS)
                return Color(.systemGray4)
            #elseif os(tvOS)
                return Color(.tertiaryLabel)
            #elseif os(watchOS)
                return Color.secondary
            #elseif os(macOS)
                return Color(.alternateSelectedControlColor)
            #endif
        }
    }
    
    bug 
    opened by marchettoartur 1
  • Error when running the example

    Error when running the example

    I got this error when running your example

    SkeletonUI-macOS-iOS[1728:47422] Task <5ED5FF93-B549-451D-88B1-A54648BCBDA0>.<1> finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey=https://rickandmortyapi.com/api/character/, NSLocalizedDescription=cancelled, NSErrorFailingURLKey=https://rickandmortyapi.com/api/character/}

    Can you give it a look? Thanks

    bug 
    opened by nhathongly 1
  • Add checks for code so it can be used in projects with a minimum target < iOS 13

    Add checks for code so it can be used in projects with a minimum target < iOS 13

    Issue Link :link:

    Projects with a minimum target < iOS 13 receive errors when importing this library

    Goals :soccer:

    • Enable SkeletonUI to be imported and used by projects with a minimum target that is < iOS 13

    Implementation Details :construction:

    • Add available checks • Add #if arch(x86_64) || arch(arm64) checks

    opened by AlexanderMarchant 0
  • Two SkeletonForEach in a LazyVGrid causes duplicate IDs

    Two SkeletonForEach in a LazyVGrid causes duplicate IDs

    Describe the bug Using SkeletonForEach twice in a LazyVGrid causes the IDs to be duplicated which leads to several bugs.

    To Reproduce

    LazyVGrid(columns: gridLayout, spacing: 20) {
        SkeletonForEach(with: ..., quantity: 2) { (loading, item) in
            Text(item).skeleton(with: loading)
        }
        SkeletonForEach(with: ..., quantity: 2) { (loading, item) in
            Text(item).skeleton(with: loading)
        }
    }
    

    Expected behavior To be able to use two SkeletonForEach's.

    Additional context

    • iOS: 15
    • Swift: 5.3
    • Branch: develop
    opened by nouun 0
  • Add padding to multiline modifier

    Add padding to multiline modifier

    Goals :soccer:

    SkeletonUI uses GeometryReader to read the views size. GeometryReader is greedy and tacks all the size it gets. If I have a typical Layout like: HStack { Text("a") VStack { Text("a") Text("a") }.skeleton(true).multiline(...) }

    This causes VStack to take the complete height of the container. Also the multiline is "blown" up. You can work around by applying extra constraints when the skeleton is there, but that increases the complexity of the layout a lout.

    A simple solution is to add a padding option to the multiline modifier, this enables more flexibility when adding the skeleton.

    Testing Details :mag:

    Added a new snapshot testtestCustomTextWithPadding

    enhancement 
    opened by bluesource 0
Releases(1.0.9)
  • 1.0.9(Aug 14, 2022)

  • 1.0.8(Jul 11, 2022)

  • 1.0.7(Nov 14, 2021)

  • 1.0.6(Sep 20, 2021)

  • 1.0.5(Sep 20, 2021)

    Added

    Changed

    Removed

    Fixed

    • Improved the way GeometryReader is used to fix its behaviour in the newest and previous SwiftUI versions.
    • Improved the performance in 'AnimationInteractor'.
    • Fixes a small bug that didn't let remove any animation.
    Source code(tar.gz)
    Source code(zip)
  • 1.0.4(Sep 20, 2021)

  • 1.0.2(Sep 20, 2021)

    Added

    • Slope angle.

    Changed

    Removed

    • Commented macOS tests because weren't passing on the CI, its screen scale factor is 1 and should be 2 to match locally generated reference images. It will be fixed later.
    • Commented default Skeleton list test because wasn't on the CI. It will be fixed later.

    Fixed

    Source code(tar.gz)
    Source code(zip)
  • 1.0.3(Sep 20, 2021)

  • 1.0.1(Sep 20, 2021)

  • 1.0.0(Sep 20, 2021)

Owner
Carlos Solana Martínez
Hi! 👋🏻 I'm Carlos, a Senior iOS Software Engineer 💻 and lover 💖, also interested in AWS, Android, Node.js and everything related to native 📱 tech stack 🚀
Carlos Solana Martínez
A Swift library to take the power of UIView.animateWithDuration(_:, animations:...) to a whole new level - layers, springs, chain-able animations and mixing view and layer animations together!

ver 2.0 NB! Breaking changes in 2.0 - due to a lot of requests EasyAnimation does NOT automatically install itself when imported. You need to enable i

Marin Todorov 3k Dec 27, 2022
Bring life to CALayers with SpriteKit-like animation builders

Animo Bring life to CALayers with SpriteKit-like animation builders. Why use Animo? Because declaring CAAnimations (especially with CAAnimationGroups)

エウレカ 279 Dec 9, 2022
Fluid - Use a declarative syntax to build your user interface using UIKit like SwiftUI

Fluid Fluid is powered by ResultBuilder and a custom layout engine. You can uses

HZ.Liu 13 Dec 9, 2022
Advanced Natural Motion Animations, Simple Blocks Based Syntax

FlightAnimator Moved to Swift 3.1 Support: For Swift 3.1 - Use tag Version 0.9.9 See Installation Instructions for clarification Introduction FlightAn

Anton 589 Dec 29, 2022
Declarative chainable animations in Swift

Wave Declarative chainable animations in Swift ❤️ Support my apps ❤️ Push Hero - pure Swift native macOS application to test push notifications PasteP

Khoa 125 Oct 10, 2022
Compose SpriteKit animations quickly in a declarative SwiftUI-style

ActionBuilder Caveat developer: As this package is pre-release, the API may change significantly without notice. It has not been tested, so use it at

Kuba Szulaczkowski 6 Dec 30, 2022
A collection of animations for iOS. Simple, just add water animations.

DCAnimationKit A collection of animations for iOS Simply, just add water! DCAnimationKit is a category on UIView to make animations easy to perform. E

Dalton 797 Sep 23, 2022
(Animate CSS) animations for iOS. An easy to use library of iOS animations. As easy to use as an easy thing.

wobbly See Wobbly in action (examples) Add a drop of honey ?? to your project wobbly has a bunch of cool, fun, and easy to use iOS animations for you

Sagaya Abdulhafeez 150 Dec 23, 2021
(Animate CSS) animations for iOS. An easy to use library of iOS animations. As easy to use as an easy thing.

wobbly See Wobbly in action (examples) Add a drop of honey ?? to your project wobbly has a bunch of cool, fun, and easy to use iOS animations for you

Sagaya Abdulhafeez 150 Dec 23, 2021
An easy way to add a shimmering effect to any view with just one line of code. It is useful as an unobtrusive loading indicator.

LoadingShimmer An easy way to add a shimmering effect to any view with just single line of code. It is useful as an unobtrusive loading indicator. Thi

Jogendra 1.4k Jan 6, 2023
Lightweight Swift loading activity for iOS7+

EZLoadingActivity Lightweight Swift loading activity for iOS7+. Really simple to use, just add the class and write 1 line of code. Easy to use: EZLoad

Goktug Yilmaz 611 Dec 22, 2022
BWMCoverView is a very easy to use advertising the carousel view, supports circular scrolling functions such as switching, asynchronous loading of images, animation, custom is very high.

BWMCoverView BWMCoverView is a very easy to use advertising the carousel view, supports circular scrolling functions such as switching, asynchronous l

Bi Weiming 31 Mar 10, 2021
A lightweight loading animation that can be applied to any SwiftUI view with 1 line of code.

SimpleAFLoader A lightweight loading animation that can be applied to any SwiftUI view with 1 line of code. All animations are built using the SwiftUI

Fahim Rahman 2 Aug 25, 2022
Elegant SVG animation kit for swift

Elephant This is SVG animation presentation kit for iOS. Example You can run example app. Please open Example-iOS/Elephant-iOS.xcworkspace! Usage You

Kazumasa Shimomura 127 Dec 14, 2022
☠️ An elegant way to show users that something is happening and also prepare them to which contents they are awaiting

Features • Guides • Installation • Usage • Miscellaneous • Contributing ?? README is available in other languages: ???? . ???? . ???? . ???? . ???? To

Juanpe Catalán 11.7k Jan 3, 2023
A radical & elegant animation library for iOS.

Installation • Usage • Debugging • Animatable Properties • License Dance is a powerful and straightforward animation framework built upon the new UIVi

Saoud Rizwan 648 Dec 14, 2022
A powerful, elegant, and modular animation library for Swift.

MotionMachine provides a modular, powerful, and generic platform for manipulating values, whether that be animating UI elements or interpolating prope

Brett Walker 387 Dec 9, 2022
An elegant and flexible tweening library for iOS and tvOS.

PMTween is an elegant and flexible tweening library for Objective-C, currently supporting the iOS and tvOS platforms. It offers sensible default funct

Brett Walker 349 Nov 25, 2022
Physics-based animations for iOS, tvOS, and macOS.

Advance An animation library for iOS, tvOS, and macOS that uses physics-based animations (including springs) to power interactions that move and respo

Tim Donnelly 4.5k Dec 29, 2022