Git Product home page Git Product logo

skeletonui's Introduction

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,
                          animation: .pulse(),
                          appearance: .solid(color: .red, background: .blue),
                          shape: .rectangle,
                          lines: 3,
                          scales: [1: 0.5])
        }
        .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.

skeletonui's People

Contributors

alexandrethsilva avatar csolanam avatar rivera-ernesto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

skeletonui's Issues

iOS 15 Adaption

SkeletonUI is not available on iOS 15. Any updates on that?

Slope angle from horizontal axis in linear gradient

Is your feature request related to a problem? Please describe.
Linear gradient could be created with an angle representing inclination from horizontal axis.

Describe the solution you'd like
On SkeletonShape, where the linear gradient is created it could have an additional angle parameter in the appearance type case, so it should be able to calculate the starting and end position taking into account some elevation on the Y-axis.

Animation when skeleton disappears and shows the actual content

Is your feature request related to a problem? Please describe.
It would be nice to have a transition when skeleton finishes and shows the real content.

Describe the solution you'd like
A fade-out opacity animation when the skeleton finishes loading and a fade-in opacity animation on the real content running in parallel.

Describe alternatives you've considered
Supporting other kind of transitions.

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.

macOS CI tests aren't passing because of scale factor

Is your feature request related to a problem? Please describe.
macOS tests are commented because they aren'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.

Describe the solution you'd like
macOS tests should be enabled and passing CI snapshot tests.

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

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

.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
    }
}

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.

Privacy Manifest

Subject: We need to incorporate the xcprivacy manifest into our app . Starting March 13, Apple will send notifications when uploading builds to the App Store, and this will become mandatory from May 1. All the SDKs used in our app needs to incorporate the xcprivacy manifest.
Reference: https://developer.apple.com/news/?id=3d8a9yyh

Actions needed: We need the compatible xcprivacy manifest version IOS SDK with xcprivacy manifest. We are expecting a seamless upgrade by upgrading to the latest version.

View with Navigation Bar side effect

When I put the skeleton in the view with the navigation bar, the view starts to change the frame, but when I change the transition to .scale, everything works.

struct ContentView: View {
    var body: some View {
        NavigationView(content: {
            Text("Hello, World!")
                .skeleton(with: true)
                .navigationTitle("temp")
                .navigationBarTitleDisplayMode(.inline)
        })
    }
}

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

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

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.