├── .gitignore ├── Infinity.podspec ├── Infinity ├── .DS_Store ├── InfiniteScroller.swift ├── Infinity.h ├── Info.plist ├── PullToRefresher.swift ├── UIScrollView+Infinity.swift └── controls │ ├── arrow │ └── ArrowRefreshAnimator.swift │ ├── circle │ ├── CircleInfinityAnimator.swift │ └── CircleRefreshAnimator.swift │ ├── default │ ├── DefaultInfinityAnimator.swift │ └── DefaultRefreshAnimator.swift │ ├── gif │ ├── GIFInfinityAnimator.swift │ └── GIFRefreshAnimator.swift │ ├── normal │ ├── NormalInfinityAnimator.swift │ └── NormalRefreshAnimator.swift │ ├── snake │ ├── SnakeInfinityAnimator.swift │ └── SnakeRefreshAnimator.swift │ └── spark │ ├── SparkInfinityAnimator.swift │ └── SparkRefreshAnimator.swift ├── InfinitySample.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ ├── danis.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── liaolei.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ └── Infinity.xcscheme └── xcuserdata │ ├── danis.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── InfinitySample.xcscheme │ │ └── xcschememanagement.plist │ └── liaolei.xcuserdatad │ └── xcschemes │ ├── InfinitySample.xcscheme │ └── xcschememanagement.plist ├── InfinitySample ├── .DS_Store ├── AddSamplesTableViewController.swift ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── InfinityIcon-1.png │ │ └── InfinityIcon.png │ ├── Contents.json │ ├── buildings.imageset │ │ ├── Contents.json │ │ └── buildings.png │ ├── parallax-header │ │ └── Contents.json │ ├── sky.imageset │ │ ├── Contents.json │ │ └── sky.png │ └── sun.imageset │ │ ├── Contents.json │ │ └── sun.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── BindSamplesTableViewController.swift ├── Info.plist ├── Main1TableViewController.swift ├── Main2TableViewController.swift └── sample-gif.xcassets │ ├── hud_0.imageset │ ├── Contents.json │ ├── hud_30.png │ └── hud_30@2x.png │ ├── hud_1.imageset │ ├── Contents.json │ ├── hud_1.png │ └── hud_1@2x.png │ ├── hud_10.imageset │ ├── Contents.json │ ├── hud_10.png │ └── hud_10@2x.png │ ├── hud_11.imageset │ ├── Contents.json │ ├── hud_11.png │ └── hud_11@2x.png │ ├── hud_12.imageset │ ├── Contents.json │ ├── hud_12.png │ └── hud_12@2x.png │ ├── hud_13.imageset │ ├── Contents.json │ ├── hud_13.png │ └── hud_13@2x.png │ ├── hud_14.imageset │ ├── Contents.json │ ├── hud_14.png │ └── hud_14@2x.png │ ├── hud_15.imageset │ ├── Contents.json │ ├── hud_15.png │ └── hud_15@2x.png │ ├── hud_16.imageset │ ├── Contents.json │ ├── hud_16.png │ └── hud_16@2x.png │ ├── hud_17.imageset │ ├── Contents.json │ ├── hud_17.png │ └── hud_17@2x.png │ ├── hud_18.imageset │ ├── Contents.json │ ├── hud_18.png │ └── hud_18@2x.png │ ├── hud_19.imageset │ ├── Contents.json │ ├── hud_19.png │ └── hud_19@2x.png │ ├── hud_2.imageset │ ├── Contents.json │ ├── hud_2.png │ └── hud_2@2x.png │ ├── hud_20.imageset │ ├── Contents.json │ ├── hud_20.png │ └── hud_20@2x.png │ ├── hud_21.imageset │ ├── Contents.json │ ├── hud_21.png │ └── hud_21@2x.png │ ├── hud_22.imageset │ ├── Contents.json │ ├── hud_22.png │ └── hud_22@2x.png │ ├── hud_23.imageset │ ├── Contents.json │ ├── hud_23.png │ └── hud_23@2x.png │ ├── hud_24.imageset │ ├── Contents.json │ ├── hud_24.png │ └── hud_24@2x.png │ ├── hud_25.imageset │ ├── Contents.json │ ├── hud_25.png │ └── hud_25@2x.png │ ├── hud_26.imageset │ ├── Contents.json │ ├── hud_26.png │ └── hud_26@2x.png │ ├── hud_27.imageset │ ├── Contents.json │ ├── hud_27.png │ └── hud_27@2x.png │ ├── hud_28.imageset │ ├── Contents.json │ ├── hud_28.png │ └── hud_28@2x.png │ ├── hud_29.imageset │ ├── Contents.json │ ├── hud_29.png │ └── hud_29@2x.png │ ├── hud_3.imageset │ ├── Contents.json │ ├── hud_3.png │ └── hud_3@2x.png │ ├── hud_4.imageset │ ├── Contents.json │ ├── hud_4.png │ └── hud_4@2x.png │ ├── hud_5.imageset │ ├── Contents.json │ ├── hud_5.png │ └── hud_5@2x.png │ ├── hud_6.imageset │ ├── Contents.json │ ├── hud_6.png │ └── hud_6@2x.png │ ├── hud_7.imageset │ ├── Contents.json │ ├── hud_7.png │ └── hud_7@2x.png │ ├── hud_8.imageset │ ├── Contents.json │ ├── hud_8.png │ └── hud_8@2x.png │ └── hud_9.imageset │ ├── Contents.json │ ├── hud_9.png │ └── hud_9@2x.png ├── InfinitySampleTests ├── InfinitySampleTests.swift └── Info.plist ├── InfinityTests ├── InfinityTests.swift └── Info.plist ├── LICENSE ├── Products └── Infinity.framework │ ├── Headers │ ├── Infinity-Swift.h │ └── Infinity.h │ ├── Infinity │ ├── Info.plist │ └── Modules │ ├── Infinity.swiftmodule │ ├── arm.swiftdoc │ ├── arm.swiftmodule │ ├── arm64.swiftdoc │ └── arm64.swiftmodule │ └── module.modulemap ├── README.md ├── README_CN.md └── images ├── .DS_Store ├── add-default.gif ├── bind-default.gif ├── logo.png └── weak.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | .DS_Store -------------------------------------------------------------------------------- /Infinity.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Infinity" 3 | s.version = "4.0.0" 4 | s.summary = "A simple way to make UIScrollView support pull-to-refresh & infinity-scroll" 5 | s.homepage = "https://github.com/selfcreator/Infinity" 6 | s.license = 'MIT' 7 | s.author = { "DanisFabric" => "danisfabric@gmail.com" } 8 | s.source = { :git => "https://github.com/selfcreator/Infinity.git", :tag => s.version.to_s } 9 | s.platform = :ios, '11.0' 10 | s.requires_arc = true 11 | s.source_files = 'Infinity/**/*' 12 | s.exclude_files = "Infinity/**/*.plist" 13 | s.swift_version = '4.2' 14 | s.ios.deployment_target = '10.0' 15 | 16 | end 17 | -------------------------------------------------------------------------------- /Infinity/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/Infinity/.DS_Store -------------------------------------------------------------------------------- /Infinity/InfiniteScroller.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfinityScroller.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/21. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol CustomInfiniteScrollAnimator { 12 | func animateState(_ state: InfiniteScrollState) 13 | } 14 | 15 | public enum InfiniteScrollState: Equatable, CustomStringConvertible { 16 | case none 17 | case loading 18 | 19 | public var description: String { 20 | switch self { 21 | case .none: return "None" 22 | case .loading: return "Loading" 23 | } 24 | } 25 | } 26 | public func == (left: InfiniteScrollState, right: InfiniteScrollState) -> Bool { 27 | switch (left, right) { 28 | case (.none, .none): return true 29 | case (.loading, .loading): return true 30 | default: 31 | return false 32 | } 33 | } 34 | 35 | class InfiniteScroller: NSObject { 36 | weak var scrollView: UIScrollView? { 37 | willSet { 38 | removeScrollViewObserving(scrollView) 39 | self.containerView.removeFromSuperview() 40 | } 41 | didSet { 42 | addScrollViewObserving(scrollView) 43 | if let scrollView = scrollView { 44 | defaultContentInset = scrollView.contentInset 45 | 46 | scrollView.addSubview(containerView) 47 | adjustFooterFrame() 48 | } 49 | } 50 | } 51 | var animator: CustomInfiniteScrollAnimator 52 | var containerView: FooterContainerView 53 | var action: (() -> Void)? 54 | var enable = true 55 | 56 | // Values 57 | var defaultContentInset = UIEdgeInsets() 58 | var defaultHeightToTrigger: CGFloat = 0 59 | // 是否在底部留出bottom inset,还是直接黏着内容,紧跟contentSize 60 | var stickToContent = true { 61 | didSet { 62 | adjustFooterFrame() 63 | } 64 | } 65 | 66 | init(height: CGFloat, animator: CustomInfiniteScrollAnimator) { 67 | self.defaultHeightToTrigger = height 68 | self.animator = animator 69 | self.containerView = FooterContainerView() 70 | } 71 | 72 | // MARK: - Observe Scroll View 73 | var KVOContext = "InfinityScrollKVOContext" 74 | func addScrollViewObserving(_ scrollView: UIScrollView?) { 75 | scrollView?.addObserver(self, forKeyPath: "contentOffset", options: .new, context: &KVOContext) 76 | scrollView?.addObserver(self, forKeyPath: "contentInset", options: .new, context: &KVOContext) 77 | scrollView?.addObserver(self, forKeyPath: "contentSize", options: .new, context: &KVOContext) 78 | } 79 | func removeScrollViewObserving(_ scrollView: UIScrollView?) { 80 | scrollView?.removeObserver(self, forKeyPath: "contentOffset", context: &KVOContext) 81 | scrollView?.removeObserver(self, forKeyPath: "contentInset", context: &KVOContext) 82 | scrollView?.removeObserver(self, forKeyPath: "contentSize", context: &KVOContext) 83 | } 84 | fileprivate var lastOffset = CGPoint() 85 | 86 | 87 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 88 | if context == &KVOContext { 89 | if keyPath == "contentSize" { 90 | adjustFooterFrame() 91 | } 92 | else if keyPath == "contentInset" { 93 | guard !self.scrollView!.lockInset else { 94 | return 95 | } 96 | defaultContentInset = (change![.newKey]! as AnyObject).uiEdgeInsetsValue! 97 | adjustFooterFrame() 98 | } 99 | else if keyPath == "contentOffset" { 100 | let point = (change![.newKey]! as AnyObject).cgPointValue! 101 | 102 | guard lastOffset.y != point.y else { 103 | return 104 | } 105 | guard !updatingState && enable else { 106 | return 107 | } 108 | 109 | var distance: CGFloat = 0 110 | if stickToContent { 111 | distance = scrollView!.contentSize.height - point.y - scrollView!.frame.height 112 | }else { 113 | distance = scrollView!.contentSize.height + self.defaultContentInset.bottom - point.y - scrollView!.frame.height 114 | } 115 | // 要保证scrollView里面是有内容的, 且保证是在上滑 116 | if distance < 0 && self.state != .loading && scrollView!.contentSize.height > 0 && point.y > lastOffset.y { 117 | self.state = .loading 118 | } 119 | 120 | lastOffset = point 121 | } 122 | } 123 | else { 124 | super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) 125 | } 126 | } 127 | var lockInset = false 128 | var updatingState = false 129 | var state: InfiniteScrollState = .none { 130 | didSet { 131 | self.animator.animateState(state) 132 | switch self.state { 133 | case .loading where oldValue == .none: 134 | 135 | self.updatingState = true 136 | let jumpToBottom = self.defaultHeightToTrigger + self.defaultContentInset.bottom 137 | let inset = UIEdgeInsets(top: self.defaultContentInset.top, left: self.defaultContentInset.left, bottom: jumpToBottom, right: self.defaultContentInset.right) 138 | self.scrollView?.setContentInset(inset, completion: { [unowned self] (finished) -> Void in 139 | self.updatingState = false 140 | }) 141 | self.action?() 142 | case .none where oldValue == .loading: 143 | self.updatingState = true 144 | self.scrollView?.setContentInset(self.defaultContentInset, completion: { (finished) -> Void in 145 | self.updatingState = false 146 | }) 147 | default: 148 | break 149 | } 150 | } 151 | } 152 | 153 | func adjustFooterFrame() { 154 | if let scrollView = scrollView { 155 | if stickToContent { 156 | containerView.frame = CGRect(x: 0, y: scrollView.contentSize.height, width: scrollView.bounds.width, height: defaultHeightToTrigger) 157 | }else { 158 | containerView.frame = CGRect(x: 0, y: scrollView.contentSize.height + self.defaultContentInset.bottom, width: scrollView.bounds.width, height: defaultHeightToTrigger) 159 | } 160 | } 161 | } 162 | // MARK: - Infinity Scroll 163 | func beginInfiniteScrolling() { 164 | scrollView?.setContentOffset(CGPoint(x: 0, y: (scrollView!.contentSize.height + defaultContentInset.bottom - scrollView!.frame.height + defaultHeightToTrigger)), animated: true) 165 | } 166 | func endInfiniteScrolling() { 167 | self.state = .none 168 | } 169 | } 170 | 171 | class FooterContainerView: UIView { 172 | 173 | override func layoutSubviews() { 174 | super.layoutSubviews() 175 | 176 | for view in subviews { 177 | view.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /Infinity/Infinity.h: -------------------------------------------------------------------------------- 1 | // 2 | // Infinity.h 3 | // Infinity 4 | // 5 | // Created by Danis on 15/12/21. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Infinity. 12 | FOUNDATION_EXPORT double InfinityVersionNumber; 13 | 14 | //! Project version string for Infinity. 15 | FOUNDATION_EXPORT const unsigned char InfinityVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Infinity/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Infinity/PullToRefresher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PullToRefresher.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/21. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol CustomPullToRefreshAnimator { 12 | func animateState(_ state: PullToRefreshState) 13 | } 14 | 15 | public enum PullToRefreshState: Equatable, CustomStringConvertible { 16 | case none 17 | case releasing(progress:CGFloat) 18 | case loading 19 | 20 | public var description: String { 21 | switch self { 22 | case .none: return "None" 23 | case .releasing(let progress): return "Releasing: \(progress)" 24 | case .loading: return "Loading" 25 | } 26 | } 27 | } 28 | public func == (left: PullToRefreshState, right: PullToRefreshState) -> Bool { 29 | switch (left, right) { 30 | case (.none, .none): return true 31 | case (.releasing, .releasing): return true 32 | case (.loading, .loading): return true 33 | default: 34 | return false 35 | } 36 | } 37 | 38 | class PullToRefresher: NSObject { 39 | weak var scrollView: UIScrollView? { 40 | willSet { 41 | removeScrollViewObserving(scrollView) 42 | self.containerView.removeFromSuperview() 43 | } 44 | didSet { 45 | addScrollViewObserving(scrollView) 46 | if let scrollView = scrollView { 47 | defaultContentInset = scrollView.contentInset 48 | 49 | containerView.scrollView = scrollView 50 | scrollView.addSubview(containerView) 51 | containerView.frame = CGRect(x: 0 + animatorOffset.horizontal, y: -defaultHeightToTrigger + animatorOffset.vertical, width: scrollView.frame.width, height: defaultHeightToTrigger) 52 | } 53 | } 54 | } 55 | var animator: CustomPullToRefreshAnimator 56 | var containerView: HeaderContainerView 57 | var action:(()->Void)? 58 | var enable = true 59 | 60 | var animatorOffset: UIOffset = UIOffset() { 61 | didSet { 62 | if let scrollView = scrollView { 63 | containerView.frame = CGRect(x: 0 + animatorOffset.horizontal, y: -defaultHeightToTrigger + animatorOffset.vertical, width: scrollView.frame.width, height: defaultHeightToTrigger) 64 | if Infinity.debugModeEnabled { 65 | print(containerView.frame) 66 | } 67 | } 68 | } 69 | } 70 | // Values 71 | var defaultContentInset: UIEdgeInsets = UIEdgeInsets() 72 | var defaultHeightToTrigger: CGFloat = 0 73 | var scrollbackImmediately = true 74 | 75 | init(height: CGFloat, animator: CustomPullToRefreshAnimator) { 76 | self.defaultHeightToTrigger = height 77 | self.animator = animator 78 | self.containerView = HeaderContainerView() 79 | } 80 | // MARK: - Observe Scroll View 81 | var KVOContext = "PullToRefreshKVOContext" 82 | func addScrollViewObserving(_ scrollView: UIScrollView?) { 83 | scrollView?.addObserver(self, forKeyPath: "contentOffset", options: .new, context: &KVOContext) 84 | scrollView?.addObserver(self, forKeyPath: "contentInset", options: .new, context: &KVOContext) 85 | 86 | } 87 | func removeScrollViewObserving(_ scrollView: UIScrollView?) { 88 | scrollView?.removeObserver(self, forKeyPath: "contentOffset", context: &KVOContext) 89 | scrollView?.removeObserver(self, forKeyPath: "contentInset", context: &KVOContext) 90 | } 91 | 92 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 93 | if context == &KVOContext { 94 | if keyPath == "contentOffset" { 95 | guard !updatingState && enable else { 96 | return 97 | } 98 | let point = (change![.newKey]! as AnyObject).cgPointValue! 99 | let offsetY = point.y + defaultContentInset.top 100 | switch offsetY { 101 | case 0 where state != .loading: 102 | state = .none 103 | case -defaultHeightToTrigger...0 where state != .loading: 104 | state = .releasing(progress: min(-offsetY / defaultHeightToTrigger, 1.0)) 105 | case (-CGFloat.greatestFiniteMagnitude)...(-defaultHeightToTrigger) where state == .releasing(progress:1): 106 | if scrollView!.isDragging { 107 | state = .releasing(progress: 1.0) 108 | }else { 109 | state = .loading 110 | } 111 | default: 112 | break 113 | } 114 | } 115 | else if keyPath == "contentInset" { 116 | guard !self.scrollView!.lockInset else { 117 | return 118 | } 119 | self.defaultContentInset = (change![.newKey]! as AnyObject).uiEdgeInsetsValue! 120 | } 121 | 122 | }else { 123 | super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) 124 | } 125 | } 126 | var updatingState = false 127 | var state: PullToRefreshState = .none { 128 | didSet { 129 | self.animator.animateState(state) 130 | 131 | switch self.state { 132 | case .none where oldValue == .loading: 133 | if !self.scrollbackImmediately { 134 | self.updatingState = true 135 | if self.scrollView is UICollectionView { 136 | self.scrollView?.setContentInset(self.defaultContentInset, completion: { [unowned self] (finished) -> Void in 137 | self.updatingState = false 138 | }) 139 | } else { 140 | self.scrollView?.setContentInset(self.defaultContentInset, completion: { [unowned self] (finished) -> Void in 141 | self.updatingState = false 142 | }) 143 | } 144 | } 145 | 146 | case .loading where oldValue != .loading: 147 | if !self.scrollbackImmediately { 148 | self.updatingState = true 149 | var inset = self.defaultContentInset 150 | inset.top += self.defaultHeightToTrigger 151 | self.scrollView?.setContentInset(inset, completion: { [unowned self] (finished) -> Void in 152 | self.updatingState = false 153 | }) 154 | } 155 | self.action?() 156 | default: 157 | break 158 | } 159 | } 160 | } 161 | // MARK: - Refresh 162 | func beginRefreshing() { 163 | self.scrollView?.setContentOffset(CGPoint(x: 0, y: -(defaultHeightToTrigger + defaultContentInset.top + 1)), animated: true) 164 | } 165 | func endRefreshing() { 166 | self.state = .none 167 | } 168 | } 169 | 170 | 171 | class HeaderContainerView: UIView { 172 | 173 | var scrollView: UIScrollView? 174 | 175 | override func layoutSubviews() { 176 | super.layoutSubviews() 177 | 178 | for view in subviews { 179 | view.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) 180 | } 181 | } 182 | override func didMoveToSuperview() { 183 | super.didMoveToSuperview() 184 | 185 | self.firstResponderViewController()?.automaticallyAdjustsScrollViewInsets = false 186 | } 187 | } 188 | 189 | extension UIView { 190 | func firstResponderViewController() -> UIViewController? { 191 | var responder: UIResponder? = self as UIResponder 192 | while responder != nil { 193 | if responder!.isKind(of: UIViewController.self) { 194 | return responder as? UIViewController 195 | } 196 | responder = responder?.next 197 | } 198 | return nil 199 | } 200 | } 201 | 202 | -------------------------------------------------------------------------------- /Infinity/UIScrollView+Infinity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+Infinity.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/21. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | private var associatedPullToRefresherKey: String = "InfinityPullToRefresherKey" 12 | private var associatedInfiniteScrollerKey: String = "InfinityInfiniteScrollerKey" 13 | 14 | private var associatedisPullToRefreshEnabledKey: String = "InfinityisPullToRefreshEnabledKey" 15 | private var associatedisInfiniteScrollEnabledKey: String = "InfinityisInfiniteScrollEnabledKey" 16 | 17 | private var associatedInfinityKey = "Infinity.Associated.Infinity" 18 | 19 | // MARK: - PullToRefresh 20 | extension UIScrollView { 21 | public var fty: Infinity { 22 | get { 23 | if let value = objc_getAssociatedObject(self, &associatedInfinityKey) as? Infinity { 24 | return value 25 | } else { 26 | let newValue = Infinity(scrollView: self) 27 | objc_setAssociatedObject(self, &associatedInfinityKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 28 | 29 | return newValue 30 | } 31 | } 32 | } 33 | 34 | } 35 | 36 | public class PullToRefreshWrapper { 37 | let scrollView: UIScrollView 38 | init(scrollView: UIScrollView) { 39 | self.scrollView = scrollView 40 | } 41 | 42 | public func add(height: CGFloat = 60, animator: CustomPullToRefreshAnimator, action: (() -> Void)?) { 43 | scrollView.addPullToRefresh(height, animator: animator, action: action) 44 | } 45 | public func bind(height: CGFloat = 60, animator: CustomPullToRefreshAnimator, action: (() -> Void)?) { 46 | scrollView.bindPullToRefresh(height, toAnimator: animator, action: action) 47 | } 48 | public func remove() { 49 | scrollView.removePullToRefresh() 50 | } 51 | public func begin() { 52 | scrollView.beginRefreshing() 53 | } 54 | public func end() { 55 | scrollView.endRefreshing() 56 | } 57 | public var isEnabled: Bool { 58 | get { 59 | return scrollView.isPullToRefreshEnabled 60 | } 61 | set { 62 | scrollView.isPullToRefreshEnabled = newValue 63 | } 64 | } 65 | public var isScrollingToTopImmediately: Bool { 66 | get { 67 | return scrollView.isScrollingToTopImmediately 68 | } 69 | set { 70 | scrollView.isScrollingToTopImmediately = newValue 71 | } 72 | } 73 | public var animatorOffset: UIOffset { 74 | get { 75 | if let offset = scrollView.pullToRefresher?.animatorOffset { 76 | return offset 77 | } 78 | return UIOffset() 79 | } 80 | set { 81 | scrollView.pullToRefresher?.animatorOffset = newValue 82 | } 83 | } 84 | } 85 | public class InfiniteScrollWrapper { 86 | let scrollView: UIScrollView 87 | init(scrollView: UIScrollView) { 88 | self.scrollView = scrollView 89 | } 90 | public func add(height: CGFloat = 60, animator: CustomInfiniteScrollAnimator, action: (() -> Void)?) { 91 | scrollView.addInfiniteScroll(height, animator: animator, action: action) 92 | } 93 | public func bind(height: CGFloat = 60, animator: CustomInfiniteScrollAnimator, action: (() -> Void)?) { 94 | scrollView.bindInfiniteScroll(height, toAnimator: animator, action: action) 95 | } 96 | public func remove() { 97 | scrollView.removeInfiniteScroll() 98 | } 99 | public func begin() { 100 | scrollView.beginInfiniteScrolling() 101 | } 102 | public func end() { 103 | scrollView.endInfiniteScrolling() 104 | } 105 | public var isEnabled: Bool { 106 | get { 107 | return scrollView.isInfiniteScrollEnabled 108 | } 109 | set { 110 | scrollView.isInfiniteScrollEnabled = newValue 111 | } 112 | } 113 | public var isStickToContent: Bool { 114 | get { 115 | return scrollView.isInfiniteStickToContent 116 | } 117 | set { 118 | scrollView.isInfiniteStickToContent = newValue 119 | } 120 | } 121 | } 122 | 123 | public class Infinity { 124 | /// Will output some debug information if `true`. 125 | /// Default value: `false` 126 | public static var debugModeEnabled = false 127 | public let pullToRefresh: PullToRefreshWrapper 128 | public let infiniteScroll: InfiniteScrollWrapper 129 | 130 | let scrollView: UIScrollView 131 | 132 | init(scrollView: UIScrollView) { 133 | self.scrollView = scrollView 134 | pullToRefresh = PullToRefreshWrapper(scrollView: scrollView) 135 | infiniteScroll = InfiniteScrollWrapper(scrollView: scrollView) 136 | } 137 | 138 | 139 | public func clear() { 140 | pullToRefresh.remove() 141 | infiniteScroll.remove() 142 | } 143 | } 144 | 145 | 146 | extension UIScrollView { 147 | 148 | func addPullToRefresh(_ height: CGFloat = 60.0, animator: CustomPullToRefreshAnimator, action:(()->Void)?) { 149 | 150 | bindPullToRefresh(height, toAnimator: animator, action: action) 151 | self.pullToRefresher?.scrollbackImmediately = false 152 | 153 | if let animatorView = animator as? UIView { 154 | self.pullToRefresher?.containerView.addSubview(animatorView) 155 | } 156 | 157 | } 158 | func bindPullToRefresh(_ height: CGFloat = 60.0, toAnimator: CustomPullToRefreshAnimator, action:(()->Void)?) { 159 | removePullToRefresh() 160 | 161 | self.pullToRefresher = PullToRefresher(height: height, animator: toAnimator) 162 | self.pullToRefresher?.scrollView = self 163 | self.pullToRefresher?.action = action 164 | } 165 | func removePullToRefresh() { 166 | self.pullToRefresher?.scrollView = nil 167 | self.pullToRefresher = nil 168 | } 169 | func beginRefreshing() { 170 | self.pullToRefresher?.beginRefreshing() 171 | } 172 | func endRefreshing() { 173 | self.pullToRefresher?.endRefreshing() 174 | } 175 | 176 | //MARK: - Properties 177 | var pullToRefresher: PullToRefresher? { 178 | get { 179 | return objc_getAssociatedObject(self, &associatedPullToRefresherKey) as? PullToRefresher 180 | } 181 | set { 182 | objc_setAssociatedObject(self, &associatedPullToRefresherKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 183 | } 184 | } 185 | var isPullToRefreshEnabled: Bool { 186 | get { 187 | return pullToRefresher?.enable ?? false 188 | } 189 | set { 190 | pullToRefresher?.enable = newValue 191 | } 192 | } 193 | var isScrollingToTopImmediately: Bool { 194 | get { 195 | return pullToRefresher?.scrollbackImmediately ?? false 196 | } 197 | set { 198 | pullToRefresher?.scrollbackImmediately = newValue 199 | } 200 | } 201 | } 202 | 203 | // MARK: - InfiniteScroll 204 | extension UIScrollView { 205 | 206 | func addInfiniteScroll(_ height: CGFloat = 80.0, animator: CustomInfiniteScrollAnimator, action: (() -> Void)?) { 207 | bindInfiniteScroll(height, toAnimator: animator, action: action) 208 | 209 | if let animatorView = animator as? UIView { 210 | self.infiniteScroller?.containerView.addSubview(animatorView) 211 | } 212 | } 213 | func bindInfiniteScroll(_ height: CGFloat = 80.0, toAnimator: CustomInfiniteScrollAnimator, action: (() -> Void)?) { 214 | removeInfiniteScroll() 215 | 216 | self.infiniteScroller = InfiniteScroller(height: height, animator: toAnimator) 217 | self.infiniteScroller?.scrollView = self 218 | self.infiniteScroller?.action = action 219 | } 220 | func removeInfiniteScroll() { 221 | self.infiniteScroller?.scrollView = nil 222 | self.infiniteScroller = nil 223 | } 224 | func beginInfiniteScrolling() { 225 | self.infiniteScroller?.beginInfiniteScrolling() 226 | } 227 | func endInfiniteScrolling() { 228 | self.infiniteScroller?.endInfiniteScrolling() 229 | } 230 | 231 | //MARK: - Properties 232 | var infiniteScroller: InfiniteScroller? { 233 | get { 234 | return objc_getAssociatedObject(self, &associatedInfiniteScrollerKey) as? InfiniteScroller 235 | } 236 | set { 237 | objc_setAssociatedObject(self, &associatedInfiniteScrollerKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 238 | } 239 | } 240 | // 当并未添加infinityScroll时返回的为nil,表示并不支持这种配置 241 | var isInfiniteStickToContent: Bool { 242 | get { 243 | return self.infiniteScroller?.stickToContent ?? false 244 | } 245 | set { 246 | self.infiniteScroller?.stickToContent = newValue 247 | } 248 | } 249 | var isInfiniteScrollEnabled: Bool { 250 | get { 251 | return infiniteScroller?.enable ?? false 252 | } 253 | set { 254 | infiniteScroller?.enable = newValue 255 | } 256 | } 257 | } 258 | 259 | private var associatedSupportSpringBouncesKey:String = "InfinitySupportSpringBouncesKey" 260 | private var associatedLockInsetKey: String = "InfinityLockInsetKey" 261 | 262 | extension UIScrollView { 263 | var lockInset: Bool { 264 | get { 265 | let locked = objc_getAssociatedObject(self, &associatedLockInsetKey) as? Bool 266 | if locked == nil { 267 | return false 268 | } 269 | return locked! 270 | } 271 | set { 272 | objc_setAssociatedObject(self, &associatedLockInsetKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 273 | } 274 | } 275 | func setContentInset(_ inset: UIEdgeInsets, completion: ((Bool) -> Void)?) { 276 | UIView.animate(withDuration: 0.3, delay: 0, options: [.allowUserInteraction, .beginFromCurrentState], animations: { () -> Void in 277 | 278 | self.lockInset = true 279 | self.contentInset = inset 280 | self.lockInset = false 281 | 282 | }, completion: { (finished) -> Void in 283 | 284 | completion?(finished) 285 | }) 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /Infinity/controls/arrow/ArrowRefreshAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArrowRefreshAnimator.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/24. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIColor { 12 | static var ArrowBlue: UIColor { 13 | return UIColor(red: 76/255.0, green: 143/255.0, blue: 1.0, alpha: 1.0) 14 | } 15 | static var ArrowLightGray: UIColor { 16 | return UIColor(red: 0.8, green: 0.8, blue: 0.8, alpha: 1.0) 17 | } 18 | } 19 | 20 | open class ArrowRefreshAnimator: UIView, CustomPullToRefreshAnimator { 21 | 22 | fileprivate(set) var animating = false 23 | open var color: UIColor = UIColor.ArrowBlue { 24 | didSet { 25 | arrowLayer.strokeColor = color.cgColor 26 | circleFrontLayer.strokeColor = color.cgColor 27 | activityIndicatorView.color = color 28 | } 29 | } 30 | 31 | fileprivate var arrowLayer:CAShapeLayer = CAShapeLayer() 32 | fileprivate var circleFrontLayer: CAShapeLayer = CAShapeLayer() 33 | fileprivate var circleBackLayer: CAShapeLayer = CAShapeLayer() 34 | 35 | fileprivate var activityIndicatorView: UIActivityIndicatorView = UIActivityIndicatorView(style: .gray) 36 | 37 | public override init(frame: CGRect) { 38 | super.init(frame: frame) 39 | 40 | circleBackLayer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: frame.width, height: frame.height)).cgPath 41 | circleBackLayer.fillColor = nil 42 | circleBackLayer.strokeColor = UIColor.ArrowLightGray.cgColor 43 | circleBackLayer.lineWidth = 3 44 | 45 | circleFrontLayer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: frame.width, height: frame.height)).cgPath 46 | circleFrontLayer.fillColor = nil 47 | circleFrontLayer.strokeColor = color.cgColor 48 | circleFrontLayer.lineWidth = 3 49 | circleFrontLayer.lineCap = CAShapeLayerLineCap.round 50 | circleFrontLayer.strokeStart = 0 51 | circleFrontLayer.strokeEnd = 0 52 | circleFrontLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransform(rotationAngle: -CGFloat.pi/2)) 53 | 54 | let arrowWidth = min(frame.width, frame.height) / 2 55 | let arrowHeight = arrowWidth * 0.5 56 | 57 | let arrowPath = UIBezierPath() 58 | arrowPath.move(to: CGPoint(x: 0, y: arrowHeight)) 59 | arrowPath.addLine(to: CGPoint(x: arrowWidth / 2, y: 0)) 60 | arrowPath.addLine(to: CGPoint(x: arrowWidth, y: arrowHeight)) 61 | 62 | arrowLayer.path = arrowPath.cgPath 63 | arrowLayer.fillColor = nil 64 | arrowLayer.strokeColor = color.cgColor 65 | arrowLayer.lineWidth = 3 66 | arrowLayer.lineJoin = CAShapeLayerLineJoin.round 67 | arrowLayer.lineCap = CAShapeLayerLineCap.butt 68 | 69 | circleBackLayer.frame = self.bounds 70 | circleFrontLayer.frame = self.bounds 71 | arrowLayer.frame = CGRect(x: (frame.width - arrowWidth)/2, y: (frame.height - arrowHeight)/2, width: arrowWidth, height: arrowHeight) 72 | 73 | activityIndicatorView.frame = self.bounds 74 | activityIndicatorView.hidesWhenStopped = true 75 | activityIndicatorView.color = UIColor.ArrowBlue 76 | 77 | self.layer.addSublayer(circleBackLayer) 78 | self.layer.addSublayer(circleFrontLayer) 79 | self.layer.addSublayer(arrowLayer) 80 | self.addSubview(activityIndicatorView) 81 | 82 | } 83 | public required init?(coder aDecoder: NSCoder) { 84 | fatalError("init(coder:) has not been implemented") 85 | } 86 | open func animateState(_ state: PullToRefreshState) { 87 | switch state { 88 | case .none: 89 | stopAnimating() 90 | case .releasing(let progress): 91 | updateForProgress(progress) 92 | case .loading: 93 | startAnimating() 94 | } 95 | } 96 | func updateForProgress(_ progress: CGFloat) { 97 | CATransaction.begin() 98 | CATransaction.setDisableActions(true) 99 | circleFrontLayer.strokeEnd = progress * progress 100 | arrowLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransform(rotationAngle: CGFloat.pi * 2 * progress * progress)) 101 | CATransaction.commit() 102 | } 103 | func startAnimating() { 104 | animating = true 105 | circleFrontLayer.strokeEnd = 0 106 | arrowLayer.transform = CATransform3DIdentity 107 | 108 | circleBackLayer.isHidden = true 109 | circleFrontLayer.isHidden = true 110 | arrowLayer.isHidden = true 111 | 112 | activityIndicatorView.startAnimating() 113 | } 114 | func stopAnimating() { 115 | animating = false 116 | 117 | circleBackLayer.isHidden = false 118 | circleFrontLayer.isHidden = false 119 | arrowLayer.isHidden = false 120 | 121 | activityIndicatorView.stopAnimating() 122 | } 123 | 124 | /* 125 | // Only override drawRect: if you perform custom drawing. 126 | // An empty implementation adversely affects performance during animation. 127 | override func drawRect(rect: CGRect) { 128 | // Drawing code 129 | } 130 | */ 131 | 132 | } 133 | -------------------------------------------------------------------------------- /Infinity/controls/circle/CircleInfinityAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CircleInfiniteAnimator.swift 3 | // InfiniteSample 4 | // 5 | // Created by Danis on 15/12/23. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class CircleInfiniteAnimator: UIView, CustomInfiniteScrollAnimator { 12 | 13 | var circle: CAShapeLayer = CAShapeLayer() 14 | fileprivate(set) var animating = false 15 | 16 | public override init(frame: CGRect) { 17 | super.init(frame: frame) 18 | 19 | 20 | circle.fillColor = UIColor.darkGray.cgColor 21 | circle.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: frame.width, height: frame.height)).cgPath 22 | circle.transform = CATransform3DMakeScale(0, 0, 0) 23 | 24 | self.layer.addSublayer(circle) 25 | } 26 | required public init?(coder aDecoder: NSCoder) { 27 | fatalError("init(coder:) has not been implemented") 28 | } 29 | override open func layoutSubviews() { 30 | super.layoutSubviews() 31 | 32 | circle.frame = self.bounds 33 | } 34 | override open func didMoveToWindow() { 35 | super.didMoveToWindow() 36 | 37 | if window != nil && animating { 38 | startAnimating() 39 | } 40 | } 41 | 42 | open func animateState(_ state: InfiniteScrollState) { 43 | switch state { 44 | case .none: 45 | stopAnimating() 46 | case .loading: 47 | startAnimating() 48 | } 49 | } 50 | 51 | fileprivate let CircleAnimationKey = "CircleAnimationKey" 52 | func startAnimating() { 53 | animating = true 54 | 55 | let scaleAnim = CABasicAnimation(keyPath: "transform.scale") 56 | let opacityAnim = CABasicAnimation(keyPath: "opacity") 57 | let animGroup = CAAnimationGroup() 58 | 59 | scaleAnim.fromValue = 0 60 | scaleAnim.toValue = 1.0 61 | scaleAnim.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) 62 | 63 | opacityAnim.fromValue = 1 64 | opacityAnim.toValue = 0 65 | opacityAnim.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) 66 | 67 | animGroup.duration = 1.0 68 | animGroup.repeatCount = 1000 69 | animGroup.animations = [scaleAnim,opacityAnim] 70 | animGroup.isRemovedOnCompletion = false 71 | animGroup.fillMode = CAMediaTimingFillMode.forwards 72 | 73 | self.circle.add(animGroup, forKey: CircleAnimationKey) 74 | } 75 | func stopAnimating() { 76 | animating = false 77 | 78 | self.circle.removeAnimation(forKey: CircleAnimationKey) 79 | self.circle.transform = CATransform3DMakeScale(0, 0, 0) 80 | self.circle.opacity = 1.0 81 | } 82 | /* 83 | // Only override drawRect: if you perform custom drawing. 84 | // An empty implementation adversely affects performance during animation. 85 | override func drawRect(rect: CGRect) { 86 | // Drawing code 87 | } 88 | */ 89 | 90 | } 91 | -------------------------------------------------------------------------------- /Infinity/controls/circle/CircleRefreshAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CircleRefreshAnimator.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/23. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class CircleRefreshAnimator: UIView, CustomPullToRefreshAnimator { 12 | 13 | var circle = CAShapeLayer() 14 | fileprivate(set) var animating = false 15 | 16 | public override init(frame: CGRect) { 17 | super.init(frame: frame) 18 | 19 | circle.fillColor = UIColor.darkGray.cgColor 20 | circle.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: frame.width, height: frame.height)).cgPath 21 | circle.transform = CATransform3DMakeScale(0, 0, 0) 22 | 23 | self.layer.addSublayer(circle) 24 | } 25 | 26 | required public init?(coder aDecoder: NSCoder) { 27 | fatalError("init(coder:) has not been implemented") 28 | } 29 | 30 | override open func layoutSubviews() { 31 | super.layoutSubviews() 32 | 33 | circle.frame = self.bounds 34 | } 35 | override open func didMoveToWindow() { 36 | super.didMoveToWindow() 37 | 38 | if window != nil && animating { 39 | startAnimating() 40 | } 41 | } 42 | open func animateState(_ state: PullToRefreshState) { 43 | switch state { 44 | case .none: 45 | stopAnimating() 46 | case .releasing(let progress): 47 | updateCircle(progress) 48 | case .loading: 49 | startAnimating() 50 | } 51 | } 52 | func updateCircle(_ progress: CGFloat) { 53 | circle.transform = CATransform3DMakeScale(progress, progress, progress) 54 | } 55 | 56 | fileprivate let CircleAnimationKey = "CircleAnimationKey" 57 | func startAnimating() { 58 | animating = true 59 | 60 | let scaleAnim = CABasicAnimation(keyPath: "transform.scale") 61 | let opacityAnim = CABasicAnimation(keyPath: "opacity") 62 | let animGroup = CAAnimationGroup() 63 | 64 | scaleAnim.fromValue = 0 65 | scaleAnim.toValue = 1.0 66 | scaleAnim.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) 67 | 68 | opacityAnim.fromValue = 1 69 | opacityAnim.toValue = 0 70 | opacityAnim.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) 71 | 72 | animGroup.duration = 1.0 73 | animGroup.repeatCount = 1000 74 | animGroup.animations = [scaleAnim,opacityAnim] 75 | animGroup.isRemovedOnCompletion = false 76 | animGroup.fillMode = CAMediaTimingFillMode.forwards 77 | 78 | self.circle.add(animGroup, forKey: CircleAnimationKey) 79 | } 80 | func stopAnimating() { 81 | animating = false 82 | 83 | self.circle.removeAnimation(forKey: CircleAnimationKey) 84 | self.circle.transform = CATransform3DMakeScale(0, 0, 0) 85 | self.circle.opacity = 1.0 86 | } 87 | 88 | /* 89 | // Only override drawRect: if you perform custom drawing. 90 | // An empty implementation adversely affects performance during animation. 91 | override func drawRect(rect: CGRect) { 92 | // Drawing code 93 | } 94 | */ 95 | 96 | } 97 | -------------------------------------------------------------------------------- /Infinity/controls/default/DefaultInfinityAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultInfinityAnimator.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/23. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class DefaultInfiniteAnimator: UIView, CustomInfiniteScrollAnimator { 12 | 13 | open var activityIndicatorView: UIActivityIndicatorView 14 | open fileprivate(set) var animating: Bool = false 15 | 16 | public override init(frame: CGRect) { 17 | activityIndicatorView = UIActivityIndicatorView(style: .gray) 18 | activityIndicatorView.hidesWhenStopped = true 19 | activityIndicatorView.isHidden = true 20 | 21 | super.init(frame: frame) 22 | 23 | self.addSubview(activityIndicatorView) 24 | } 25 | public required init?(coder aDecoder: NSCoder) { 26 | fatalError("init(coder:) has not been implemented") 27 | } 28 | open override func layoutSubviews() { 29 | super.layoutSubviews() 30 | 31 | activityIndicatorView.frame = self.bounds 32 | } 33 | open override func didMoveToWindow() { 34 | if window != nil && animating { 35 | startAnimating() 36 | } 37 | } 38 | open func animateState(_ state: InfiniteScrollState) { 39 | if Infinity.debugModeEnabled { 40 | print(state) 41 | } 42 | switch state { 43 | case .none: 44 | stopAnimating() 45 | case .loading: 46 | startAnimating() 47 | } 48 | } 49 | func startAnimating() { 50 | animating = true 51 | 52 | activityIndicatorView.startAnimating() 53 | activityIndicatorView.isHidden = false 54 | } 55 | func stopAnimating() { 56 | animating = false 57 | 58 | activityIndicatorView.stopAnimating() 59 | activityIndicatorView.isHidden = true 60 | } 61 | /* 62 | // Only override drawRect: if you perform custom drawing. 63 | // An empty implementation adversely affects performance during animation. 64 | override func drawRect(rect: CGRect) { 65 | // Drawing code 66 | } 67 | */ 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Infinity/controls/default/DefaultRefreshAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultRefreshAnimator.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/23. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class DefaultRefreshAnimator: UIView, CustomPullToRefreshAnimator { 12 | 13 | open var activityIndicatorView: UIActivityIndicatorView = UIActivityIndicatorView(style: .gray) 14 | open var circleLayer: CAShapeLayer = CAShapeLayer() 15 | 16 | public override init(frame: CGRect) { 17 | super.init(frame: frame) 18 | 19 | activityIndicatorView.isHidden = true 20 | activityIndicatorView.hidesWhenStopped = true 21 | 22 | circleLayer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: frame.width, height: frame.height)).cgPath 23 | circleLayer.strokeColor = UIColor.gray.cgColor 24 | circleLayer.fillColor = UIColor.clear.cgColor 25 | circleLayer.lineWidth = 3 26 | circleLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransform(rotationAngle: -CGFloat.pi/2)) 27 | circleLayer.strokeStart = 0 28 | circleLayer.strokeEnd = 0 29 | 30 | self.addSubview(activityIndicatorView) 31 | self.layer.addSublayer(circleLayer) 32 | } 33 | public required init?(coder aDecoder: NSCoder) { 34 | fatalError("init(coder:) has not been implemented") 35 | } 36 | open override func layoutSubviews() { 37 | super.layoutSubviews() 38 | 39 | activityIndicatorView.frame = self.bounds 40 | circleLayer.frame = self.bounds 41 | } 42 | open func animateState(_ state: PullToRefreshState) { 43 | switch state { 44 | case .none: 45 | stopAnimating() 46 | case .releasing(let progress): 47 | self.updateCircle(progress) 48 | case .loading: 49 | startAnimating() 50 | } 51 | } 52 | func startAnimating() { 53 | circleLayer.isHidden = true 54 | circleLayer.strokeEnd = 0 55 | 56 | activityIndicatorView.isHidden = false 57 | activityIndicatorView.startAnimating() 58 | } 59 | func stopAnimating() { 60 | circleLayer.isHidden = false 61 | 62 | activityIndicatorView.isHidden = true 63 | activityIndicatorView.stopAnimating() 64 | } 65 | 66 | func updateCircle(_ progress: CGFloat) { 67 | CATransaction.begin() 68 | CATransaction.setDisableActions(true) 69 | circleLayer.strokeStart = 0 70 | // 为了让circle增长速度在开始时比较慢,后来加快,这样更好看 71 | circleLayer.strokeEnd = progress * progress 72 | CATransaction.commit() 73 | } 74 | /* 75 | // Only override drawRect: if you perform custom drawing. 76 | // An empty implementation adversely affects performance during animation. 77 | override func drawRect(rect: CGRect) { 78 | // Drawing code 79 | } 80 | */ 81 | 82 | } 83 | -------------------------------------------------------------------------------- /Infinity/controls/gif/GIFInfinityAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GIFInfinityAnimator.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/23. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class GIFInfiniteAnimator: UIView, CustomInfiniteScrollAnimator { 12 | 13 | open var animatedImages = [UIImage]() 14 | 15 | var imageView: UIImageView = UIImageView() 16 | 17 | public override init(frame: CGRect) { 18 | super.init(frame: frame) 19 | 20 | imageView.frame = self.bounds 21 | self.addSubview(imageView) 22 | } 23 | public required init?(coder aDecoder: NSCoder) { 24 | fatalError("init(coder:) has not been implemented") 25 | } 26 | 27 | open func animateState(_ state: InfiniteScrollState) { 28 | switch state { 29 | case .loading: 30 | startAnimating() 31 | case .none: 32 | stopAnimating() 33 | } 34 | } 35 | func startAnimating() { 36 | imageView.animationImages = animatedImages 37 | imageView.isHidden = false 38 | imageView.startAnimating() 39 | } 40 | func stopAnimating() { 41 | imageView.isHidden = true 42 | imageView.stopAnimating() 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Infinity/controls/gif/GIFRefreshAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GIFRefreshAnimator.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/23. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class GIFRefreshAnimator: UIView, CustomPullToRefreshAnimator { 12 | 13 | open var refreshImages = [UIImage]() 14 | open var animatedImages = [UIImage]() 15 | 16 | fileprivate var imageView:UIImageView = UIImageView() 17 | 18 | public override init(frame: CGRect) { 19 | super.init(frame: frame) 20 | 21 | imageView.frame = self.bounds 22 | 23 | self.addSubview(imageView) 24 | } 25 | public required init?(coder aDecoder: NSCoder) { 26 | fatalError("init(coder:) has not been implemented") 27 | } 28 | 29 | open func animateState(_ state: PullToRefreshState) { 30 | switch state { 31 | case .none: 32 | stopAnimating() 33 | case .releasing(let progress): 34 | updateForProgress(progress) 35 | case .loading: 36 | startAnimating() 37 | } 38 | } 39 | func updateForProgress(_ progress: CGFloat) { 40 | if refreshImages.count > 0 { 41 | let currentIndex = min(Int(progress * CGFloat(refreshImages.count)), refreshImages.count - 1) 42 | imageView.image = refreshImages[currentIndex] 43 | } 44 | } 45 | func startAnimating() { 46 | imageView.animationImages = animatedImages 47 | imageView.startAnimating() 48 | } 49 | func stopAnimating() { 50 | imageView.stopAnimating() 51 | imageView.image = refreshImages.first 52 | } 53 | /* 54 | // Only override drawRect: if you perform custom drawing. 55 | // An empty implementation adversely affects performance during animation. 56 | override func drawRect(rect: CGRect) { 57 | // Drawing code 58 | } 59 | */ 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Infinity/controls/normal/NormalInfinityAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NormalInfinityAnimator.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/23. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NormalInfinityAnimator: UIView { 12 | 13 | /* 14 | // Only override drawRect: if you perform custom drawing. 15 | // An empty implementation adversely affects performance during animation. 16 | override func drawRect(rect: CGRect) { 17 | // Drawing code 18 | } 19 | */ 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Infinity/controls/normal/NormalRefreshAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NormalRefreshAnimator.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/23. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NormalRefreshAnimator: UIView { 12 | 13 | /* 14 | // Only override drawRect: if you perform custom drawing. 15 | // An empty implementation adversely affects performance during animation. 16 | override func drawRect(rect: CGRect) { 17 | // Drawing code 18 | } 19 | */ 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Infinity/controls/snake/SnakeInfinityAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnakeInfiniteAnimator.swift 3 | // InfiniteSample 4 | // 5 | // Created by Danis on 15/12/26. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIColor { 12 | static var SnakeBlue: UIColor { 13 | return UIColor(red: 76/255.0, green: 143/255.0, blue: 1.0, alpha: 1.0) 14 | } 15 | } 16 | 17 | open class SnakeInfiniteAnimator: UIView, CustomInfiniteScrollAnimator { 18 | 19 | open var color: UIColor = UIColor.SnakeBlue { 20 | didSet { 21 | snakeLayer.strokeColor = color.cgColor 22 | } 23 | } 24 | var animating = false 25 | 26 | fileprivate var snakeLayer = CAShapeLayer() 27 | fileprivate var snakeLengthByCycle:CGFloat = 0 // 占的周期数 28 | fileprivate var cycleCount = 1000 29 | 30 | fileprivate var pathLength:CGFloat = 0 31 | 32 | public override init(frame: CGRect) { 33 | super.init(frame: frame) 34 | 35 | let ovalDiametor = frame.width / 4 36 | let lineHeight = frame.height - ovalDiametor 37 | 38 | snakeLengthByCycle = 2 - (ovalDiametor/2 * CGFloat.pi) / ((lineHeight + ovalDiametor/2 * CGFloat.pi) * 2) 39 | pathLength = ovalDiametor * 2 * CGFloat(cycleCount) 40 | 41 | let snakePath = UIBezierPath() 42 | snakePath.move(to: CGPoint(x: 0, y: frame.height - ovalDiametor/2)) 43 | for index in 0...cycleCount { 44 | let cycleStartX = CGFloat(index) * ovalDiametor * 2 45 | snakePath.addLine(to: CGPoint(x: cycleStartX, y: ovalDiametor / 2)) 46 | snakePath.addArc(withCenter: CGPoint(x: cycleStartX + ovalDiametor / 2, y: ovalDiametor / 2), radius: ovalDiametor / 2, startAngle: CGFloat.pi, endAngle: 0, clockwise: true) 47 | snakePath.addLine(to: CGPoint(x: cycleStartX + ovalDiametor, y: frame.height - ovalDiametor / 2)) 48 | snakePath.addArc(withCenter: CGPoint(x: cycleStartX + ovalDiametor / 2 * 3, y: frame.height - ovalDiametor/2), radius: ovalDiametor/2, startAngle: CGFloat.pi, endAngle: 0, clockwise: false) 49 | } 50 | snakeLayer.path = snakePath.cgPath 51 | snakeLayer.fillColor = nil 52 | snakeLayer.strokeColor = color.cgColor 53 | snakeLayer.strokeStart = 0 54 | snakeLayer.strokeEnd = snakeLengthByCycle / CGFloat(cycleCount) 55 | snakeLayer.lineWidth = 3 56 | snakeLayer.lineCap = CAShapeLayerLineCap.round 57 | 58 | snakeLayer.frame = self.bounds 59 | self.layer.addSublayer(snakeLayer) 60 | } 61 | required public init?(coder aDecoder: NSCoder) { 62 | fatalError("init(coder:) has not been implemented") 63 | } 64 | override open func didMoveToWindow() { 65 | super.didMoveToWindow() 66 | 67 | if window != nil && animating { 68 | startAnimating() 69 | } 70 | } 71 | 72 | open func animateState(_ state: InfiniteScrollState) { 73 | switch state { 74 | case .none: 75 | stopAnimating() 76 | case .loading: 77 | startAnimating() 78 | } 79 | } 80 | 81 | fileprivate let AnimationGroupKey = "SnakePathAnimations" 82 | func startAnimating() { 83 | animating = true 84 | snakeLayer.isHidden = false 85 | 86 | snakeLayer.strokeStart = 0 87 | snakeLayer.strokeEnd = snakeLengthByCycle / CGFloat(cycleCount) 88 | 89 | let strokeStartAnim = CABasicAnimation(keyPath: "strokeStart") 90 | let strokeEndAnim = CABasicAnimation(keyPath: "strokeEnd") 91 | let moveAnim = CABasicAnimation(keyPath: "position") 92 | 93 | strokeStartAnim.toValue = 1 - snakeLengthByCycle/CGFloat(cycleCount) 94 | strokeEndAnim.toValue = 1 95 | moveAnim.toValue = NSValue(cgPoint: CGPoint(x: snakeLayer.position.x - pathLength, y: snakeLayer.position.y)) 96 | 97 | 98 | let animGroup = CAAnimationGroup() 99 | animGroup.animations = [strokeStartAnim,strokeEndAnim,moveAnim] 100 | animGroup.duration = Double(cycleCount) * 0.6 101 | 102 | snakeLayer.add(animGroup, forKey: AnimationGroupKey) 103 | 104 | } 105 | func stopAnimating() { 106 | animating = false 107 | snakeLayer.isHidden = true 108 | 109 | snakeLayer.removeAnimation(forKey: AnimationGroupKey) 110 | 111 | } 112 | /* 113 | // Only override drawRect: if you perform custom drawing. 114 | // An empty implementation adversely affects performance during animation. 115 | override func drawRect(rect: CGRect) { 116 | // Drawing code 117 | } 118 | */ 119 | 120 | } 121 | -------------------------------------------------------------------------------- /Infinity/controls/snake/SnakeRefreshAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnakeRefreshAnimator.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/26. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class SnakeRefreshAnimator: UIView, CustomPullToRefreshAnimator { 12 | 13 | open var color: UIColor = UIColor.SnakeBlue { 14 | didSet { 15 | snakeLayer.strokeColor = color.cgColor 16 | } 17 | } 18 | var animating = false 19 | 20 | fileprivate var snakeLayer = CAShapeLayer() 21 | fileprivate var snakeLengthByCycle:CGFloat = 0 // 显示的长度所占周期数 22 | fileprivate var cycleCount = 1000 23 | 24 | fileprivate var pathLength:CGFloat = 0 25 | 26 | public override init(frame: CGRect) { 27 | super.init(frame: frame) 28 | 29 | let ovalDiametor = frame.width / 4 30 | let lineHeight = frame.height - ovalDiametor 31 | 32 | snakeLengthByCycle = 2 - (ovalDiametor/2 * CGFloat.pi) / ((lineHeight + ovalDiametor/2 * CGFloat.pi) * 2) 33 | pathLength = ovalDiametor * 2 * CGFloat(cycleCount) 34 | 35 | let snakePath = UIBezierPath() 36 | snakePath.move(to: CGPoint(x: 0, y: frame.height - ovalDiametor/2)) 37 | for index in 0...cycleCount { 38 | let cycleStartX = CGFloat(index) * ovalDiametor * 2 39 | snakePath.addLine(to: CGPoint(x: cycleStartX, y: ovalDiametor / 2)) 40 | snakePath.addArc(withCenter: CGPoint(x: cycleStartX + ovalDiametor / 2, y: ovalDiametor / 2), radius: ovalDiametor / 2, startAngle: CGFloat.pi, endAngle: 0, clockwise: true) 41 | snakePath.addLine(to: CGPoint(x: cycleStartX + ovalDiametor, y: frame.height - ovalDiametor / 2)) 42 | snakePath.addArc(withCenter: CGPoint(x: cycleStartX + ovalDiametor / 2 * 3, y: frame.height - ovalDiametor/2), radius: ovalDiametor/2, startAngle: CGFloat.pi, endAngle: 0, clockwise: false) 43 | } 44 | snakeLayer.path = snakePath.cgPath 45 | snakeLayer.fillColor = nil 46 | snakeLayer.strokeColor = color.cgColor 47 | snakeLayer.strokeStart = 0 48 | snakeLayer.strokeEnd = snakeLengthByCycle / CGFloat(cycleCount) 49 | snakeLayer.lineWidth = 3 50 | snakeLayer.lineCap = CAShapeLayerLineCap.round 51 | 52 | snakeLayer.frame = self.bounds 53 | self.layer.addSublayer(snakeLayer) 54 | } 55 | required public init?(coder aDecoder: NSCoder) { 56 | fatalError("init(coder:) has not been implemented") 57 | } 58 | open override func didMoveToWindow() { 59 | super.didMoveToWindow() 60 | 61 | if window != nil && animating { 62 | startAnimating() 63 | } 64 | } 65 | open func animateState(_ state: PullToRefreshState) { 66 | switch state { 67 | case .none: 68 | stopAnimating() 69 | case .loading: 70 | startAnimating() 71 | case .releasing(let progress): 72 | updateForProgress(progress) 73 | } 74 | } 75 | func updateForProgress(_ progress: CGFloat) { 76 | snakeLayer.isHidden = false 77 | 78 | CATransaction.begin() 79 | CATransaction.setDisableActions(true) 80 | snakeLayer.strokeStart = 0 81 | snakeLayer.strokeEnd = snakeLengthByCycle / CGFloat(cycleCount) * progress 82 | CATransaction.commit() 83 | } 84 | 85 | fileprivate let AnimationGroupKey = "SnakePathAnimations" 86 | func startAnimating() { 87 | animating = true 88 | snakeLayer.isHidden = false 89 | 90 | snakeLayer.strokeStart = 0 91 | snakeLayer.strokeEnd = snakeLengthByCycle / CGFloat(cycleCount) 92 | 93 | let strokeStartAnim = CABasicAnimation(keyPath: "strokeStart") 94 | let strokeEndAnim = CABasicAnimation(keyPath: "strokeEnd") 95 | let moveAnim = CABasicAnimation(keyPath: "position") 96 | 97 | strokeStartAnim.toValue = 1 - snakeLengthByCycle/CGFloat(cycleCount) 98 | strokeEndAnim.toValue = 1 99 | moveAnim.toValue = NSValue(cgPoint: CGPoint(x: snakeLayer.position.x - pathLength, y: snakeLayer.position.y)) 100 | 101 | 102 | let animGroup = CAAnimationGroup() 103 | animGroup.animations = [strokeStartAnim,strokeEndAnim,moveAnim] 104 | animGroup.duration = Double(cycleCount) * 0.6 105 | 106 | snakeLayer.add(animGroup, forKey: AnimationGroupKey) 107 | 108 | } 109 | func stopAnimating() { 110 | animating = false 111 | 112 | snakeLayer.isHidden = true 113 | snakeLayer.removeAnimation(forKey: AnimationGroupKey) 114 | } 115 | /* 116 | // Only override drawRect: if you perform custom drawing. 117 | // An empty implementation adversely affects performance during animation. 118 | override func drawRect(rect: CGRect) { 119 | // Drawing code 120 | } 121 | */ 122 | 123 | } 124 | -------------------------------------------------------------------------------- /Infinity/controls/spark/SparkInfinityAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SparkInfiniteAnimator.swift 3 | // InfiniteSample 4 | // 5 | // Created by Danis on 16/1/2. 6 | // Copyright © 2016年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class SparkInfiniteAnimator: UIView, CustomInfiniteScrollAnimator { 12 | 13 | fileprivate var circles = [CAShapeLayer]() 14 | var animating = false 15 | 16 | fileprivate var positions = [CGPoint]() 17 | 18 | public override init(frame: CGRect) { 19 | super.init(frame: frame) 20 | 21 | let ovalDiameter = min(frame.width,frame.height) / 8 22 | let ovalPath = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: ovalDiameter, height: ovalDiameter)) 23 | 24 | let count = 8 25 | for index in 0..> 16) / 255.0 14 | let green = CGFloat((hex & 0xFF00) >> 8) / 255.0 15 | let blue = CGFloat(hex & 0xFF) / 255.0 16 | 17 | self.init(red: red, green: green, blue: blue, alpha: alpha) 18 | } 19 | convenience init(hex: Int) { 20 | self.init(hex:hex, alpha:1.0) 21 | } 22 | 23 | static func sparkColorWithIndex(_ index: Int) -> UIColor { 24 | switch index % 8 { 25 | case 0: 26 | return UIColor(hex: 0xf9b60f) 27 | case 1: 28 | return UIColor(hex: 0xf78a44) 29 | case 2: 30 | return UIColor(hex: 0xf05e4d) 31 | case 3: 32 | return UIColor(hex: 0xf75078) 33 | case 4: 34 | return UIColor(hex: 0xc973e4) 35 | case 5: 36 | return UIColor(hex: 0x1bbef1) 37 | case 6: 38 | return UIColor(hex: 0x5593f0) 39 | case 7: 40 | return UIColor(hex: 0x00cf98) 41 | default: 42 | return UIColor.clear 43 | } 44 | } 45 | } 46 | 47 | open class SparkRefreshAnimator: UIView, CustomPullToRefreshAnimator { 48 | 49 | fileprivate var circles = [CAShapeLayer]() 50 | var animating = false 51 | 52 | fileprivate var positions = [CGPoint]() 53 | 54 | public override init(frame: CGRect) { 55 | super.init(frame: frame) 56 | 57 | let ovalDiameter = min(frame.width,frame.height) / 8 58 | let ovalPath = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: ovalDiameter, height: ovalDiameter)) 59 | 60 | let count = 8 61 | for index in 0.. 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /InfinitySample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /InfinitySample.xcodeproj/project.xcworkspace/xcuserdata/danis.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample.xcodeproj/project.xcworkspace/xcuserdata/danis.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /InfinitySample.xcodeproj/project.xcworkspace/xcuserdata/liaolei.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample.xcodeproj/project.xcworkspace/xcuserdata/liaolei.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /InfinitySample.xcodeproj/xcshareddata/xcschemes/Infinity.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /InfinitySample.xcodeproj/xcuserdata/danis.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /InfinitySample.xcodeproj/xcuserdata/danis.xcuserdatad/xcschemes/InfinitySample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /InfinitySample.xcodeproj/xcuserdata/danis.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Infinity.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 1 11 | 12 | InfinitySample.xcscheme 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 12EFE0E11C27BD5800242079 21 | 22 | primary 23 | 24 | 25 | 12EFE0F51C27BD5900242079 26 | 27 | primary 28 | 29 | 30 | 12EFE1091C27BD6A00242079 31 | 32 | primary 33 | 34 | 35 | 12EFE1121C27BD6A00242079 36 | 37 | primary 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /InfinitySample.xcodeproj/xcuserdata/liaolei.xcuserdatad/xcschemes/InfinitySample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /InfinitySample.xcodeproj/xcuserdata/liaolei.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Infinity.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | InfinitySample.xcscheme 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 12EFE0E11C27BD5800242079 21 | 22 | primary 23 | 24 | 25 | 12EFE0F51C27BD5900242079 26 | 27 | primary 28 | 29 | 30 | 12EFE1091C27BD6A00242079 31 | 32 | primary 33 | 34 | 35 | 12EFE1121C27BD6A00242079 36 | 37 | primary 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /InfinitySample/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/.DS_Store -------------------------------------------------------------------------------- /InfinitySample/AddSamplesTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SamplesTableViewController.swift 3 | // InfiniteSample 4 | // 5 | // Created by Danis on 15/12/22. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Infinity 11 | 12 | class AddSamplesTableViewController: UITableViewController { 13 | 14 | var type:AnimatorType = .Default 15 | var items = 5 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | edgesForExtendedLayout = [] 20 | navigationItem.rightBarButtonItem = UIBarButtonItem(title: "refresh", style: .plain, target: self, action: #selector(startRefreshing(sender:))) 21 | 22 | view.backgroundColor = .white 23 | title = type.description 24 | 25 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: "SampleCell") 26 | 27 | addPullToRefresh(type: type) 28 | addInfiniteScroll(type: type) 29 | 30 | // tableView.isPullToRefreshEnabled = false 31 | // tableView.isInfiniteScrollEnabled = false 32 | } 33 | 34 | deinit { 35 | tableView.fty.clear() 36 | } 37 | 38 | 39 | @objc func startRefreshing(sender: AnyObject) { 40 | tableView.fty.pullToRefresh.begin() 41 | } 42 | 43 | // MARK: - Add PullToRefresh 44 | func addPullToRefresh(type: AnimatorType) { 45 | switch type { 46 | case .Default: 47 | let animator = DefaultRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 48 | addPullToRefreshWithAnimator(animator: animator) 49 | case .GIF: 50 | let animator = GIFRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 51 | // Add Images for Animator 52 | var refreshImages = [UIImage]() 53 | for index in 0..<22 { 54 | let image = UIImage(named: "hud_\(index)") 55 | if let image = image { 56 | refreshImages.append(image) 57 | } 58 | } 59 | var animatedImages = [UIImage]() 60 | for index in 21..<30 { 61 | let image = UIImage(named: "hud_\(index)") 62 | if let image = image { 63 | animatedImages.append(image) 64 | } 65 | } 66 | for index in 0..<22 { 67 | let image = UIImage(named: "hud_\(index)") 68 | if let image = image { 69 | animatedImages.append(image) 70 | } 71 | } 72 | animator.refreshImages = refreshImages 73 | animator.animatedImages = animatedImages 74 | addPullToRefreshWithAnimator(animator: animator) 75 | case .Circle: 76 | let animator = CircleRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 77 | addPullToRefreshWithAnimator(animator: animator) 78 | case .Arrow: 79 | let animator = ArrowRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 80 | animator.color = .red 81 | addPullToRefreshWithAnimator(animator: animator) 82 | case .Snake: 83 | let animator = SnakeRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 30, height: 18)) 84 | addPullToRefreshWithAnimator(animator: animator) 85 | case .Spark: 86 | let animator = SparkRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 40, height: 40)) 87 | addPullToRefreshWithAnimator(animator: animator) 88 | } 89 | } 90 | func addPullToRefreshWithAnimator(animator: CustomPullToRefreshAnimator) { 91 | tableView.fty.pullToRefresh.add(animator: animator) { 92 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [unowned self] in 93 | print("end refreshing") 94 | 95 | self.items += 3 96 | self.tableView.reloadData() 97 | self.tableView.fty.pullToRefresh.end() 98 | 99 | if self.items < 12 { 100 | self.tableView.fty.infiniteScroll.isEnabled = false 101 | } else { 102 | self.tableView.fty.infiniteScroll.isEnabled = true 103 | } 104 | } 105 | } 106 | // tableView.fty.pullToRefresh.animatorOffset = UIOffset(horizontal: 100, vertical: 0) 107 | } 108 | // MARK: - Add InfiniteScroll 109 | func addInfiniteScroll(type: AnimatorType) { 110 | switch type { 111 | case .Default: 112 | let animator = DefaultInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) 113 | addInfiniteScrollWithAnimator(animator: animator) 114 | case .GIF: 115 | let animator = GIFInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 116 | var animatedImages = [UIImage]() 117 | for index in 0..<30 { 118 | let image = UIImage(named: "hud_\(index)") 119 | if let image = image { 120 | animatedImages.append(image) 121 | } 122 | } 123 | animator.animatedImages = animatedImages 124 | addInfiniteScrollWithAnimator(animator: animator) 125 | case .Circle: 126 | let animator = CircleInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) 127 | addInfiniteScrollWithAnimator(animator: animator) 128 | case .Snake: 129 | let animator = SnakeInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 30, height: 18)) 130 | addInfiniteScrollWithAnimator(animator: animator) 131 | default: 132 | break 133 | } 134 | } 135 | func addInfiniteScrollWithAnimator(animator: CustomInfiniteScrollAnimator) { 136 | tableView.fty.infiniteScroll.add(animator: animator) { 137 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [unowned self] in 138 | self.items += 15 139 | self.tableView.reloadData() 140 | self.tableView.fty.infiniteScroll.end() 141 | } 142 | } 143 | tableView.fty.infiniteScroll.isEnabled = false 144 | } 145 | 146 | override func didReceiveMemoryWarning() { 147 | super.didReceiveMemoryWarning() 148 | // Dispose of any resources that can be recreated. 149 | } 150 | 151 | // MARK: - Table view data source 152 | 153 | override func numberOfSections(in tableView: UITableView) -> Int { 154 | return 1 155 | } 156 | 157 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 158 | return self.items 159 | } 160 | 161 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 162 | let cell = tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath) 163 | 164 | cell.textLabel?.text = "Cell" 165 | 166 | return cell 167 | } 168 | 169 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 170 | let newVC = UIViewController() 171 | newVC.view.backgroundColor = .red 172 | 173 | show(newVC, sender: self) 174 | } 175 | 176 | /* 177 | // MARK: - Navigation 178 | 179 | // In a storyboard-based application, you will often want to do a little preparation before navigation 180 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 181 | // Get the new view controller using segue.destinationViewController. 182 | // Pass the selected object to the new view controller. 183 | } 184 | */ 185 | 186 | } 187 | -------------------------------------------------------------------------------- /InfinitySample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/21. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Infinity 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | 18 | private func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 19 | Infinity.debugModeEnabled = true 20 | // Override point for customization after application launch. 21 | return true 22 | } 23 | 24 | func applicationWillResignActive(_ application: UIApplication) { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 27 | } 28 | 29 | func applicationDidEnterBackground(_ application: UIApplication) { 30 | // 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. 31 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 32 | } 33 | 34 | func applicationWillEnterForeground(_ application: UIApplication) { 35 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 36 | } 37 | 38 | func applicationDidBecomeActive(_ application: UIApplication) { 39 | // 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. 40 | } 41 | 42 | func applicationWillTerminate(_ application: UIApplication) { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "InfinityIcon-1.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "InfinityIcon.png", 43 | "scale" : "3x" 44 | } 45 | ], 46 | "info" : { 47 | "version" : 1, 48 | "author" : "xcode" 49 | } 50 | } -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/AppIcon.appiconset/InfinityIcon-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/Assets.xcassets/AppIcon.appiconset/InfinityIcon-1.png -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/AppIcon.appiconset/InfinityIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/Assets.xcassets/AppIcon.appiconset/InfinityIcon.png -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/buildings.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "buildings.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/buildings.imageset/buildings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/Assets.xcassets/buildings.imageset/buildings.png -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/parallax-header/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/sky.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "sky.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/sky.imageset/sky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/Assets.xcassets/sky.imageset/sky.png -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/sun.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "sun.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InfinitySample/Assets.xcassets/sun.imageset/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/Assets.xcassets/sun.imageset/sun.png -------------------------------------------------------------------------------- /InfinitySample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /InfinitySample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 54 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 133 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /InfinitySample/BindSamplesTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BindSamplesTableViewController.swift 3 | // InfiniteSample 4 | // 5 | // Created by Danis on 15/12/24. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Infinity 11 | 12 | class BindSamplesTableViewController: UITableViewController { 13 | 14 | var type: BindAnimatorType = .Default 15 | var items = 20 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | edgesForExtendedLayout = [] 20 | view.backgroundColor = .white 21 | title = type.description 22 | 23 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: "SampleCell") 24 | 25 | bindPullToRefresh(type: type) 26 | addInfiniteScroll(type: type) 27 | } 28 | 29 | deinit { 30 | tableView.fty.clear() 31 | } 32 | 33 | // MARK: - Add PullToRefresh 34 | func bindPullToRefresh(type: BindAnimatorType) { 35 | switch type { 36 | case .Default: 37 | let animator = DefaultRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 38 | self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: animator) 39 | bindPullToRefreshWithAnimator(animator: animator) 40 | case .GIF: 41 | let animator = GIFRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 42 | // Add Images for Animator 43 | var refreshImages = [UIImage]() 44 | for index in 0..<21 { 45 | let image = UIImage(named: "hud_\(index)") 46 | if let image = image { 47 | refreshImages.append(image) 48 | } 49 | } 50 | var animatedImages = [UIImage]() 51 | for index in 21...29 { 52 | let image = UIImage(named: "hud_\(index)") 53 | if let image = image { 54 | animatedImages.append(image) 55 | } 56 | } 57 | for index in 0..<21 { 58 | let image = UIImage(named: "hud_\(index)") 59 | if let image = image { 60 | animatedImages.append(image) 61 | } 62 | } 63 | animator.refreshImages = refreshImages 64 | animator.animatedImages = animatedImages 65 | self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: animator) 66 | bindPullToRefreshWithAnimator(animator: animator) 67 | case .Circle: 68 | let animator = CircleRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 69 | self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: animator) 70 | bindPullToRefreshWithAnimator(animator: animator) 71 | case .Arrow: 72 | let animator = ArrowRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 73 | self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: animator) 74 | bindPullToRefreshWithAnimator(animator: animator) 75 | } 76 | } 77 | func bindPullToRefreshWithAnimator(animator: CustomPullToRefreshAnimator) { 78 | tableView.fty.pullToRefresh.bind(animator: animator) { 79 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [unowned self] in 80 | self.tableView.fty.pullToRefresh.end() 81 | } 82 | } 83 | } 84 | // MARK: - Add InfiniteScroll 85 | func addInfiniteScroll(type: BindAnimatorType) { 86 | switch type { 87 | case .Default: 88 | let animator = DefaultInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) 89 | addInfiniteScrollWithAnimator(animator: animator) 90 | case .GIF: 91 | let animator = GIFInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 92 | var animatedImages = [UIImage]() 93 | for index in 0..<29 { 94 | let image = UIImage(named: "hud_\(index)") 95 | if let image = image { 96 | animatedImages.append(image) 97 | } 98 | } 99 | animator.animatedImages = animatedImages 100 | addInfiniteScrollWithAnimator(animator: animator) 101 | case .Circle: 102 | let animator = CircleInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) 103 | addInfiniteScrollWithAnimator(animator: animator) 104 | 105 | default: 106 | break 107 | } 108 | } 109 | func addInfiniteScrollWithAnimator(animator: CustomInfiniteScrollAnimator) { 110 | tableView.fty.infiniteScroll.add(animator: animator) { 111 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [unowned self] in 112 | self.items += 15 113 | self.tableView.reloadData() 114 | self.tableView.fty.infiniteScroll.end() 115 | } 116 | } 117 | } 118 | 119 | override func didReceiveMemoryWarning() { 120 | super.didReceiveMemoryWarning() 121 | // Dispose of any resources that can be recreated. 122 | } 123 | 124 | // MARK: - Table view data source 125 | 126 | override func numberOfSections(in tableView: UITableView) -> Int { 127 | return 1 128 | } 129 | 130 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 131 | return self.items 132 | } 133 | 134 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 135 | let cell = tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath) 136 | 137 | cell.textLabel?.text = "Cell" 138 | 139 | return cell 140 | } 141 | 142 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 143 | let newVC = UIViewController() 144 | newVC.view.backgroundColor = .red 145 | 146 | self.show(newVC, sender: self) 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /InfinitySample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /InfinitySample/Main1TableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Samples1TableViewController.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/22. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum AnimatorType: Int, CustomStringConvertible{ 12 | case Default = 0 13 | case GIF 14 | case Circle 15 | case Arrow 16 | case Snake 17 | case Spark 18 | 19 | var description:String { 20 | switch self { 21 | case .Default: 22 | return "Default" 23 | case .GIF: 24 | return "GIF" 25 | case .Circle: 26 | return "Circle" 27 | case .Arrow: 28 | return "Arrow" 29 | case .Snake: 30 | return "Snake" 31 | case .Spark: 32 | return "Spark" 33 | } 34 | } 35 | } 36 | 37 | class Main1TableViewController: UITableViewController { 38 | 39 | var samples = [AnimatorType.Default,.GIF,.Circle,.Arrow,.Snake,.Spark] 40 | 41 | override func viewDidLoad() { 42 | super.viewDidLoad() 43 | 44 | } 45 | 46 | override func didReceiveMemoryWarning() { 47 | super.didReceiveMemoryWarning() 48 | // Dispose of any resources that can be recreated. 49 | } 50 | 51 | // MARK: - Table view data source 52 | 53 | override func numberOfSections(in tableView: UITableView) -> Int { 54 | return 1 55 | } 56 | 57 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 58 | return samples.count 59 | } 60 | 61 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 62 | let cell = tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath) 63 | 64 | cell.textLabel?.text = samples[indexPath.row].description 65 | if indexPath.row <= 1 { 66 | cell.detailTextLabel?.text = "Built-In" 67 | }else { 68 | cell.detailTextLabel?.text = nil 69 | } 70 | 71 | return cell 72 | } 73 | 74 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 75 | let sampleVC = AddSamplesTableViewController() 76 | sampleVC.hidesBottomBarWhenPushed = true 77 | sampleVC.type = self.samples[indexPath.row] 78 | 79 | self.show(sampleVC, sender: self) 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /InfinitySample/Main2TableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Main2TableViewController.swift 3 | // InfinitySample 4 | // 5 | // Created by Danis on 15/12/22. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum BindAnimatorType: Int, CustomStringConvertible{ 12 | case Default = 0 13 | case GIF 14 | case Circle 15 | case Arrow 16 | 17 | var description:String { 18 | switch self { 19 | case .Default: 20 | return "Default" 21 | case .GIF: 22 | return "GIF" 23 | case .Circle: 24 | return "Circle" 25 | case .Arrow: 26 | return "Arrow" 27 | } 28 | } 29 | } 30 | 31 | 32 | class Main2TableViewController: UITableViewController { 33 | 34 | var samples = [BindAnimatorType.Default,.GIF,.Circle,.Arrow] 35 | 36 | override func viewDidLoad() { 37 | super.viewDidLoad() 38 | 39 | 40 | } 41 | 42 | override func didReceiveMemoryWarning() { 43 | super.didReceiveMemoryWarning() 44 | // Dispose of any resources that can be recreated. 45 | } 46 | 47 | // MARK: - Table view data source 48 | 49 | override func numberOfSections(in tableView: UITableView) -> Int { 50 | return 1 51 | } 52 | 53 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 54 | return samples.count 55 | } 56 | 57 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 58 | let cell = tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath) 59 | 60 | cell.textLabel?.text = samples[indexPath.row].description 61 | if indexPath.row <= 1 { 62 | cell.detailTextLabel?.text = "Built-In" 63 | }else { 64 | cell.detailTextLabel?.text = nil 65 | } 66 | 67 | return cell 68 | } 69 | 70 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 71 | let sampleVC = BindSamplesTableViewController() 72 | sampleVC.type = samples[indexPath.row] 73 | 74 | self.show(sampleVC, sender: self) 75 | } 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_0.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_30.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_30@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_0.imageset/hud_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_0.imageset/hud_30.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_0.imageset/hud_30@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_0.imageset/hud_30@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_1.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_1@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_1.imageset/hud_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_1.imageset/hud_1.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_1.imageset/hud_1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_1.imageset/hud_1@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_10.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_10.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_10@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_10.imageset/hud_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_10.imageset/hud_10.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_10.imageset/hud_10@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_10.imageset/hud_10@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_11.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_11.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_11@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_11.imageset/hud_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_11.imageset/hud_11.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_11.imageset/hud_11@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_11.imageset/hud_11@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_12.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_12.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_12@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_12.imageset/hud_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_12.imageset/hud_12.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_12.imageset/hud_12@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_12.imageset/hud_12@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_13.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_13.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_13@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_13.imageset/hud_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_13.imageset/hud_13.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_13.imageset/hud_13@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_13.imageset/hud_13@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_14.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_14.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_14@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_14.imageset/hud_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_14.imageset/hud_14.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_14.imageset/hud_14@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_14.imageset/hud_14@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_15.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_15.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_15@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_15.imageset/hud_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_15.imageset/hud_15.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_15.imageset/hud_15@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_15.imageset/hud_15@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_16.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_16.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_16@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_16.imageset/hud_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_16.imageset/hud_16.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_16.imageset/hud_16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_16.imageset/hud_16@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_17.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_17.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_17@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_17.imageset/hud_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_17.imageset/hud_17.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_17.imageset/hud_17@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_17.imageset/hud_17@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_18.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_18.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_18@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_18.imageset/hud_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_18.imageset/hud_18.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_18.imageset/hud_18@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_18.imageset/hud_18@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_19.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_19.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_19@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_19.imageset/hud_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_19.imageset/hud_19.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_19.imageset/hud_19@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_19.imageset/hud_19@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_2.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_2@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_2.imageset/hud_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_2.imageset/hud_2.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_2.imageset/hud_2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_2.imageset/hud_2@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_20.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_20.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_20@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_20.imageset/hud_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_20.imageset/hud_20.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_20.imageset/hud_20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_20.imageset/hud_20@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_21.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_21.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_21@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_21.imageset/hud_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_21.imageset/hud_21.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_21.imageset/hud_21@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_21.imageset/hud_21@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_22.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_22.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_22@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_22.imageset/hud_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_22.imageset/hud_22.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_22.imageset/hud_22@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_22.imageset/hud_22@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_23.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_23.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_23@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_23.imageset/hud_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_23.imageset/hud_23.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_23.imageset/hud_23@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_23.imageset/hud_23@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_24.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_24.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_24@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_24.imageset/hud_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_24.imageset/hud_24.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_24.imageset/hud_24@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_24.imageset/hud_24@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_25.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_25.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_25@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_25.imageset/hud_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_25.imageset/hud_25.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_25.imageset/hud_25@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_25.imageset/hud_25@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_26.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_26.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_26@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_26.imageset/hud_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_26.imageset/hud_26.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_26.imageset/hud_26@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_26.imageset/hud_26@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_27.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_27.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_27@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_27.imageset/hud_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_27.imageset/hud_27.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_27.imageset/hud_27@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_27.imageset/hud_27@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_28.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_28.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_28@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_28.imageset/hud_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_28.imageset/hud_28.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_28.imageset/hud_28@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_28.imageset/hud_28@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_29.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_29.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_29@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_29.imageset/hud_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_29.imageset/hud_29.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_29.imageset/hud_29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_29.imageset/hud_29@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_3.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_3@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_3.imageset/hud_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_3.imageset/hud_3.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_3.imageset/hud_3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_3.imageset/hud_3@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_4.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_4@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_4.imageset/hud_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_4.imageset/hud_4.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_4.imageset/hud_4@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_4.imageset/hud_4@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_5.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_5.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_5@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_5.imageset/hud_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_5.imageset/hud_5.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_5.imageset/hud_5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_5.imageset/hud_5@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_6.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_6.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_6@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_6.imageset/hud_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_6.imageset/hud_6.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_6.imageset/hud_6@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_6.imageset/hud_6@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_7.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_7.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_7@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_7.imageset/hud_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_7.imageset/hud_7.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_7.imageset/hud_7@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_7.imageset/hud_7@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_8.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_8.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_8@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_8.imageset/hud_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_8.imageset/hud_8.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_8.imageset/hud_8@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_8.imageset/hud_8@2x.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_9.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal" 5 | }, 6 | { 7 | "idiom" : "universal", 8 | "scale" : "1x", 9 | "filename" : "hud_9.png" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "2x", 14 | "filename" : "hud_9@2x.png" 15 | }, 16 | { 17 | "idiom" : "universal", 18 | "scale" : "3x" 19 | } 20 | ], 21 | "info" : { 22 | "version" : 1, 23 | "author" : "xcode" 24 | } 25 | } -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_9.imageset/hud_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_9.imageset/hud_9.png -------------------------------------------------------------------------------- /InfinitySample/sample-gif.xcassets/hud_9.imageset/hud_9@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/InfinitySample/sample-gif.xcassets/hud_9.imageset/hud_9@2x.png -------------------------------------------------------------------------------- /InfinitySampleTests/InfinitySampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfinitySampleTests.swift 3 | // InfinitySampleTests 4 | // 5 | // Created by Danis on 15/12/21. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import InfinitySample 11 | 12 | class InfinitySampleTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /InfinitySampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /InfinityTests/InfinityTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfinityTests.swift 3 | // InfinityTests 4 | // 5 | // Created by Danis on 15/12/21. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Infinity 11 | 12 | class InfinityTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /InfinityTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 DanisFabric 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Products/Infinity.framework/Headers/Infinity-Swift.h: -------------------------------------------------------------------------------- 1 | // Generated by Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1) 2 | #pragma clang diagnostic push 3 | 4 | #if defined(__has_include) && __has_include() 5 | # include 6 | #endif 7 | 8 | #pragma clang diagnostic ignored "-Wauto-import" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #if !defined(SWIFT_TYPEDEFS) 15 | # define SWIFT_TYPEDEFS 1 16 | # if defined(__has_include) && __has_include() 17 | # include 18 | # elif !defined(__cplusplus) || __cplusplus < 201103L 19 | typedef uint_least16_t char16_t; 20 | typedef uint_least32_t char32_t; 21 | # endif 22 | typedef float swift_float2 __attribute__((__ext_vector_type__(2))); 23 | typedef float swift_float3 __attribute__((__ext_vector_type__(3))); 24 | typedef float swift_float4 __attribute__((__ext_vector_type__(4))); 25 | typedef double swift_double2 __attribute__((__ext_vector_type__(2))); 26 | typedef double swift_double3 __attribute__((__ext_vector_type__(3))); 27 | typedef double swift_double4 __attribute__((__ext_vector_type__(4))); 28 | typedef int swift_int2 __attribute__((__ext_vector_type__(2))); 29 | typedef int swift_int3 __attribute__((__ext_vector_type__(3))); 30 | typedef int swift_int4 __attribute__((__ext_vector_type__(4))); 31 | typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); 32 | typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); 33 | typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); 34 | #endif 35 | 36 | #if !defined(SWIFT_PASTE) 37 | # define SWIFT_PASTE_HELPER(x, y) x##y 38 | # define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) 39 | #endif 40 | #if !defined(SWIFT_METATYPE) 41 | # define SWIFT_METATYPE(X) Class 42 | #endif 43 | #if !defined(SWIFT_CLASS_PROPERTY) 44 | # if __has_feature(objc_class_property) 45 | # define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ 46 | # else 47 | # define SWIFT_CLASS_PROPERTY(...) 48 | # endif 49 | #endif 50 | 51 | #if defined(__has_attribute) && __has_attribute(objc_runtime_name) 52 | # define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) 53 | #else 54 | # define SWIFT_RUNTIME_NAME(X) 55 | #endif 56 | #if defined(__has_attribute) && __has_attribute(swift_name) 57 | # define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) 58 | #else 59 | # define SWIFT_COMPILE_NAME(X) 60 | #endif 61 | #if defined(__has_attribute) && __has_attribute(objc_method_family) 62 | # define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) 63 | #else 64 | # define SWIFT_METHOD_FAMILY(X) 65 | #endif 66 | #if defined(__has_attribute) && __has_attribute(noescape) 67 | # define SWIFT_NOESCAPE __attribute__((noescape)) 68 | #else 69 | # define SWIFT_NOESCAPE 70 | #endif 71 | #if !defined(SWIFT_CLASS_EXTRA) 72 | # define SWIFT_CLASS_EXTRA 73 | #endif 74 | #if !defined(SWIFT_PROTOCOL_EXTRA) 75 | # define SWIFT_PROTOCOL_EXTRA 76 | #endif 77 | #if !defined(SWIFT_ENUM_EXTRA) 78 | # define SWIFT_ENUM_EXTRA 79 | #endif 80 | #if !defined(SWIFT_CLASS) 81 | # if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted) 82 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA 83 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 84 | # else 85 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 86 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 87 | # endif 88 | #endif 89 | 90 | #if !defined(SWIFT_PROTOCOL) 91 | # define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA 92 | # define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA 93 | #endif 94 | 95 | #if !defined(SWIFT_EXTENSION) 96 | # define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) 97 | #endif 98 | 99 | #if !defined(OBJC_DESIGNATED_INITIALIZER) 100 | # if defined(__has_attribute) && __has_attribute(objc_designated_initializer) 101 | # define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) 102 | # else 103 | # define OBJC_DESIGNATED_INITIALIZER 104 | # endif 105 | #endif 106 | #if !defined(SWIFT_ENUM) 107 | # define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_EXTRA _name : _type 108 | # if defined(__has_feature) && __has_feature(generalized_swift_name) 109 | # define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type 110 | # else 111 | # define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name) 112 | # endif 113 | #endif 114 | #if !defined(SWIFT_UNAVAILABLE) 115 | # define SWIFT_UNAVAILABLE __attribute__((unavailable)) 116 | #endif 117 | #if defined(__has_feature) && __has_feature(modules) 118 | @import UIKit; 119 | @import CoreGraphics; 120 | #endif 121 | 122 | #pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" 123 | #pragma clang diagnostic ignored "-Wduplicate-method-arg" 124 | @class UIColor; 125 | @class NSCoder; 126 | 127 | SWIFT_CLASS("_TtC8Infinity20ArrowRefreshAnimator") 128 | @interface ArrowRefreshAnimator : UIView 129 | @property (nonatomic, strong) UIColor * _Nonnull color; 130 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 131 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 132 | @end 133 | 134 | 135 | SWIFT_CLASS("_TtC8Infinity22CircleInfiniteAnimator") 136 | @interface CircleInfiniteAnimator : UIView 137 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 138 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 139 | - (void)layoutSubviews; 140 | - (void)didMoveToWindow; 141 | @end 142 | 143 | 144 | SWIFT_CLASS("_TtC8Infinity21CircleRefreshAnimator") 145 | @interface CircleRefreshAnimator : UIView 146 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 147 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 148 | - (void)layoutSubviews; 149 | - (void)didMoveToWindow; 150 | @end 151 | 152 | @class UIActivityIndicatorView; 153 | 154 | SWIFT_CLASS("_TtC8Infinity23DefaultInfiniteAnimator") 155 | @interface DefaultInfiniteAnimator : UIView 156 | @property (nonatomic, strong) UIActivityIndicatorView * _Nonnull activityIndicatorView; 157 | @property (nonatomic, readonly) BOOL animating; 158 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 159 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 160 | - (void)layoutSubviews; 161 | - (void)didMoveToWindow; 162 | @end 163 | 164 | @class CAShapeLayer; 165 | 166 | SWIFT_CLASS("_TtC8Infinity22DefaultRefreshAnimator") 167 | @interface DefaultRefreshAnimator : UIView 168 | @property (nonatomic, strong) UIActivityIndicatorView * _Nonnull activityIndicatorView; 169 | @property (nonatomic, strong) CAShapeLayer * _Nonnull circleLayer; 170 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 171 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 172 | - (void)layoutSubviews; 173 | @end 174 | 175 | @class UIImage; 176 | 177 | SWIFT_CLASS("_TtC8Infinity19GIFInfiniteAnimator") 178 | @interface GIFInfiniteAnimator : UIView 179 | @property (nonatomic, copy) NSArray * _Nonnull animatedImages; 180 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 181 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 182 | @end 183 | 184 | 185 | SWIFT_CLASS("_TtC8Infinity18GIFRefreshAnimator") 186 | @interface GIFRefreshAnimator : UIView 187 | @property (nonatomic, copy) NSArray * _Nonnull refreshImages; 188 | @property (nonatomic, copy) NSArray * _Nonnull animatedImages; 189 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 190 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 191 | @end 192 | 193 | 194 | SWIFT_CLASS("_TtC8Infinity21SnakeInfiniteAnimator") 195 | @interface SnakeInfiniteAnimator : UIView 196 | @property (nonatomic, strong) UIColor * _Nonnull color; 197 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 198 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 199 | - (void)didMoveToWindow; 200 | @end 201 | 202 | 203 | SWIFT_CLASS("_TtC8Infinity20SnakeRefreshAnimator") 204 | @interface SnakeRefreshAnimator : UIView 205 | @property (nonatomic, strong) UIColor * _Nonnull color; 206 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 207 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 208 | - (void)didMoveToWindow; 209 | @end 210 | 211 | 212 | SWIFT_CLASS("_TtC8Infinity21SparkInfiniteAnimator") 213 | @interface SparkInfiniteAnimator : UIView 214 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 215 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 216 | - (void)didMoveToWindow; 217 | @end 218 | 219 | 220 | SWIFT_CLASS("_TtC8Infinity20SparkRefreshAnimator") 221 | @interface SparkRefreshAnimator : UIView 222 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 223 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 224 | - (void)didMoveToWindow; 225 | @end 226 | 227 | 228 | @interface UIColor (SWIFT_EXTENSION(Infinity)) 229 | @end 230 | 231 | 232 | @interface UIColor (SWIFT_EXTENSION(Infinity)) 233 | @end 234 | 235 | 236 | @interface UIColor (SWIFT_EXTENSION(Infinity)) 237 | @end 238 | 239 | 240 | @interface UIScrollView (SWIFT_EXTENSION(Infinity)) 241 | @end 242 | 243 | 244 | @interface UIScrollView (SWIFT_EXTENSION(Infinity)) 245 | @end 246 | 247 | 248 | @interface UIScrollView (SWIFT_EXTENSION(Infinity)) 249 | @end 250 | 251 | 252 | @interface UIScrollView (SWIFT_EXTENSION(Infinity)) 253 | @end 254 | 255 | 256 | @interface UIScrollView (SWIFT_EXTENSION(Infinity)) 257 | @end 258 | 259 | 260 | @interface UIView (SWIFT_EXTENSION(Infinity)) 261 | @end 262 | 263 | #pragma clang diagnostic pop 264 | -------------------------------------------------------------------------------- /Products/Infinity.framework/Headers/Infinity.h: -------------------------------------------------------------------------------- 1 | // 2 | // Infinity.h 3 | // Infinity 4 | // 5 | // Created by Danis on 15/12/21. 6 | // Copyright © 2015年 danis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Infinity. 12 | FOUNDATION_EXPORT double InfinityVersionNumber; 13 | 14 | //! Project version string for Infinity. 15 | FOUNDATION_EXPORT const unsigned char InfinityVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Products/Infinity.framework/Infinity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/Products/Infinity.framework/Infinity -------------------------------------------------------------------------------- /Products/Infinity.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/Products/Infinity.framework/Info.plist -------------------------------------------------------------------------------- /Products/Infinity.framework/Modules/Infinity.swiftmodule/arm.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/Products/Infinity.framework/Modules/Infinity.swiftmodule/arm.swiftdoc -------------------------------------------------------------------------------- /Products/Infinity.framework/Modules/Infinity.swiftmodule/arm.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/Products/Infinity.framework/Modules/Infinity.swiftmodule/arm.swiftmodule -------------------------------------------------------------------------------- /Products/Infinity.framework/Modules/Infinity.swiftmodule/arm64.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/Products/Infinity.framework/Modules/Infinity.swiftmodule/arm64.swiftdoc -------------------------------------------------------------------------------- /Products/Infinity.framework/Modules/Infinity.swiftmodule/arm64.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/Products/Infinity.framework/Modules/Infinity.swiftmodule/arm64.swiftmodule -------------------------------------------------------------------------------- /Products/Infinity.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module Infinity { 2 | umbrella header "Infinity.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | 8 | module Infinity.Swift { 9 | header "Infinity-Swift.h" 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo](https://github.com/DanisFabric/Infinity/blob/master/images/logo.png) 2 | 3 | # Infinity [中文教程](https://github.com/DanisFabric/Infinity/blob/master/README_CN.md) 4 | 5 | ## Introduction 6 | 7 | `Infinity` is a simple to use library written in Swift3.0. there are some advantages: 8 | 9 | 1. Flexibility: You can write your animations. 10 | 2. Easy to use: One line code make UIScrollView support pull-to-refresh or infinity-scrolling 11 | 12 | 13 | ## Screens [More Sample Images](https://github.com/DanisFabric/Infinity/wiki/Screens) 14 | 15 | ![screen1](https://github.com/DanisFabric/Infinity/blob/master/images/add-default.gif) 16 | ![screen1](https://github.com/DanisFabric/Infinity/blob/master/images/bind-default.gif) 17 | 18 | ## Requirements 19 | 20 | - iOS 8.0+ 21 | - Swift 3.0+ 22 | 23 | ## Install 24 | 25 | ### Carthaga 26 | 27 | Add the following code to your `Cartfile` and run `Carthage update`. 28 | 29 | ```ruby 30 | github "DanisFabric/Infinity" 31 | ``` 32 | 33 | ### Manual 34 | 35 | 1. Download the sample project 36 | 2. add the files in Infinity folder to your project 37 | 38 | 39 | ## Usage 40 | 41 | Import `Infinity` 42 | 43 | ```Swift 44 | import Infinity 45 | ``` 46 | 47 | ### Pull-To-Refresh 48 | 49 | #### Add pull-to-refresh to UIScrollView 50 | 51 | 1. create animator which to show the progress of pull-to-refresh 52 | 2. add animator to your UIScrollView 53 | 54 | ```Swift 55 | let animator = DefaultRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 56 | tableView.fty.pullToRefresh.add(animator: animator) { [unowned self] in 57 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) { 58 | print("end refreshing") 59 | self.tableView.fty.pullToRefresh.end() 60 | } 61 | } 62 | ``` 63 | 64 | #### Stop refreshing 65 | 66 | ```Swift 67 | tableView.fty.pullToRefresh.end() 68 | ``` 69 | 70 | #### Remove refreshing 71 | 72 | ```Swift 73 | tableView.fty.pullToRefresh.remove() 74 | ``` 75 | 76 | #### Trigger refreshing 77 | 78 | ```Swift 79 | tableView.fty.pullToRefresh.begin() 80 | ``` 81 | 82 | ### Infinite-Scrolling 83 | 84 | #### Add infinite-scrolling to UIScrollView 85 | 86 | 1. create animator to show the state of infinity-scroll: 87 | 2. add animator to your UIScrollView 88 | 89 | ```Swift 90 | let animator = DefaultInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) 91 | tableView.fty.infiniteScroll.add(animator: animator) { [unowned self] in 92 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { 93 | self.tableView.fty.infiniteScroll.end() 94 | } 95 | } 96 | 97 | ``` 98 | 99 | #### Stop infinite-scrolling 100 | 101 | ```Swift 102 | tableView.fty.infiniteScroll.end() 103 | ``` 104 | 105 | #### Remote infinite-scrolling 106 | 107 | ```Swift 108 | tableView.fty.infiniteScroll.remove() 109 | ``` 110 | 111 | #### Trigger infinite-scrolling 112 | 113 | ```Swift 114 | tableView.fty.infiniteScroll.begin() 115 | ``` 116 | 117 | ### Best Practice 118 | 119 | #### When to add/remove Infinity 120 | 121 | - `addPullToRefresh`/`addInfiniteScroll` in `viewDidLoad` of `UIViewController` 122 | - `removePullToRefresh`/`removeInfiniteScroll` in `deinit` of `UIViewController` 123 | 124 | 125 | 126 | ```Swift 127 | override func viewDidLoad() { 128 | super.viewDidLoad() 129 | 130 | let animator = DefaultRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 131 | tableView.fty.pullToRefresh.add(animator: animator) { [unowned self] in 132 | // 耗时操作(数据库读取,网络读取) 133 | self.tableView.fty.pullToRefresh.end() // 调用此方法来停止刷新的动画 134 | } 135 | 136 | let animator = DefaultInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) 137 | tableView.fty.infiniteScroll.add(animator: animator) { [unowned self] in 138 | // 耗时操作(数据库读取,网络读取) 139 | self.tableView.fty.infiniteScroll.end() 140 | } 141 | } 142 | 143 | deinit { 144 | tableView.fty.pullToRefresh.remove() 145 | tableView.fty.infiniteScroll.remove() 146 | 147 | // 或者使用下面这句代码,和上面代码效果相同 148 | tableView.fty.clear() 149 | } 150 | ``` 151 | 152 | ### automaticallyAdjustsScrollViewInsets 153 | 154 | 155 | `automaticallyAdjustsScrollViewInsets` property on UIViewController which is by default to true bother the `Infinity` control UIScrollView, so it will be automatically set to false when add pull-to-refresh. 156 | 157 | ```Swift 158 | tableView.automaticallyAdjustsScrollViewInsets = false 159 | tableView.contentInset = UIEdgeInsets(top: 64, left: 0, bottom: 0, right: 0) 160 | ``` 161 | ## Bind VS Add 162 | 163 | Let's see the definition of add/bind operations: 164 | 165 | ```Swift 166 | // PullToRefresh 167 | public func add(height: CGFloat = 60.0, animator: CustomPullToRefreshAnimator, action:(()->Void)?) 168 | public func bind(height: CGFloat = 60.0, toAnimator: CustomPullToRefreshAnimator, action:(()->Void)?) 169 | 170 | //InfinityScroll 171 | public func add(height: CGFloat = 80.0, animator: CustomInfinityScrollAnimator, action: (() -> Void)?) 172 | public func bind(height: CGFloat = 80.0, toAnimator: CustomInfinityScrollAnimator, action: (() -> Void)?) 173 | ``` 174 | 175 | The parameters of bind operation is the same as parameters of add operation, following is the differences: 176 | 177 | - add operation will add animator to UIScrollView as a subview 178 | - bind operation don't do anything to animator, the animator just receive messages from pull-to-refresh/infinity-scrolling. It means you can bind any object to pull-to-refresh/infinity-scrolling, and you can control that object completely. 179 | 180 | ## Custom Animator 181 | 182 | You just need to confirm one of following protocols to create your animator whose all behavior is under your control. 183 | 184 | ```Swift 185 | public protocol CustomPullToRefreshAnimator { 186 | func animateState(state: PullToRefreshState) 187 | } 188 | ``` 189 | 190 | ``` 191 | public protocol CustomInfinityScrollAnimator { 192 | func animateState(state: InfinityScrollState) 193 | } 194 | ``` 195 | Let's create a most simple Animator which onlu has a label to show the state of pull-to-refresh. 196 | 197 | ```Swift 198 | class TextAnimator: UIView, CustomPullToRefreshAnimator { 199 | var textLabel = UILabel() 200 | 201 | override init(frame: CGRect) { 202 | super.init(frame: frame) 203 | 204 | textLabel.frame = self.bounds 205 | self.addSubview(textLabel) 206 | } 207 | required init?(coder aDecoder: NSCoder) { 208 | fatalError("init(coder:) has not been implemented") 209 | } 210 | func animateState(state: PullToRefreshState) { 211 | switch state { 212 | case .None: 213 | textLabel.text = "Pull Me To Refresh" 214 | case .Releasing(let progress): 215 | textLabel.text = String(progress) 216 | case .Loading: 217 | textLabel.text = "Loading ......." 218 | } 219 | } 220 | } 221 | // add TextAniamtor to UIScrollView 222 | let animator = TextAnimator(frame: CGRect(x: 0, y: 0, width: 200, height: 24)) 223 | tableView.fty.pullToRefresh.add(animator: animator){ [unowned self] in 224 | // 耗时操作(数据库读取,网络读取) 225 | self.tableView.fty.pullToRefresh.end() 226 | } 227 | ``` 228 | 229 | 230 | ## Others 231 | 232 | ### supportSpringBounces 233 | 234 | A bool value of UIScrollView to support spring effect 235 | 236 | ```Swift 237 | tableView.supportSpringBounces = true 238 | ``` 239 | 240 | ### Contact 241 | 242 | I'd be happy if you sent me links to your apps where you use `Infinity`. If you have any questions or suggestion, send me an email to let me know. 243 | 244 | Email : [DanisFabric](danisfabric@gmail.com) 245 | 246 | ### License 247 | 248 | ``` 249 | The MIT License (MIT) 250 | 251 | Copyright © 2015 DanisFabric 252 | 253 | Permission is hereby granted, free of charge, to any person obtaining a copy 254 | of this software and associated documentation files (the "Software"), to deal 255 | in the Software without restriction, including without limitation the rights 256 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 257 | copies of the Software, and to permit persons to whom the Software is 258 | furnished to do so, subject to the following conditions: 259 | 260 | The above copyright notice and this permission notice shall be included in 261 | all copies or substantial portions of the Software. 262 | 263 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 264 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 265 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 266 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 267 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 268 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 269 | THE SOFTWARE. 270 | ``` 271 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | ![logo](https://github.com/DanisFabric/Infinity/blob/master/images/logo.png) 2 | 3 | # Infinity 4 | 5 | ## 基本介绍 6 | `Infinity`是基于Swift3.0的为UIScrollView快速集成下拉刷新和上拉加载更多的开源库。`Infinity`有以下几个优点: 7 | 8 | 1. 灵活性:完全支持自定义交互动画 9 | 2. 易用性:一句代码集成/移除 下拉刷新功能 10 | 3. 低伤害性:对`UIScrollView`的行为不造成影响,让你放心使用`UIScrollView`相关功能。 11 | 12 | ## 运行效果图 [更多](https://github.com/DanisFabric/InfinityImages) 13 | 14 | ![screen1](https://github.com/DanisFabric/Infinity/blob/master/images/add-default.gif) 15 | ![screen1](https://github.com/DanisFabric/Infinity/blob/master/images/add-arrow.gif) 16 | ![screen1](https://github.com/DanisFabric/Infinity/blob/master/images/add-gif.gif) 17 | ![screen1](https://github.com/DanisFabric/Infinity/blob/master/images/bind-default.gif) 18 | ![screen1](https://github.com/DanisFabric/Infinity/blob/master/images/bind-arrow.gif) 19 | 20 | ## 集成 21 | 22 | ### Carthaga 23 | 24 | 将下面代码添加到你的Cartfile里面 25 | 26 | ```ruby 27 | github "DanisFabric/Infninity" 28 | ``` 29 | 30 | ### 手动添加 31 | 32 | 1. 下载工程文件 33 | 2. 将Infinity文件夹添加到你的工程里就OK了 34 | 35 | 36 | ## 使用方法 37 | 38 | ### 下拉刷新 39 | 40 | #### 集成的过程分为两步: 41 | 42 | 1. 为下拉刷新操作指定动画(Infinity提供了基本的刷新动画) 43 | 2. 将创建的动画指定给UIScrollView 44 | 45 | ```Swift 46 | let animator = DefaultRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 47 | tableView.fty.pullToRefresh.add(animator: animator) { [unowned self] in 48 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) { 49 | print("end refreshing") 50 | self.tableView.fty.pullToRefresh.end() 51 | } 52 | } 53 | ``` 54 | #### 停止刷新 55 | ```Swift 56 | tableView.fty.pullToRefresh.end() 57 | ``` 58 | #### 移除 59 | ```Swift 60 | tableView.fty.pullToRefresh.remove() 61 | ``` 62 | #### 代码触发刷新操作 63 | 64 | ```Swift 65 | tableView.fty.pullToRefresh.begin() 66 | ``` 67 | 68 | 69 | ### 上拉加载更多 70 | 71 | #### 集成过程与【下拉刷新】完全相同 72 | 73 | ```Swift 74 | let animator = DefaultInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) 75 | tableView.fty.infiniteScroll.add(animator: animator) { [unowned self] in 76 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { 77 | self.tableView.fty.infiniteScroll.end() 78 | } 79 | } 80 | 81 | ``` 82 | #### 停止 83 | 84 | ```Swift 85 | tableView.fty.infiniteScroll.end() 86 | ``` 87 | #### 移除 88 | 89 | ```Swift 90 | tableView.fty.infiniteScroll.remove() 91 | ``` 92 | #### 代码触发加载更多 93 | 94 | ```Swift 95 | tableView.fty.infiniteScroll.begin() 96 | ``` 97 | 98 | ### 最佳实践 99 | 100 | #### 何时集成 & 移除组件 101 | 102 | - 在`UIViewController`的`viewDidLoad`方法里集成组件(推荐) 103 | - 在`UIViewController`的`deinit`里移除组件(必须) 104 | 105 | ```Swift 106 | override func viewDidLoad() { 107 | super.viewDidLoad() 108 | 109 | let animator = DefaultRefreshAnimator(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) 110 | tableView.fty.pullToRefresh.add(animator: animator) { [unowned self] in 111 | // 耗时操作(数据库读取,网络读取) 112 | self.tableView.fty.pullToRefresh.end() // 调用此方法来停止刷新的动画 113 | } 114 | 115 | let animator = DefaultInfiniteAnimator(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) 116 | tableView.fty.infiniteScroll.add(animator: animator) { [unowned self] in 117 | // 耗时操作(数据库读取,网络读取) 118 | self.tableView.fty.infiniteScroll.end() 119 | } 120 | } 121 | 122 | deinit { 123 | tableView.fty.pullToRefresh.remove() 124 | tableView.fty.infiniteScroll.remove() 125 | 126 | // 或者使用下面这句代码,和上面代码效果相同 127 | tableView.fty.clear() 128 | } 129 | ``` 130 | 131 | #### 循环引用 132 | 133 | ![weak-reference](https://github.com/DanisFabric/Infinity/blob/master/images/weak.png) 134 | 135 | 如图,存在一个循环引用的链条,所以需要保证action->self 的引用为`unowned`的弱引用,self才能够得到正确的释放 136 | 137 | ### automaticallyAdjustsScrollViewInsets 138 | 139 | `UIViewController`有`automaticallyAdjustsScrollViewInsets`属性,当其为true时,viewController内的`UIScrollView`的contentInset会被自动调整为合适的值(自动调整的依据为`UIViewController`是否包含于`UINavigationController`和`UITabBarController`中)。这种自动调整会为下拉刷新带来一些意想不到的BUG。[PullToRefresh](https://github.com/Yalantis/PullToRefresh)等被使用较多的第三方库会出现进入新的viewController后回弹失效的问题。 140 | 141 | `Infinity`为了彻底解决这个问题以及让用户能够清楚地知晓其scrollView的contentInset值。所以默认将`automaticallyAdjustsScrollViewInsets`设置为false。 142 | 143 | 推荐开发者自己设置scrollView的`contentInset`。 144 | 145 | ```Swift 146 | tableView.automaticallyAdjustsScrollViewInsets = false 147 | tableView.contentInset = UIEdgeInsets(top: 64, left: 0, bottom: 0, right: 0) 148 | ``` 149 | 150 | ## 绑定 VS 集成 151 | 152 | 下面代码是add和bind方法的定义,由定义可以看出,bind和add操作的参数是完全相同的。而实际上,add和bind操作唯一的区别就是: 153 | 154 | - add操作会将animator作为UIView添加到`UIScrollView`上。 155 | - bind操作不会对animator做任何事,只负责将下拉刷新/加载更多 的信息发给animator 156 | 157 | ```Swift 158 | // PullToRefresh 159 | public func add(height: CGFloat = 60.0, animator: CustomPullToRefreshAnimator, action:(()->Void)?) 160 | public func bind(height: CGFloat = 60.0, toAnimator: CustomPullToRefreshAnimator, action:(()->Void)?) 161 | 162 | //InfinityScroll 163 | public func add(height: CGFloat = 80.0, animator: CustomInfinityScrollAnimator, action: (() -> Void)?) 164 | public func bind(height: CGFloat = 80.0, toAnimator: CustomInfinityScrollAnimator, action: (() -> Void)?) 165 | ``` 166 | 167 | bind操作提供了更多的灵活性。可以在示例项目里查看具体效果。 168 | 169 | ## 自定义动画 170 | 171 | `Infinity`的动画是面向协议的: 172 | 173 | ```Swift 174 | public protocol CustomPullToRefreshAnimator { 175 | func animateState(state: PullToRefreshState) 176 | } 177 | ``` 178 | 179 | ``` 180 | public protocol CustomInfinityScrollAnimator { 181 | func animateState(state: InfinityScrollState) 182 | } 183 | ``` 184 | 你唯一要做的,就是实现对应的协议的animateState方法。根据具体的state来做动画就可以了。 185 | 186 | 下面来实现一个具体的animator看看动画实现多么简单: 187 | 188 | ```Swift 189 | class TextAnimator: UIView, CustomPullToRefreshAnimator { 190 | var textLabel = UILabel() 191 | 192 | override init(frame: CGRect) { 193 | super.init(frame: frame) 194 | 195 | textLabel.frame = self.bounds 196 | self.addSubview(textLabel) 197 | } 198 | required init?(coder aDecoder: NSCoder) { 199 | fatalError("init(coder:) has not been implemented") 200 | } 201 | func animateState(state: PullToRefreshState) { 202 | switch state { 203 | case .None: 204 | textLabel.text = "Pull Me To Refresh" 205 | case .Releasing(let progress): 206 | textLabel.text = String(progress) 207 | case .Loading: 208 | textLabel.text = "Loading ......." 209 | } 210 | } 211 | } 212 | // 在UIViewController的viewDidLoad使用TextAnimator 213 | let animator = TextAnimator(frame: CGRect(x: 0, y: 0, width: 200, height: 24)) 214 | tableView.fty.pullToRefresh.add(animator: animator){ [unowned self] in 215 | // 耗时操作(数据库读取,网络读取) 216 | self.tableView.fty.pullToRefresh.end() 217 | } 218 | ``` 219 | 220 | 是不是很简单啊。而因为bind操作的存在,你甚至能够用任意类型来做animator,不一定要继承UIView。 221 | 222 | ## 其他 223 | 224 | ### infinityStickToContent 225 | 226 | - true: 底部`footer`忽略contentInset.bottom距离,而直接紧跟在UIScrollView的content后面 227 | - false: 底部`footer`留出contentInset.bottom的距离。 228 | - 默认为true, 一般情况下使用默认就OK了。 229 | 230 | ### 联系方式 231 | 232 | Email : [DanisFabric](danisfabric@gmail.com) 233 | 234 | ### License 235 | 236 | ``` 237 | The MIT License (MIT) 238 | 239 | Copyright © 2015 DanisFabric 240 | 241 | Permission is hereby granted, free of charge, to any person obtaining a copy 242 | of this software and associated documentation files (the "Software"), to deal 243 | in the Software without restriction, including without limitation the rights 244 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 245 | copies of the Software, and to permit persons to whom the Software is 246 | furnished to do so, subject to the following conditions: 247 | 248 | The above copyright notice and this permission notice shall be included in 249 | all copies or substantial portions of the Software. 250 | 251 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 252 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 253 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 254 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 255 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 256 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 257 | THE SOFTWARE. 258 | ``` 259 | -------------------------------------------------------------------------------- /images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/images/.DS_Store -------------------------------------------------------------------------------- /images/add-default.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/images/add-default.gif -------------------------------------------------------------------------------- /images/bind-default.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/images/bind-default.gif -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/images/logo.png -------------------------------------------------------------------------------- /images/weak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanisFabric/Infinity/c64ecb994f8157c17102caaee06a8e2cdc5456f4/images/weak.png --------------------------------------------------------------------------------