Compare commits

..

18 Commits

Author SHA1 Message Date
Juanpe Catalán 8f891f02b0 feat: upgrade framework version 2017-11-18 19:26:03 +01:00
Juanpe Catalán 9ef6d3e48d feat: change signature makeSlidingAnimation method 2017-11-18 19:23:17 +01:00
Juanpe Catalán 1862179c44 feat: updated README file to include SkeletonAnimationBuilder 2017-11-18 19:17:57 +01:00
Juanpe Catalán fc66cc5c0b feat: added SkeletonAnimationBuilder to create layer animations 2017-11-18 18:36:07 +01:00
Juanpe Catalán ef48129ef0 feat: updated README file 2017-11-17 19:47:50 +01:00
Juanpe Catalán e24969220f feat: added table of contents 2017-11-17 19:27:53 +01:00
Juanpe Catalán e123bed684 feat: added share link in README file 2017-11-16 21:44:15 +01:00
Juanpe Catalán dbb570dab7 feat: rename GradientVector to GradientPoint 2017-11-16 21:41:22 +01:00
Juanpe Catalán cdbb4dc6a0 feat: added GradientDirection 2017-11-16 18:53:25 +01:00
Juanpe b6c1c89645 feat: added travis shield on README file 2017-11-15 12:56:41 +01:00
Juanpe f583fe3316 feat: added travis file to CI 2017-11-15 12:39:39 +01:00
Juanpe befa9b0442 feat: update twitter account 2017-11-15 12:21:56 +01:00
Juanpe Catalán 07075f02d1 Update issue_template.md 2017-11-13 15:56:40 +01:00
Juanpe Catalán b8f52e7ce5 Create issue_template.md 2017-11-13 15:54:32 +01:00
Juanpe Catalán 9e3396d934 feat: updated README file 2017-11-10 15:50:31 +01:00
Juanpe Catalán 5a68d03af4 feat: Updated podspec file 2017-11-10 15:49:42 +01:00
Juanpe Catalán 91b4ac2bf6 Merge pull request #2 from LeonardoCardoso/master
feat: Change some private keywords, to be Swift 3 compatible
2017-11-10 15:43:15 +01:00
Leonardo f6d28d9492 fix: accessibility level 2017-11-09 13:26:26 +01:00
16 changed files with 196 additions and 27 deletions
+23
View File
@@ -0,0 +1,23 @@
⚠️ Please fill out this template when filing an issue.
### 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:**
Executable
+6
View File
@@ -0,0 +1,6 @@
language: objective-c
osx_image: xcode9
script:
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonView-iOS -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=11'
- xcodebuild -project SkeletonView.xcodeproj -target SkeletonViewExample -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=11'
after_success:
Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.1</string>
<string>1.0.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.1</string>
<string>1.0.3</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
+70 -19
View File
@@ -1,6 +1,9 @@
![](Assets/header.jpg)
<p align="center">
<a href="https://travis-ci.org/Juanpe/SkeletonView">
<img src="https://img.shields.io/travis/Juanpe/SkeletonView.svg">
</a>
<img src="https://img.shields.io/badge/Swift-4.0-orange.svg" />
<a href="https://cocoapods.org/pods/SkeletonView">
<img src="https://img.shields.io/cocoapods/v/SkeletonView.svg" alt="CocoaPods" />
@@ -8,14 +11,39 @@
<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://twitter.com/juanpe_catalan">
<img src="https://img.shields.io/badge/contact-@juanpe_catalan-blue.svg?style=flat" alt="Twitter: @juanpe_catalan" />
<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://opensource.org/licenses/MIT">
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License" />
</a>
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License" />
</a>
<a href="https://twitter.com/intent/tweet?text=Wow%20This%20library%20is%20awesome:&url=https%3A%2F%2Fgithub.com%2FJuanpe%2FSkeletonView">
<img src="https://img.shields.io/twitter/url/https/github.com/Juanpe/SkeletonView.svg?style=social" alt="License" />
</a>
</p>
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.
```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.
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)
* [Custom animations](#-custom-animations)
* [Hierarchy](#-hierarchy)
* [Documentation](#-documentation)
* [Contributed](#-contributed)
* [Author](#-author)
* [License](#-license)
## 🌟 Features
@@ -31,17 +59,7 @@
### 📋 Supported OS & SDK Versions
* iOS 9.0+
* Swift 4
### 🎤 Introduction
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.
```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.
Enjoy it! 🙂
###### Project generated with [SwiftPlate](https://github.com/JohnSundell/SwiftPlate)
* Swift 4 (Swift 3 compatible)
### 🔮 Example
@@ -144,7 +162,7 @@ public protocol SkeletonTableViewDataSource: UITableViewDataSource {
func collectionSkeletonView(_ skeletonView: UITableView, cellIdenfierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier
}
```
As you can see, this protocol inherits from ```UITableViewDataSource``, so you can replace this protocol with the skeleton protocol.
As you can see, this protocol inherits from ```UITableViewDataSource```, so you can replace this protocol with the skeleton protocol.
This protocol has a default implementation:
@@ -185,7 +203,9 @@ You can decide which color the skeleton is tinted with. You only need to pass as
**Using solid colors**
``` swift
view.showSkeleton(usingColor: UIColor.midnightBlue) // Solid
view.showSkeleton(usingColor: UIColor.gray) // Solid
// or
view.showSkeleton(usingColor: UIColor(red: 25.0, green: 30.0, blue: 255.0, alpha: 1.0))
```
**Using gradients**
``` swift
@@ -193,7 +213,9 @@ let gradient = SkeletonGradient(baseColor: UIColor.midnightBlue)
view.showGradientSkeleton(usingGradient: gradient) // Gradient
```
```SkeletonView``` features 20 flat colors 🤙🏼:
Besides, ```SkeletonView``` features 20 flat colors 🤙🏼
```UIColor.turquoise, UIColor.greenSea, UIColor.sunFlower, UIColor.flatOrange ...```
![](Assets/flatcolors.png)
###### Image captured from website [https://flatuicolors.com](https://flatuicolors.com)
@@ -222,6 +244,33 @@ view.showAnimatedSkeleton { (layer) -> CAAnimation in
}
```
**NEW** It's available ```SkeletonAnimationBuilder```. It's a builder to make ```SkeletonLayerAnimation```.
Today, you can create **sliding animations** for gradients, deciding the **direction** and setting the **duration** of the animation (default = 1.5s).
```swift
// func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation
let animation = SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: .leftToRight)
view.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
```
```GradientDirection``` is an enum, with this cases:
| Direction | Preview
|------- | -------
| .leftRight | ![](Assets/sliding_left_to_right.gif)
| .rightLeft | ![](Assets/sliding_right_to_left.gif)
| .topBottom | ![](Assets/sliding_top_to_bottom.gif)
| .bottomTop | ![](Assets/sliding_bottom_to_top.gif)
| .topLeftBottomRight | ![](Assets/sliding_topLeft_to_bottomRight.gif)
| .bottomRightTopLeft | ![](Assets/sliding_bottomRight_to_topLeft.gif)
> **😉 TRICK!**
Exist another way to create sliding animations, just using this shortcut:
>>```let animation = GradientDirection.leftToRight.slidingAnimation()```
### 👨‍👧‍👦 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.
@@ -250,9 +299,11 @@ 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)
## 👨🏻‍💻 Author
[1.1]: http://i.imgur.com/tXSoThF.png
[1]: http://www.twitter.com/juanpe_catalan
[1]: http://www.twitter.com/JuanpeCatalan
* Juanpe Catalán [![alt text][1.1]][1]
+2 -2
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SkeletonView"
s.version = "1.0.1"
s.version = "1.0.3"
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.
@@ -9,7 +9,7 @@ Pod::Spec.new do |s|
s.homepage = "https://github.com/Juanpe/SkeletonView"
s.license = { :type => "MIT", :file => "LICENSE" }
s.author = { "Juanpe Catalán" => "juanpecm@gmail.com" }
s.social_media_url = "https://twitter.com/juanpe_catalan"
s.social_media_url = "https://twitter.com/JuanpeCatalan"
s.ios.deployment_target = "9.0"
s.source = { :git => "https://github.com/Juanpe/SkeletonView.git", :tag => s.version.to_s }
s.source_files = "Sources/**/*"
+4
View File
@@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */
8933C7851EB5B820000D00A4 /* SkeletonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7841EB5B820000D00A4 /* SkeletonView.swift */; };
F51DE1091FBF70A70037919A /* SkeletonAnimationBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */; };
F5307E2C1FAF6BC900EE67C5 /* SkeletonGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E2B1FAF6BC900EE67C5 /* SkeletonGradient.swift */; };
F5307E2E1FB0E5E400EE67C5 /* UIView+Frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */; };
F5307E301FB0EC9D00EE67C5 /* SkeletonDefaultConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5307E2F1FB0EC9D00EE67C5 /* SkeletonDefaultConfig.swift */; };
@@ -61,6 +62,7 @@
52D6D97C1BEFF229002C0205 /* SkeletonView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SkeletonView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8933C7841EB5B820000D00A4 /* SkeletonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SkeletonView.swift; sourceTree = "<group>"; };
AD2FAA261CD0B6D800659CF4 /* SkeletonView.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SkeletonView.plist; sourceTree = "<group>"; };
F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonAnimationBuilder.swift; sourceTree = "<group>"; };
F5307E2B1FAF6BC900EE67C5 /* SkeletonGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonGradient.swift; sourceTree = "<group>"; };
F5307E2D1FB0E5E400EE67C5 /* UIView+Frame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Frame.swift"; sourceTree = "<group>"; };
F5307E2F1FB0EC9D00EE67C5 /* SkeletonDefaultConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonDefaultConfig.swift; sourceTree = "<group>"; };
@@ -140,6 +142,7 @@
F5307E331FB1068500EE67C5 /* Collections */,
F5307E341FB106A500EE67C5 /* Extensions */,
F5307E351FB106BF00EE67C5 /* Helpers */,
F51DE1081FBF70A70037919A /* SkeletonAnimationBuilder.swift */,
F5307E2F1FB0EC9D00EE67C5 /* SkeletonDefaultConfig.swift */,
F5307E2B1FAF6BC900EE67C5 /* SkeletonGradient.swift */,
F5F899E81FAB9D2B002E8FDA /* SkeletonLayer.swift */,
@@ -349,6 +352,7 @@
F5307E3B1FB123C100EE67C5 /* ContainsMultilineText.swift in Sources */,
F5F899E91FAB9D2B002E8FDA /* SkeletonLayer.swift in Sources */,
F5307E2E1FB0E5E400EE67C5 /* UIView+Frame.swift in Sources */,
F51DE1091FBF70A70037919A /* SkeletonAnimationBuilder.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -44,7 +44,7 @@ extension UIView {
set { objc_setAssociatedObject(self, &AssociatedKeys.status, newValue, AssociationPolicy.retain.objc) }
}
private var skeletonable: Bool! {
fileprivate var skeletonable: Bool! {
get { return objc_getAssociatedObject(self, &AssociatedKeys.skeletonable) as? Bool ?? false }
set { objc_setAssociatedObject(self, &AssociatedKeys.skeletonable, newValue, AssociationPolicy.retain.objc) }
}
+85
View File
@@ -0,0 +1,85 @@
//
// SkeletonAnimationBuilder.swift
// SkeletonView-iOS
//
// Created by Juanpe Catalán on 17/11/2017.
// Copyright © 2017 SkeletonView. All rights reserved.
//
import UIKit
typealias GradientAnimationPoint = (from: CGPoint, to: CGPoint)
public enum GradientDirection {
case leftRight
case rightLeft
case topBottom
case bottomTop
case topLeftBottomRight
case bottomRightTopLeft
public func slidingAnimation(duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation {
return SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: self, duration: duration)
}
var startPoint: GradientAnimationPoint {
switch self {
case .leftRight:
return (from: CGPoint(x:-1, y:0.5), to: CGPoint(x:1, y:0.5))
case .rightLeft:
return (from: CGPoint(x:1, y:0.5), to: CGPoint(x:-1, y:0.5))
case .topBottom:
return (from: CGPoint(x:0.5, y:-1), to: CGPoint(x:0.5, y:1))
case .bottomTop:
return (from: CGPoint(x:0.5, y:1), to: CGPoint(x:0.5, y:-1))
case .topLeftBottomRight:
return (from: CGPoint(x:-1, y:-1), to: CGPoint(x:1, y:1))
case .bottomRightTopLeft:
return (from: CGPoint(x:1, y:1), to: CGPoint(x:-1, y:-1))
}
}
var endPoint: GradientAnimationPoint {
switch self {
case .leftRight:
return (from: CGPoint(x:0, y:0.5), to: CGPoint(x:2, y:0.5))
case .rightLeft:
return ( from: CGPoint(x:2, y:0.5), to: CGPoint(x:0, y:0.5))
case .topBottom:
return ( from: CGPoint(x:0.5, y:0), to: CGPoint(x:0.5, y:2))
case .bottomTop:
return ( from: CGPoint(x:0.5, y:2), to: CGPoint(x:0.5, y:0))
case .topLeftBottomRight:
return ( from: CGPoint(x:0, y:0), to: CGPoint(x:2, y:2))
case .bottomRightTopLeft:
return ( from: CGPoint(x:2, y:2), to: CGPoint(x:0, y:0))
}
}
}
public class SkeletonAnimationBuilder {
public init() {
}
public func makeSlidingAnimation(withDirection direction: GradientDirection, duration: CFTimeInterval = 1.5) -> SkeletonLayerAnimation {
return { layer in
let startPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.startPoint))
startPointAnim.fromValue = NSValue(cgPoint: direction.startPoint.from)
startPointAnim.toValue = NSValue(cgPoint: direction.startPoint.to)
let endPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.endPoint))
endPointAnim.fromValue = NSValue(cgPoint: direction.endPoint.from)
endPointAnim.toValue = NSValue(cgPoint: direction.endPoint.to)
let animGroup = CAAnimationGroup()
animGroup.animations = [startPointAnim, endPointAnim]
animGroup.duration = duration
animGroup.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
animGroup.repeatCount = .infinity
return animGroup
}
}
}
+3 -3
View File
@@ -64,14 +64,14 @@ extension UIView {
}
}
private func startSkeletonLayerAnimationBlock(_ anim: SkeletonLayerAnimation? = nil) -> VoidBlock {
fileprivate func startSkeletonLayerAnimationBlock(_ anim: SkeletonLayerAnimation? = nil) -> VoidBlock {
return {
guard let layer = self.skeletonLayer else { return }
layer.start(anim)
}
}
private var stopSkeletonLayerAnimationBlock: VoidBlock {
fileprivate var stopSkeletonLayerAnimationBlock: VoidBlock {
return {
guard let layer = self.skeletonLayer else { return }
layer.stopAnimation()
@@ -105,7 +105,7 @@ extension UIStackView {
extension UIView {
func addSkeletonLayer(withType type: SkeletonType, usingColors colors: [UIColor], animated: Bool, animation: SkeletonLayerAnimation? = nil) {
func addSkeletonLayer(withType type: SkeletonType, usingColors colors: [UIColor], gradientDirection direction: GradientDirection? = nil, animated: Bool, animation: SkeletonLayerAnimation? = nil) {
self.skeletonLayer = SkeletonLayerFactory().makeLayer(withType: type, usingColors: colors, andHolder: self)
layer.insertSublayer(skeletonLayer!.contentLayer, at: UInt32.max)
if animated { skeletonLayer!.start(animation) }