├── .DS_Store ├── .swiftpm └── xcode │ ├── package.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── stewart.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ └── stewart.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── .travis.yml ├── Example ├── AppleTv │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── App Icon & Top Shelf Image.brandassets │ │ │ ├── App Icon - App Store.imagestack │ │ │ │ ├── Back.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── Front.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ └── Middle.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ ├── App Icon.imagestack │ │ │ │ ├── Back.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── Front.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ └── Middle.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── Top Shelf Image Wide.imageset │ │ │ │ └── Contents.json │ │ │ └── Top Shelf Image.imageset │ │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.storyboard │ ├── Info.plist │ └── ViewController.swift ├── Podfile ├── Podfile.lock ├── Pods │ ├── Local Podspecs │ │ └── SwiftTickerView.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ │ ├── project.pbxproj │ │ └── xcuserdata │ │ │ └── stewart.xcuserdatad │ │ │ └── xcschemes │ │ │ ├── Pods-SwiftTickerView_Example.xcscheme │ │ │ ├── Pods-SwiftTickerView_Tests.xcscheme │ │ │ ├── Pods-appletv.xcscheme │ │ │ ├── Pods-appletvTests.xcscheme │ │ │ ├── SwiftTickerView-iOS.xcscheme │ │ │ ├── SwiftTickerView-tvOS.xcscheme │ │ │ └── xcschememanagement.plist │ └── Target Support Files │ │ ├── Pods-SwiftTickerView_Example │ │ ├── Pods-SwiftTickerView_Example-Info.plist │ │ ├── Pods-SwiftTickerView_Example-acknowledgements.markdown │ │ ├── Pods-SwiftTickerView_Example-acknowledgements.plist │ │ ├── Pods-SwiftTickerView_Example-dummy.m │ │ ├── Pods-SwiftTickerView_Example-frameworks.sh │ │ ├── Pods-SwiftTickerView_Example-umbrella.h │ │ ├── Pods-SwiftTickerView_Example.debug.xcconfig │ │ ├── Pods-SwiftTickerView_Example.modulemap │ │ └── Pods-SwiftTickerView_Example.release.xcconfig │ │ ├── Pods-SwiftTickerView_Tests │ │ ├── Pods-SwiftTickerView_Tests-Info.plist │ │ ├── Pods-SwiftTickerView_Tests-acknowledgements.markdown │ │ ├── Pods-SwiftTickerView_Tests-acknowledgements.plist │ │ ├── Pods-SwiftTickerView_Tests-dummy.m │ │ ├── Pods-SwiftTickerView_Tests-umbrella.h │ │ ├── Pods-SwiftTickerView_Tests.debug.xcconfig │ │ ├── Pods-SwiftTickerView_Tests.modulemap │ │ └── Pods-SwiftTickerView_Tests.release.xcconfig │ │ ├── Pods-appletv │ │ ├── Pods-appletv-Info.plist │ │ ├── Pods-appletv-acknowledgements.markdown │ │ ├── Pods-appletv-acknowledgements.plist │ │ ├── Pods-appletv-dummy.m │ │ ├── Pods-appletv-frameworks.sh │ │ ├── Pods-appletv-umbrella.h │ │ ├── Pods-appletv.debug.xcconfig │ │ ├── Pods-appletv.modulemap │ │ └── Pods-appletv.release.xcconfig │ │ ├── Pods-appletvTests │ │ ├── Pods-appletvTests-Info.plist │ │ ├── Pods-appletvTests-acknowledgements.markdown │ │ ├── Pods-appletvTests-acknowledgements.plist │ │ ├── Pods-appletvTests-dummy.m │ │ ├── Pods-appletvTests-umbrella.h │ │ ├── Pods-appletvTests.debug.xcconfig │ │ ├── Pods-appletvTests.modulemap │ │ └── Pods-appletvTests.release.xcconfig │ │ ├── SwiftTickerView-iOS │ │ ├── SwiftTickerView-iOS-Info.plist │ │ ├── SwiftTickerView-iOS-dummy.m │ │ ├── SwiftTickerView-iOS-prefix.pch │ │ ├── SwiftTickerView-iOS-umbrella.h │ │ ├── SwiftTickerView-iOS.modulemap │ │ └── SwiftTickerView-iOS.xcconfig │ │ └── SwiftTickerView-tvOS │ │ ├── SwiftTickerView-tvOS-Info.plist │ │ ├── SwiftTickerView-tvOS-dummy.m │ │ ├── SwiftTickerView-tvOS-prefix.pch │ │ ├── SwiftTickerView-tvOS-umbrella.h │ │ ├── SwiftTickerView-tvOS.modulemap │ │ └── SwiftTickerView-tvOS.xcconfig ├── SwiftTickerView.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── SwiftTickerView-Example.xcscheme │ └── xcuserdata │ │ └── stewart.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── SwiftTickerView.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── stewart.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── SwiftTickerView │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── NodeView.xib │ ├── TickerProvider.swift │ └── ViewController.swift ├── Tests │ ├── Info.plist │ └── Tests.swift ├── appletvTests │ ├── Info.plist │ └── appletvTests.swift └── appletvUITests │ ├── Info.plist │ └── appletvUITests.swift ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── SwiftTickerView │ ├── .gitkeep │ ├── DefaultConditionBehaviour.swift │ ├── Renderer.swift │ ├── SwiftTickerItemDecorator.swift │ └── SwiftTickerView.swift ├── SwiftTickerView.podspec └── _Pods.xcodeproj /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EMart86/SwiftTickerView/3229ba4e4c8283a7fd1601064d2f857f03544179/.DS_Store -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcuserdata/stewart.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EMart86/SwiftTickerView/3229ba4e4c8283a7fd1601064d2f857f03544179/.swiftpm/xcode/package.xcworkspace/xcuserdata/stewart.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /.swiftpm/xcode/xcuserdata/stewart.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftTickerView.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/ 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode10.0 6 | language: swift 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - pod lib lint --allow-warnings 14 | -------------------------------------------------------------------------------- /Example/AppleTv/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // appletv 4 | // 5 | // Created by Martin Eberl on 22.01.18. 6 | // Copyright © 2018 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // 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. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv" 5 | } 6 | ], 7 | "info" : { 8 | "version" : 1, 9 | "author" : "xcode" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Back.imagestacklayer" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv" 5 | } 6 | ], 7 | "info" : { 8 | "version" : 1, 9 | "author" : "xcode" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv" 5 | } 6 | ], 7 | "info" : { 8 | "version" : 1, 9 | "author" : "xcode" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Back.imagestacklayer" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets" : [ 3 | { 4 | "size" : "1280x768", 5 | "idiom" : "tv", 6 | "filename" : "App Icon - App Store.imagestack", 7 | "role" : "primary-app-icon" 8 | }, 9 | { 10 | "size" : "400x240", 11 | "idiom" : "tv", 12 | "filename" : "App Icon.imagestack", 13 | "role" : "primary-app-icon" 14 | }, 15 | { 16 | "size" : "2320x720", 17 | "idiom" : "tv", 18 | "filename" : "Top Shelf Image Wide.imageset", 19 | "role" : "top-shelf-image-wide" 20 | }, 21 | { 22 | "size" : "1920x720", 23 | "idiom" : "tv", 24 | "filename" : "Top Shelf Image.imageset", 25 | "role" : "top-shelf-image" 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/AppleTv/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "landscape", 5 | "idiom" : "tv", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "9.0", 8 | "scale" : "1x" 9 | } 10 | ], 11 | "info" : { 12 | "version" : 1, 13 | "author" : "xcode" 14 | } 15 | } -------------------------------------------------------------------------------- /Example/AppleTv/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 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Example/AppleTv/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | UIMainStoryboardFile 22 | Main 23 | 24 | 25 | -------------------------------------------------------------------------------- /Example/AppleTv/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SwiftTickerView 4 | // 5 | // Created by eberl_ma@gmx.at on 08/15/2017. 6 | // Copyright (c) 2017 eberl_ma@gmx.at. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftTickerView 11 | 12 | class ViewController: UIViewController { 13 | fileprivate let labelIdentifier = "TextMessage" 14 | @IBOutlet weak var tickerView: SwiftTickerView! 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | // Do any additional setup after loading the view, typically from a nib. 19 | 20 | tickerView.contentProvider = TickerProvider() 21 | tickerView.viewProvider = self 22 | tickerView.separator = "+++" 23 | tickerView.registerNodeView(UILabel.self, for: labelIdentifier) 24 | tickerView.render = Renderer.rightToLeft 25 | tickerView.tickerDelegate = self 26 | } 27 | 28 | override func viewWillAppear(_ animated: Bool) { 29 | super.viewWillAppear(animated) 30 | tickerView.start() 31 | } 32 | 33 | override func viewWillDisappear(_ animated: Bool) { 34 | super.viewWillDisappear(animated) 35 | tickerView.stop() 36 | } 37 | } 38 | 39 | extension ViewController: SwiftTickerDelegate { 40 | func tickerView(willResume ticker: SwiftTickerView) {} 41 | func tickerView(willStart ticker: SwiftTickerView) {} 42 | func tickerView(willStop ticker: SwiftTickerView) {} 43 | func tickerView(didPress view: UIView, content: Any?) {} 44 | } 45 | 46 | extension ViewController: SwiftTickerViewProvider { 47 | func tickerView(_ tickerView: SwiftTickerView, prepareSeparator separator: UIView) { 48 | if let separator = separator as? UILabel { 49 | separator.textColor = .white 50 | } 51 | } 52 | 53 | func tickerView(_ tickerView: SwiftTickerView, viewFor: Any) -> (UIView, reuseIdentifier: String?) { 54 | if let text = viewFor as? String, 55 | let label = tickerView.dequeReusableNodeView(for: labelIdentifier) as? UILabel { 56 | label.text = text 57 | label.sizeToFit() 58 | label.textColor = .white 59 | return (label, reuseIdentifier: labelIdentifier) 60 | } 61 | return (UIView(), reuseIdentifier: nil) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'SwiftTickerView_Example' do 4 | pod 'SwiftTickerView', :path => '../' 5 | 6 | target 'SwiftTickerView_Tests' do 7 | inherit! :search_paths 8 | 9 | 10 | end 11 | end 12 | 13 | target 'appletv' do 14 | pod 'SwiftTickerView', :path => '../' 15 | 16 | target 'appletvTests' do 17 | inherit! :search_paths 18 | 19 | 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - SwiftTickerView (1.5.0) 3 | 4 | DEPENDENCIES: 5 | - SwiftTickerView (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | SwiftTickerView: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | SwiftTickerView: 80aa186bf9cfbea31e9daa367d8b84823e4ef809 13 | 14 | PODFILE CHECKSUM: 0913893b3c3ed3f27b9a63d863d7215ddc13a471 15 | 16 | COCOAPODS: 1.7.5 17 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/SwiftTickerView.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SwiftTickerView", 3 | "version": "1.5.0", 4 | "summary": "A simple news ticker view", 5 | "swift_versions": "4.2", 6 | "description": "A swift ticker, written in swift. The one, with those '+++' separators ;)", 7 | "homepage": "https://github.com/EMart86/SwiftTickerView", 8 | "license": { 9 | "type": "MIT", 10 | "file": "LICENSE" 11 | }, 12 | "authors": { 13 | "Martin Eberl": "eberl_ma@gmx.at" 14 | }, 15 | "source": { 16 | "git": "https://github.com/EMart86/SwiftTickerView.git", 17 | "tag": "1.5.0" 18 | }, 19 | "platforms": { 20 | "ios": "9.0", 21 | "tvos": "9.0" 22 | }, 23 | "source_files": "Sources/SwiftTickerView/*", 24 | "swift_version": "4.2" 25 | } 26 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - SwiftTickerView (1.5.0) 3 | 4 | DEPENDENCIES: 5 | - SwiftTickerView (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | SwiftTickerView: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | SwiftTickerView: 80aa186bf9cfbea31e9daa367d8b84823e4ef809 13 | 14 | PODFILE CHECKSUM: 0913893b3c3ed3f27b9a63d863d7215ddc13a471 15 | 16 | COCOAPODS: 1.7.5 17 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/stewart.xcuserdatad/xcschemes/Pods-SwiftTickerView_Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/stewart.xcuserdatad/xcschemes/Pods-SwiftTickerView_Tests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/stewart.xcuserdatad/xcschemes/Pods-appletv.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/stewart.xcuserdatad/xcschemes/Pods-appletvTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/stewart.xcuserdatad/xcschemes/SwiftTickerView-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/stewart.xcuserdatad/xcschemes/SwiftTickerView-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/stewart.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Pods-SwiftTickerView_Example.xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 3 13 | 14 | Pods-SwiftTickerView_Tests.xcscheme 15 | 16 | isShown 17 | 18 | orderHint 19 | 4 20 | 21 | Pods-appletv.xcscheme 22 | 23 | isShown 24 | 25 | orderHint 26 | 1 27 | 28 | Pods-appletvTests.xcscheme 29 | 30 | isShown 31 | 32 | orderHint 33 | 2 34 | 35 | SwiftTickerView-iOS.xcscheme 36 | 37 | isShown 38 | 39 | orderHint 40 | 5 41 | 42 | SwiftTickerView-tvOS.xcscheme 43 | 44 | isShown 45 | 46 | orderHint 47 | 6 48 | 49 | 50 | SuppressBuildableAutocreation 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Example/Pods-SwiftTickerView_Example-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.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Example/Pods-SwiftTickerView_Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## SwiftTickerView 5 | 6 | Copyright (c) 2019 Martin Eberl 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Example/Pods-SwiftTickerView_Example-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2019 Martin Eberl <eberl_ma@gmx.at> 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | SwiftTickerView 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Example/Pods-SwiftTickerView_Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_SwiftTickerView_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_SwiftTickerView_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Example/Pods-SwiftTickerView_Example-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | 23 | # Used as a return value for each invocation of `strip_invalid_archs` function. 24 | STRIP_BINARY_RETVAL=0 25 | 26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 29 | 30 | # Copies and strips a vendored framework 31 | install_framework() 32 | { 33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 34 | local source="${BUILT_PRODUCTS_DIR}/$1" 35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 37 | elif [ -r "$1" ]; then 38 | local source="$1" 39 | fi 40 | 41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 42 | 43 | if [ -L "${source}" ]; then 44 | echo "Symlinked..." 45 | source="$(readlink "${source}")" 46 | fi 47 | 48 | # Use filter instead of exclude so missing patterns don't throw errors. 49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 51 | 52 | local basename 53 | basename="$(basename -s .framework "$1")" 54 | binary="${destination}/${basename}.framework/${basename}" 55 | 56 | if ! [ -r "$binary" ]; then 57 | binary="${destination}/${basename}" 58 | elif [ -L "${binary}" ]; then 59 | echo "Destination binary is symlinked..." 60 | dirname="$(dirname "${binary}")" 61 | binary="${dirname}/$(readlink "${binary}")" 62 | fi 63 | 64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 66 | strip_invalid_archs "$binary" 67 | fi 68 | 69 | # Resign the code if required by the build settings to avoid unstable apps 70 | code_sign_if_enabled "${destination}/$(basename "$1")" 71 | 72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 74 | local swift_runtime_libs 75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 76 | for lib in $swift_runtime_libs; do 77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 79 | code_sign_if_enabled "${destination}/${lib}" 80 | done 81 | fi 82 | } 83 | 84 | # Copies and strips a vendored dSYM 85 | install_dsym() { 86 | local source="$1" 87 | if [ -r "$source" ]; then 88 | # Copy the dSYM into a the targets temp dir. 89 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 90 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 91 | 92 | local basename 93 | basename="$(basename -s .framework.dSYM "$source")" 94 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" 95 | 96 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 97 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then 98 | strip_invalid_archs "$binary" 99 | fi 100 | 101 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 102 | # Move the stripped file into its final destination. 103 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 104 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 105 | else 106 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 107 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" 108 | fi 109 | fi 110 | } 111 | 112 | # Copies the bcsymbolmap files of a vendored framework 113 | install_bcsymbolmap() { 114 | local bcsymbolmap_path="$1" 115 | local destination="${BUILT_PRODUCTS_DIR}" 116 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" 117 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" 118 | } 119 | 120 | # Signs a framework with the provided identity 121 | code_sign_if_enabled() { 122 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 123 | # Use the current code_sign_identity 124 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 125 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 126 | 127 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 128 | code_sign_cmd="$code_sign_cmd &" 129 | fi 130 | echo "$code_sign_cmd" 131 | eval "$code_sign_cmd" 132 | fi 133 | } 134 | 135 | # Strip invalid architectures 136 | strip_invalid_archs() { 137 | binary="$1" 138 | # Get architectures for current target binary 139 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 140 | # Intersect them with the architectures we are building for 141 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 142 | # If there are no archs supported by this binary then warn the user 143 | if [[ -z "$intersected_archs" ]]; then 144 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 145 | STRIP_BINARY_RETVAL=0 146 | return 147 | fi 148 | stripped="" 149 | for arch in $binary_archs; do 150 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 151 | # Strip non-valid architectures in-place 152 | lipo -remove "$arch" -output "$binary" "$binary" 153 | stripped="$stripped $arch" 154 | fi 155 | done 156 | if [[ "$stripped" ]]; then 157 | echo "Stripped $binary of architectures:$stripped" 158 | fi 159 | STRIP_BINARY_RETVAL=1 160 | } 161 | 162 | 163 | if [[ "$CONFIGURATION" == "Debug" ]]; then 164 | install_framework "${BUILT_PRODUCTS_DIR}/SwiftTickerView-iOS/SwiftTickerView.framework" 165 | fi 166 | if [[ "$CONFIGURATION" == "Release" ]]; then 167 | install_framework "${BUILT_PRODUCTS_DIR}/SwiftTickerView-iOS/SwiftTickerView.framework" 168 | fi 169 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 170 | wait 171 | fi 172 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Example/Pods-SwiftTickerView_Example-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_SwiftTickerView_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_SwiftTickerView_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Example/Pods-SwiftTickerView_Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-iOS" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-iOS/SwiftTickerView.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "SwiftTickerView" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Example/Pods-SwiftTickerView_Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_SwiftTickerView_Example { 2 | umbrella header "Pods-SwiftTickerView_Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Example/Pods-SwiftTickerView_Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-iOS" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-iOS/SwiftTickerView.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "SwiftTickerView" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Tests/Pods-SwiftTickerView_Tests-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.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Tests/Pods-SwiftTickerView_Tests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Tests/Pods-SwiftTickerView_Tests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Tests/Pods-SwiftTickerView_Tests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_SwiftTickerView_Tests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_SwiftTickerView_Tests 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Tests/Pods-SwiftTickerView_Tests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_SwiftTickerView_TestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_SwiftTickerView_TestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Tests/Pods-SwiftTickerView_Tests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-iOS" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-iOS/SwiftTickerView.framework/Headers" 4 | OTHER_LDFLAGS = $(inherited) -framework "SwiftTickerView" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Tests/Pods-SwiftTickerView_Tests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_SwiftTickerView_Tests { 2 | umbrella header "Pods-SwiftTickerView_Tests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftTickerView_Tests/Pods-SwiftTickerView_Tests.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-iOS" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-iOS/SwiftTickerView.framework/Headers" 4 | OTHER_LDFLAGS = $(inherited) -framework "SwiftTickerView" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletv/Pods-appletv-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.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletv/Pods-appletv-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## SwiftTickerView 5 | 6 | Copyright (c) 2019 Martin Eberl 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletv/Pods-appletv-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2019 Martin Eberl <eberl_ma@gmx.at> 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | SwiftTickerView 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletv/Pods-appletv-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_appletv : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_appletv 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletv/Pods-appletv-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | 23 | # Used as a return value for each invocation of `strip_invalid_archs` function. 24 | STRIP_BINARY_RETVAL=0 25 | 26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 29 | 30 | # Copies and strips a vendored framework 31 | install_framework() 32 | { 33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 34 | local source="${BUILT_PRODUCTS_DIR}/$1" 35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 37 | elif [ -r "$1" ]; then 38 | local source="$1" 39 | fi 40 | 41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 42 | 43 | if [ -L "${source}" ]; then 44 | echo "Symlinked..." 45 | source="$(readlink "${source}")" 46 | fi 47 | 48 | # Use filter instead of exclude so missing patterns don't throw errors. 49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 51 | 52 | local basename 53 | basename="$(basename -s .framework "$1")" 54 | binary="${destination}/${basename}.framework/${basename}" 55 | 56 | if ! [ -r "$binary" ]; then 57 | binary="${destination}/${basename}" 58 | elif [ -L "${binary}" ]; then 59 | echo "Destination binary is symlinked..." 60 | dirname="$(dirname "${binary}")" 61 | binary="${dirname}/$(readlink "${binary}")" 62 | fi 63 | 64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 66 | strip_invalid_archs "$binary" 67 | fi 68 | 69 | # Resign the code if required by the build settings to avoid unstable apps 70 | code_sign_if_enabled "${destination}/$(basename "$1")" 71 | 72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 74 | local swift_runtime_libs 75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 76 | for lib in $swift_runtime_libs; do 77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 79 | code_sign_if_enabled "${destination}/${lib}" 80 | done 81 | fi 82 | } 83 | 84 | # Copies and strips a vendored dSYM 85 | install_dsym() { 86 | local source="$1" 87 | if [ -r "$source" ]; then 88 | # Copy the dSYM into a the targets temp dir. 89 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 90 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 91 | 92 | local basename 93 | basename="$(basename -s .framework.dSYM "$source")" 94 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" 95 | 96 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 97 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then 98 | strip_invalid_archs "$binary" 99 | fi 100 | 101 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 102 | # Move the stripped file into its final destination. 103 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 104 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 105 | else 106 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 107 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" 108 | fi 109 | fi 110 | } 111 | 112 | # Copies the bcsymbolmap files of a vendored framework 113 | install_bcsymbolmap() { 114 | local bcsymbolmap_path="$1" 115 | local destination="${BUILT_PRODUCTS_DIR}" 116 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" 117 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" 118 | } 119 | 120 | # Signs a framework with the provided identity 121 | code_sign_if_enabled() { 122 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 123 | # Use the current code_sign_identity 124 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 125 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 126 | 127 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 128 | code_sign_cmd="$code_sign_cmd &" 129 | fi 130 | echo "$code_sign_cmd" 131 | eval "$code_sign_cmd" 132 | fi 133 | } 134 | 135 | # Strip invalid architectures 136 | strip_invalid_archs() { 137 | binary="$1" 138 | # Get architectures for current target binary 139 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 140 | # Intersect them with the architectures we are building for 141 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 142 | # If there are no archs supported by this binary then warn the user 143 | if [[ -z "$intersected_archs" ]]; then 144 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 145 | STRIP_BINARY_RETVAL=0 146 | return 147 | fi 148 | stripped="" 149 | for arch in $binary_archs; do 150 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 151 | # Strip non-valid architectures in-place 152 | lipo -remove "$arch" -output "$binary" "$binary" 153 | stripped="$stripped $arch" 154 | fi 155 | done 156 | if [[ "$stripped" ]]; then 157 | echo "Stripped $binary of architectures:$stripped" 158 | fi 159 | STRIP_BINARY_RETVAL=1 160 | } 161 | 162 | 163 | if [[ "$CONFIGURATION" == "Debug" ]]; then 164 | install_framework "${BUILT_PRODUCTS_DIR}/SwiftTickerView-tvOS/SwiftTickerView.framework" 165 | fi 166 | if [[ "$CONFIGURATION" == "Release" ]]; then 167 | install_framework "${BUILT_PRODUCTS_DIR}/SwiftTickerView-tvOS/SwiftTickerView.framework" 168 | fi 169 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 170 | wait 171 | fi 172 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletv/Pods-appletv-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_appletvVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_appletvVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletv/Pods-appletv.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-tvOS" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-tvOS/SwiftTickerView.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "SwiftTickerView" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletv/Pods-appletv.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_appletv { 2 | umbrella header "Pods-appletv-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletv/Pods-appletv.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-tvOS" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-tvOS/SwiftTickerView.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "SwiftTickerView" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletvTests/Pods-appletvTests-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.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletvTests/Pods-appletvTests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletvTests/Pods-appletvTests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletvTests/Pods-appletvTests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_appletvTests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_appletvTests 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletvTests/Pods-appletvTests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_appletvTestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_appletvTestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletvTests/Pods-appletvTests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-tvOS" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-tvOS/SwiftTickerView.framework/Headers" 4 | OTHER_LDFLAGS = $(inherited) -framework "SwiftTickerView" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletvTests/Pods-appletvTests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_appletvTests { 2 | umbrella header "Pods-appletvTests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-appletvTests/Pods-appletvTests.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-tvOS" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-tvOS/SwiftTickerView.framework/Headers" 4 | OTHER_LDFLAGS = $(inherited) -framework "SwiftTickerView" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-iOS/SwiftTickerView-iOS-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.5.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-iOS/SwiftTickerView-iOS-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_SwiftTickerView_iOS : NSObject 3 | @end 4 | @implementation PodsDummy_SwiftTickerView_iOS 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-iOS/SwiftTickerView-iOS-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-iOS/SwiftTickerView-iOS-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double SwiftTickerViewVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char SwiftTickerViewVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-iOS/SwiftTickerView-iOS.modulemap: -------------------------------------------------------------------------------- 1 | framework module SwiftTickerView { 2 | umbrella header "SwiftTickerView-iOS-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-iOS/SwiftTickerView-iOS.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-iOS 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-tvOS/SwiftTickerView-tvOS-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.5.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-tvOS/SwiftTickerView-tvOS-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_SwiftTickerView_tvOS : NSObject 3 | @end 4 | @implementation PodsDummy_SwiftTickerView_tvOS 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-tvOS/SwiftTickerView-tvOS-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-tvOS/SwiftTickerView-tvOS-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double SwiftTickerViewVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char SwiftTickerViewVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-tvOS/SwiftTickerView-tvOS.modulemap: -------------------------------------------------------------------------------- 1 | framework module SwiftTickerView { 2 | umbrella header "SwiftTickerView-tvOS-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftTickerView-tvOS/SwiftTickerView-tvOS.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SwiftTickerView-tvOS 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /Example/SwiftTickerView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/SwiftTickerView.xcodeproj/xcshareddata/xcschemes/SwiftTickerView-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /Example/SwiftTickerView.xcodeproj/xcuserdata/stewart.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | AppleTv.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 7 11 | 12 | SwiftTickerView-Example.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | appletv.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 8 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Example/SwiftTickerView.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/SwiftTickerView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/SwiftTickerView.xcworkspace/xcuserdata/stewart.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EMart86/SwiftTickerView/3229ba4e4c8283a7fd1601064d2f857f03544179/Example/SwiftTickerView.xcworkspace/xcuserdata/stewart.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Example/SwiftTickerView/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftTickerView 4 | // 5 | // Created by eberl_ma@gmx.at on 08/15/2017. 6 | // Copyright (c) 2017 eberl_ma@gmx.at. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // 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. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // 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. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/SwiftTickerView/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Example/SwiftTickerView/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 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /Example/SwiftTickerView/Images.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 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /Example/SwiftTickerView/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 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Example/SwiftTickerView/NodeView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Example/SwiftTickerView/TickerProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TickerProvider.swift 3 | // SwiftTickerView 4 | // 5 | // Created by Martin Eberl on 15.08.17. 6 | // Copyright © 2017 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftTickerView 11 | 12 | final class TickerProvider: SwiftTickerProviderProtocol { 13 | private let superContent = [["A", "B", "C"], 14 | ["D", "E", "F"], 15 | ["G", "H", "I"], 16 | ["J", "K", "L"], 17 | ["M", "N", "O"], 18 | ["P", "Q", "R"], 19 | ["S", "T", "U"], 20 | ["V", "W", "X"], 21 | ["Y", "Z"]] 22 | private var content: [String] 23 | private var contentIndex = 0 24 | private var index = 0 25 | 26 | init() { 27 | content = superContent[contentIndex] 28 | } 29 | 30 | var hasContent = true 31 | var nextObject: Any { 32 | if index >= content.count { 33 | index = 0 34 | } 35 | let next = content[index] 36 | index += 1 37 | return next 38 | } 39 | 40 | func updateContent() { 41 | if !superContent.indices.contains(contentIndex) { 42 | index = 0 43 | contentIndex = 0 44 | } 45 | let next = superContent[contentIndex] 46 | contentIndex += 1 47 | index = 0 48 | content = next 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Example/SwiftTickerView/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SwiftTickerView 4 | // 5 | // Created by eberl_ma@gmx.at on 08/15/2017. 6 | // Copyright (c) 2017 eberl_ma@gmx.at. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftTickerView 11 | 12 | class ViewController: UIViewController { 13 | fileprivate let labelIdentifier = "TextMessage" 14 | private let tickerContentProvider = TickerProvider() 15 | @IBOutlet weak var tickerView: SwiftTickerView! 16 | 17 | @IBOutlet weak var slider: UISlider! 18 | 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | // Do any additional setup after loading the view, typically from a nib. 22 | 23 | // setupTickerView(tickerView, dataSet: ["A", "B", "C"]) 24 | 25 | tickerView.contentProvider = tickerContentProvider 26 | tickerView.viewProvider = self 27 | tickerView.separator = "+++" 28 | tickerView.render = Renderer.leftToRight 29 | tickerView.render = Renderer.bottomToTopStopAtCenter(holdForSeconds: -1) 30 | // tickerView.render = Renderer(initials: [SwiftTickerItemDecorators.prepareAtLeftInnerBorder(), 31 | // SwiftTickerItemDecorators.alignItemsAboveEachOther(), 32 | // SwiftTickerItemDecorators.centerVertical()], 33 | // updates: [SwiftTickerItemDecorators.updateY(+)], 34 | // shouldAddNewNode: { current, _, offset in 35 | // current.frame.minY > offset 36 | // }, shouldRemoveNode: { current, tickerView in 37 | // current.frame.minY > tickerView.frame.maxY 38 | // }) 39 | // tickerView.render = Renderer.bottomToTop.customize(with: SwiftTickerItemDecorators.prepareAtLeftInnerBorder())*/ 40 | // tickerView.add(decorator: .ignoreFirstSeparator) 41 | tickerView.registerNodeView(UILabel.self, for: labelIdentifier) 42 | tickerView.tickerDelegate = self 43 | tickerView.reloadData() 44 | } 45 | 46 | override func viewWillAppear(_ animated: Bool) { 47 | super.viewWillAppear(animated) 48 | tickerView.start() 49 | } 50 | 51 | override func viewWillDisappear(_ animated: Bool) { 52 | super.viewWillDisappear(animated) 53 | tickerView.stop() 54 | } 55 | 56 | @IBAction func onValueChange(_ sender: Any) { 57 | tickerView.pixelPerSecond = CGFloat(slider.value) 58 | } 59 | 60 | @IBAction func onButtonClicked() { 61 | tickerContentProvider.updateContent() 62 | } 63 | 64 | @IBAction func updateContentAndReload(_ sender: Any) { 65 | tickerContentProvider.updateContent() 66 | tickerView.reloadData() 67 | } 68 | 69 | func setupTickerView(_ tickerView: SwiftTickerView, dataSet: [String]) { 70 | tickerView.contentProvider = tickerContentProvider 71 | tickerView.viewProvider = self 72 | tickerView.separator = "..." 73 | tickerView.add(decorator: .ignoreFirstSeparator) 74 | tickerView.distanceBetweenNodes = 10 75 | tickerView.render = Renderer.rightToLeft 76 | tickerView.registerNodeView(UILabel.self, for: labelIdentifier) 77 | tickerView.tickerDelegate = self 78 | } 79 | 80 | } 81 | 82 | extension ViewController: SwiftTickerDelegate { 83 | func tickerView(willResume ticker: SwiftTickerView) {} 84 | func tickerView(willStart ticker: SwiftTickerView) {} 85 | func tickerView(willStop ticker: SwiftTickerView) {} 86 | func tickerView(didPress view: UIView, content: Any?) {} 87 | } 88 | 89 | extension ViewController: SwiftTickerViewProvider { 90 | func tickerView(_ tickerView: SwiftTickerView, prepareSeparator separator: UIView) { 91 | if let separator = separator as? UILabel { 92 | separator.textColor = .white 93 | } 94 | } 95 | 96 | func tickerView(_ tickerView: SwiftTickerView, viewFor: Any) -> (UIView, reuseIdentifier: String?) { 97 | if let text = viewFor as? String, 98 | let label = tickerView.dequeReusableNodeView(for: labelIdentifier) as? UILabel { 99 | label.text = text 100 | label.sizeToFit() 101 | label.textColor = .white 102 | return (label, reuseIdentifier: labelIdentifier) 103 | } 104 | return (UIView(), reuseIdentifier: nil) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Example/Tests/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 | -------------------------------------------------------------------------------- /Example/Tests/Tests.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import XCTest 3 | import SwiftTickerView 4 | 5 | class Tests: XCTestCase { 6 | 7 | override func setUp() { 8 | super.setUp() 9 | // Put setup code here. This method is called before the invocation of each test method in the class. 10 | } 11 | 12 | override func tearDown() { 13 | // Put teardown code here. This method is called after the invocation of each test method in the class. 14 | super.tearDown() 15 | } 16 | 17 | func testExample() { 18 | // This is an example of a functional test case. 19 | XCTAssert(true, "Pass") 20 | } 21 | 22 | func testPerformanceExample() { 23 | // This is an example of a performance test case. 24 | self.measure() { 25 | // Put the code you want to measure the time of here. 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Example/appletvTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/appletvTests/appletvTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // appletvTests.swift 3 | // appletvTests 4 | // 5 | // Created by Martin Eberl on 22.01.18. 6 | // Copyright © 2018 CocoaPods. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import appletv 11 | 12 | class appletvTests: 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 | -------------------------------------------------------------------------------- /Example/appletvUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/appletvUITests/appletvUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // appletvUITests.swift 3 | // appletvUITests 4 | // 5 | // Created by Martin Eberl on 22.01.18. 6 | // Copyright © 2018 CocoaPods. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class appletvUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Martin Eberl 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 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SwiftTickerView", 8 | products: [ 9 | .library(name: "SwiftTickerView", targets: ["SwiftTickerView"]), 10 | ], 11 | dependencies: [ 12 | ], 13 | targets: [ 14 | .target(name: "SwiftTickerView", dependencies: []) 15 | ] 16 | ) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftTickerView 2 | 3 | [![CI Status](http://img.shields.io/travis/EMart86/SwiftTickerView.svg?style=flat)](https://travis-ci.org/EMart86/SwiftTickerView) 4 | [![Version](https://img.shields.io/cocoapods/v/SwiftTickerView.svg?style=flat)](http://cocoapods.org/pods/SwiftTickerView) 5 | [![License](https://img.shields.io/cocoapods/l/SwiftTickerView.svg?style=flat)](http://cocoapods.org/pods/SwiftTickerView) 6 | [![Platform](https://img.shields.io/cocoapods/p/SwiftTickerView.svg?style=flat)](http://cocoapods.org/pods/SwiftTickerView) 7 | 8 | ![Animation](https://thumbs.gfycat.com/NextFabulousEarthworm-size_restricted.gif) 9 | I'll definately have to update this gif, it doesn't look that crappy anymore! 10 | 11 | ## 1.5.0 12 | 13 | ### Following new Render decorators are vailable: 14 | * ```initialRenderer(closure: (UIView, UIView?, SwiftTickerView, CGFloat) -> Void)``` 15 | positon your node view wherever you want them to be placed 16 | * ```updateRenderer(closure: (UIView, CGFloat) -> Void)``` 17 | use this to customize your rendering option for e.g. to fade in the items or fade out 18 | * ```bottomToTopStopAtCenter(holdForSeconds seconds: TimeInterval)``` 19 | this can be used to create the mostly in TV used Ticker where the Ticker node appears at the bottom, when reaching center stayes there for some time and continues to the top 20 | 21 | ## 1.4.3 22 | 23 | - Add support for iOS 9 24 | 25 | ## 1.4.2 26 | 27 | ### Fixes 28 | - Fixes ignoreSeparator on startup when calling reloadData #5 29 | 30 | ## 1.4.1 31 | 32 | ### Fixes 33 | - Fix center vertical and horizontal 34 | 35 | ## 1.4.0 36 | 37 | ### Customize the Renderer easily by adding a new decorators: 38 | ```Renderer.topToBottom.customize(with: SwiftTickerItemDecorators.prepareAtBottomInnerBorder(with: 8))``` 39 | 40 | ### Following new Render decorators are vailable: 41 | * ```prepareAtTopInnerBorder()``` 42 | * ```prepareAtTopOuterBorder()``` 43 | * ```prepareAtBottomInnerBorder()``` 44 | * ```prepareAtBottomOuterBorder()``` 45 | * ```prepareAtLeftInnerBorder()``` 46 | * ```prepareAtLeftOuterBorder()``` 47 | * ```prepareAtRightInnerBorder()``` 48 | * ```prepareAtRightOuterBorder()``` 49 | 50 | ### Implement your own inital or update Render decorator by implementing the ```InitialRenderer & SwiftTickerItemDecorator``` or ```UpdateRenderer & SwiftTickerItemDecorator``` 51 | 52 | ### Following new Ticker decorator is available: 53 | * ```ignoreFirstSeparator``` 54 | Add a decorator to the TickerView by calling ```tickerView.add(.ignoreFirstSeparator)``` 55 | 56 | ### Renamings 57 | * ```SwiftTickerView.Renderer.rightToLeft``` renamed to ```Renderer.rightToLeft``` 58 | * ```SwiftTickerView.Renderer.leftToRight``` renamed to ```Renderer.leftToRight``` 59 | * ```SwiftTickerView.Renderer.topToBottom``` renamed to ```Renderer.topToBottom``` 60 | * ```SwiftTickerView.Renderer.bottomToTop``` renamed to ```Renderer.bottomToTop``` 61 | 62 | ## 1.3.0 63 | 64 | * You can now implement your own renderer 65 | 66 | ### Renamings 67 | * renamed ```direction``` to ```renderer``` 68 | * ```Direction.horizontalRightToLeft``` renamed to ```SwiftTickerView.Renderer.rightToLeft``` 69 | * ```Direction.horizontalLeftToRight``` renamed to ```SwiftTickerView.Renderer.leftToRight``` 70 | * ```Direction.verticalTopToBottom``` renamed to ```SwiftTickerView.Renderer.topToBottom``` 71 | * ```Direction.verticalBottomToTop``` renamed to ```SwiftTickerView.Renderer.bottomToTop``` 72 | 73 | ## 1.2.2 74 | 75 | * Now supports TV OS 76 | * Performance improvements 77 | 78 | ## Example 79 | 80 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 81 | 82 | ## Requirements 83 | 84 | SwiftTickerView is available through [CocoaPods](http://cocoapods.org). To install 85 | it, simply add the following line to your Podfile: 86 | 87 | ```ruby 88 | pod 'SwiftTickerView' 89 | ``` 90 | 91 | ## Setup 92 | 93 | You can eigther embed the SwiftTickerView within an Storyboard or a Xib View, or instantiate the View just like any other view: 94 | 95 | ```swift 96 | let tickerView = SwiftTickerView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 30)) 97 | ``` 98 | 99 | Use the separator property to simply create those textual separators or set a separator view class or nib to create those separator views. Also implement the viewProvider protocol to manipulate the separator view and the node view on demand 100 | ```swift 101 | tickerView.separator = "+++" 102 | tickerView.viewProvider = self 103 | ... 104 | ``` 105 | 106 | Register also some custom node views to be able to load them more easily 107 | ```swift 108 | tickerView.registerNodeView(UILabel.self, for: labelIdentifier) 109 | ``` 110 | 111 | If you want some callbacks on if the user stopped the ticker view (yes, the user can stop the view by tapping on the ticker view), implement the tickerDelegate and don't forget to asign it to the ticker view. You will also be able to determine the content, which the user has selected. 112 | ```swift 113 | tickerView.tickerDelegate = self 114 | ``` 115 | 116 | This ticker view is designed to be able to support arabic and hebrew aswell as the other languages. Simply use the direction property, to determine if you want the content to run from left to right, from right to left, from top to bottom or from bottom to top: 117 | ```swift 118 | tickerView.renderer = SwiftTickerView.Renderer.rightToLeft 119 | ``` 120 | 121 | You can manage the velocity of the content to run across the display. You can alter this value at runtime aswell to increase or slow down the ticker view: 122 | ```swift 123 | tickerView.pixelPerSecond = 60 //default is 60 124 | ``` 125 | 126 | Don't forget to start the tickerview, otherwhise it's not working: 127 | ```swift 128 | tickerView.start() 129 | ``` 130 | 131 | And last but not least, implement the contentProvider property to provide your content! 132 | 133 | Btw, in the viewProvider protocol, the view node view creation function has to return a tuple with a view parameter and an optional reuseIdentifier parameter. Use this parameter to store it and reuse it for later usage: 134 | ```swift 135 | func tickerView(_ tickerView: SwiftTickerView, viewFor: Any) -> (UIView, reuseIdentifier: String?) { 136 | if let text = viewFor as? String, 137 | let label = tickerView.dequeReusableNodeView(for: labelIdentifier) as? UILabel { 138 | label.text = text 139 | label.sizeToFit() 140 | label.textColor = .white 141 | return (label, reuseIdentifier: labelIdentifier) 142 | } 143 | return (UIView(), reuseIdentifier: nil) 144 | } 145 | 146 | func tickerView(_ tickerView: SwiftTickerView, prepareSeparator separator: UIView) { 147 | if let separator = separator as? UILabel { 148 | separator.textColor = .white 149 | } 150 | } 151 | ``` 152 | 153 | ## Author 154 | 155 | Martin Eberl, eberl_ma@gmx.at 156 | 157 | ## License 158 | 159 | SwiftTickerView is available under the MIT license. See the LICENSE file for more info. 160 | -------------------------------------------------------------------------------- /Sources/SwiftTickerView/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EMart86/SwiftTickerView/3229ba4e4c8283a7fd1601064d2f857f03544179/Sources/SwiftTickerView/.gitkeep -------------------------------------------------------------------------------- /Sources/SwiftTickerView/DefaultConditionBehaviour.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Default.swift 3 | // SwiftTickerView-iOS 4 | // 5 | // Created by Martin Eberl on 02.03.19. 6 | // 7 | 8 | import UIKit 9 | 10 | public class DefaultConditionBehaviour: Condition { 11 | weak var nodeView: UIView? 12 | var condition: ((UIView, SwiftTickerView, DefaultConditionBehaviour) -> Bool) 13 | 14 | init(condition: @escaping ((UIView, SwiftTickerView, DefaultConditionBehaviour) -> Bool)) { 15 | self.condition = condition 16 | } 17 | 18 | public func meets(nodeView: UIView, tickerView: SwiftTickerView) -> Bool { 19 | return condition(nodeView, tickerView, self) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/SwiftTickerView/Renderer.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | open class Renderer: SwiftTickerContentRenderer { 4 | public typealias ShouldAddNewNode = ((UIView, SwiftTickerView, CGFloat) -> Bool) 5 | public typealias ShouldRemoveNode = ((UIView, SwiftTickerView) -> Bool) 6 | 7 | /** 8 | Add inital render decorator for customizing the initial position of the node content 9 | 10 | - Parameter initial: Must conform to the InitialRenderer and SwiftTickerItemDecorator protocol 11 | */ 12 | open func customize(with initial: SwiftTickerItemDecorator & InitialRenderer) -> Renderer { 13 | initials.append(initial) 14 | return self 15 | } 16 | 17 | /** 18 | Add update render decorator for customizing the updated position of the node content 19 | 20 | - Parameter update: Must conform to the UpdateRenderer and SwiftTickerItemDecorator protocol 21 | */ 22 | open func customize(with update: SwiftTickerItemDecorator & UpdateRenderer) -> Renderer { 23 | updates.append(update) 24 | return self 25 | } 26 | 27 | /** 28 | Add condition decorator for customizing the condition to do something at a certain point 29 | 30 | - Parameter condition: A tuple with the first iteme being a closure that indicates the condition and a second item beind a closure that indicates the action 31 | */ 32 | open func customize(with condition: (condition: Condition, then: Action)) -> Renderer { 33 | when = when ?? [] 34 | when?.append(condition) 35 | return self 36 | } 37 | 38 | /** 39 | Renders the content from right to left and centered vertically in the ticker view, starting at the right border. 40 | */ 41 | public static var rightToLeft = Renderer(initials: [SwiftTickerItemDecorators.alignItemsLeftToEachOther(), 42 | SwiftTickerItemDecorators.prepareAtRightOuterBorder(), 43 | SwiftTickerItemDecorators.centerVertical()], 44 | updates: [SwiftTickerItemDecorators.updateX(-)], 45 | shouldAddNewNode: { current, tickerView, offset in 46 | if current.frame.maxX == -CGFloat.infinity { 47 | return false 48 | } 49 | return tickerView.frame.width - current.frame.maxX > offset 50 | }, shouldRemoveNode: { current, _ in 51 | current.frame.maxX < 0 52 | }) 53 | 54 | /** 55 | Renders the content from left to right and centered vertically in the ticker view, starting at the left border. 56 | */ 57 | public static var leftToRight = Renderer(initials: [SwiftTickerItemDecorators.alignItemsRightToEachOther(), 58 | SwiftTickerItemDecorators.prepareAtLeftOuterBorder(), 59 | SwiftTickerItemDecorators.centerVertical()], 60 | updates: [SwiftTickerItemDecorators.updateX(+)], 61 | shouldAddNewNode: { current, _, offset in 62 | current.frame.minX > offset 63 | }, shouldRemoveNode: { current, tickerView in 64 | current.frame.minX > tickerView.frame.maxX 65 | }) 66 | 67 | /** 68 | Renders the content bottom to top and centered horizontally in the ticker view, starting at the bottom border. 69 | */ 70 | public static var bottomToTop = Renderer(initials: [SwiftTickerItemDecorators.alignItemsBelowEachOther(), 71 | SwiftTickerItemDecorators.prepareAtBottomOuterBorder(), 72 | SwiftTickerItemDecorators.centerHorizontal()], 73 | updates: [SwiftTickerItemDecorators.updateY(-)], 74 | shouldAddNewNode: { current, tickerView, offset in 75 | tickerView.frame.height - current.frame.maxY > offset 76 | }, shouldRemoveNode: { current, _ in 77 | current.frame.maxY < 0 78 | }) 79 | 80 | /** 81 | Renders the content top to bottom and centered horizontally in the ticker view, starting at the top border. 82 | */ 83 | public static var topToBottom = Renderer(initials: [SwiftTickerItemDecorators.centerHorizontal(), 84 | SwiftTickerItemDecorators.alignItemsAboveEachOther(), 85 | SwiftTickerItemDecorators.prepareAtTopOuterBorder()], 86 | updates: [SwiftTickerItemDecorators.updateY(+)], 87 | shouldAddNewNode: { current, _, offset in 88 | current.frame.minY > offset 89 | }, shouldRemoveNode: { current, tickerView in 90 | current.frame.minY > tickerView.frame.maxY 91 | }) 92 | 93 | private class CustomTimer { 94 | private var block: ((Timer) -> Void)? = nil 95 | private weak var timer: Timer? 96 | 97 | func schedule(with interval: TimeInterval, repeats: Bool, block: @escaping ((Timer) -> Void)) { 98 | if #available(iOS 10.0, tvOS 10.0, *) { 99 | Timer.scheduledTimer(withTimeInterval: interval, repeats: repeats, block: block) 100 | } else { 101 | self.block = block 102 | timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(timerFired(_:)), userInfo: nil, repeats: repeats) 103 | } 104 | } 105 | 106 | @objc private func timerFired(_ sender: Any) { 107 | guard let timer = timer else { 108 | return 109 | } 110 | block?(timer) 111 | } 112 | } 113 | 114 | /** 115 | Renders the content bottom to top with the first item startin out of the bounds and moving each item up. 116 | When the current item reaches the center, it stops for given ammounts of seconds. Thereafter it continues. 117 | This behaviour is ment to be used on modern news tickers 118 | 119 | - Parameter holdForSeconds: use this option to let the user see the ticker node when centered in the view for ammount of seconds. Value has to be positive 120 | */ 121 | public static func bottomToTopStopAtCenter(holdForSeconds seconds: TimeInterval) -> Renderer { 122 | return Renderer(initials: [SwiftTickerItemDecorators.prepareAtBottomOuterBorder(force: true), 123 | SwiftTickerItemDecorators.prepareAtLeftInnerBorder()], 124 | updates: [SwiftTickerItemDecorators.updateY(-)], 125 | when: [( 126 | condition: DefaultConditionBehaviour(condition: { node, tickerView, behaviour in 127 | func isInVerticalCenter(node: UIView, tickerView: SwiftTickerView, allowedOffset: CGFloat = 5) -> Bool { 128 | let tickerCenter = tickerView.bounds.midY 129 | let nodeCenter = node.frame.minY + node.frame.height / 2 130 | return abs(tickerCenter - nodeCenter) < 5 131 | } 132 | 133 | guard behaviour.nodeView != node else { 134 | if !isInVerticalCenter(node: node, tickerView: tickerView) { 135 | behaviour.nodeView = nil 136 | } 137 | return false 138 | } 139 | if isInVerticalCenter(node: node, tickerView: tickerView) { 140 | behaviour.nodeView = node 141 | return true 142 | } 143 | behaviour.nodeView = nil 144 | return false 145 | }), 146 | then: { _, tickerView in 147 | tickerView.stop() 148 | CustomTimer().schedule(with: max(0, seconds), repeats: false, block: { _ in 149 | tickerView.start() 150 | }) 151 | return .return 152 | } 153 | )], 154 | shouldAddNewNode: { current, _, _ in 155 | current.frame.maxY < 0 156 | }, shouldRemoveNode: { current, tickerView in 157 | current.frame.maxY < 0 158 | }) 159 | } 160 | 161 | private var initials: [InitialRenderer & SwiftTickerItemDecorator] 162 | private var updates: [UpdateRenderer & SwiftTickerItemDecorator] 163 | private var when: [(condition: Condition, then: Action)]? 164 | private let shouldAddNewNode: ShouldAddNewNode 165 | private let shouldRemoveNode: ShouldRemoveNode 166 | private var last: UIView? 167 | 168 | /** 169 | Renderer constructor 170 | 171 | - Parameter initials: An array of InitialRenderer and SwiftTickerItemDecorator for defining the start position of each ticker node view 172 | - Parameter updates: An array of UpdateRenderer and SwiftTickerItemDecorator for defining the updated position of each ticker node view 173 | - Parameter shouldAddNewNode: Closure if a new node view should be added 174 | - Parameter shouldRemoveNode: Closure if a given new node view should be removed 175 | */ 176 | public init(initials: [InitialRenderer & SwiftTickerItemDecorator], 177 | updates: [UpdateRenderer & SwiftTickerItemDecorator], 178 | when: [(condition: Condition, then: Action)]? = nil, 179 | shouldAddNewNode: @escaping ShouldAddNewNode, 180 | shouldRemoveNode: @escaping ShouldRemoveNode) { 181 | self.initials = initials 182 | self.updates = updates 183 | self.when = when 184 | self.shouldAddNewNode = shouldAddNewNode 185 | self.shouldRemoveNode = shouldRemoveNode 186 | } 187 | 188 | open func tickerViewUpdate(_ tickerView: SwiftTickerView, render nodeView: UIView, offset: CGFloat) { 189 | updates.forEach { $0.updateWith(current: nodeView, offset: offset) } 190 | guard let when = when else { 191 | return 192 | } 193 | for whenCondition in when { 194 | if whenCondition.condition.meets(nodeView: nodeView, tickerView: tickerView) { 195 | switch whenCondition.then(self, tickerView) { 196 | case .return: 197 | return 198 | case .break: 199 | break 200 | case .continue: 201 | continue 202 | } 203 | } 204 | } 205 | } 206 | 207 | open func tickerViewShouldAddNext(_ tickerView: SwiftTickerView, current nodeView: UIView) -> Bool { 208 | return shouldAddNewNode(nodeView, tickerView, tickerView.distanceBetweenNodes) 209 | } 210 | 211 | open func tickerViewShouldRemove(_ tickerView: SwiftTickerView, nodeView: UIView) -> Bool { 212 | return shouldRemoveNode(nodeView, tickerView) 213 | } 214 | 215 | open func tickerView(_ tickerView: SwiftTickerView, render nodeView: UIView, with identifier: String) { 216 | initials.forEach { 217 | $0.updateWith(current: nodeView, 218 | last: last?.superview != nil ? last : nil, 219 | tickerView: tickerView, 220 | offset: tickerView.distanceBetweenNodes) } 221 | last = nodeView 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /Sources/SwiftTickerView/SwiftTickerItemDecorator.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | public struct SwiftTickerItemDecorators { 4 | // MARK: - Initial Renderer 5 | 6 | /** 7 | InitialRendererClosure 8 | 9 | Used in the initialRendere(closure:) method 10 | 11 | - Parameter node: the newly added view 12 | - Parameter last: the previously added view. This is optional, because when there hasn't been any nodes added, this parameter is nil. You can use this parameter, to align your new node alongside this node 13 | - Parameter tickerView: the SwiftTicker view 14 | - Parameter offset: the default offset between nodes 15 | */ 16 | public typealias InitialRendererClosure = ((UIView, UIView?, SwiftTickerView, CGFloat) -> Void) 17 | 18 | /** 19 | InitialRenderer 20 | 21 | Use this option, if you want the Ticker Nodes to be completely customizable initialized 22 | 23 | - Parameter closure: InitialRendererClosure 24 | */ 25 | public static func initialRenderer(closure: @escaping InitialRendererClosure) -> SwiftTickerItemDecorator & InitialRenderer { 26 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 27 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 28 | closure(current, last, tickerView, offset) 29 | } 30 | 31 | init(closure: @escaping InitialRendererClosure) { 32 | self.closure = closure 33 | } 34 | 35 | let closure: InitialRendererClosure 36 | 37 | } 38 | return Anonymous(closure: closure) 39 | } 40 | 41 | /** 42 | InitialRenderer 43 | 44 | Aligns the items left to each other 45 | 46 | This is used in the rightToLeft Rendering option 47 | 48 | - Parameter customOffset: A custom offset to each item 49 | */ 50 | public static func alignItemsLeftToEachOther(with customOffset: CGFloat? = nil) -> SwiftTickerItemDecorator & InitialRenderer { 51 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 52 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 53 | guard let last = last else { 54 | return 55 | } 56 | var frame = current.frame 57 | frame.origin.x = last.frame.maxX + (customOffset ?? offset) 58 | current.frame = frame 59 | } 60 | 61 | init(customOffset: CGFloat? = nil) { 62 | self.customOffset = customOffset 63 | } 64 | 65 | let customOffset: CGFloat? 66 | 67 | } 68 | return Anonymous(customOffset: customOffset) 69 | } 70 | 71 | /** 72 | InitialRenderer 73 | 74 | Aligns the items right to each other 75 | 76 | This is used in the leftToRight Rendering option 77 | 78 | - Parameter customOffset: A custom offset to each item 79 | */ 80 | 81 | public static func alignItemsRightToEachOther(with customOffset: CGFloat? = nil) -> SwiftTickerItemDecorator & InitialRenderer { 82 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 83 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 84 | guard let last = last else { 85 | return 86 | } 87 | var frame = current.frame 88 | frame.origin.x = last.frame.minX - (customOffset ?? offset) - frame.width 89 | current.frame = frame 90 | } 91 | 92 | init(customOffset: CGFloat? = nil) { 93 | self.customOffset = customOffset 94 | } 95 | 96 | let customOffset: CGFloat? 97 | 98 | } 99 | return Anonymous(customOffset: customOffset) 100 | } 101 | 102 | /** 103 | InitialRenderer 104 | 105 | Aligns the items below each other 106 | 107 | This is used in the bottomToTop Rendering option 108 | 109 | - Parameter customOffset: A custom offset to each item 110 | */ 111 | 112 | public static func alignItemsBelowEachOther(with customOffset: CGFloat? = nil) -> SwiftTickerItemDecorator & InitialRenderer { 113 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 114 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 115 | guard let last = last else { 116 | return 117 | } 118 | var frame = current.frame 119 | frame.origin.y = last.frame.maxY + (customOffset ?? offset) 120 | current.frame = frame 121 | } 122 | 123 | init(customOffset: CGFloat? = nil) { 124 | self.customOffset = customOffset 125 | } 126 | 127 | let customOffset: CGFloat? 128 | 129 | } 130 | return Anonymous(customOffset: customOffset) 131 | } 132 | 133 | /** 134 | InitialRenderer 135 | 136 | Aligns the items above each other 137 | 138 | This is used in the topToBottom Rendering option 139 | 140 | - Parameter customOffset: A custom offset to each item 141 | */ 142 | 143 | public static func alignItemsAboveEachOther(with customOffset: CGFloat? = nil) -> SwiftTickerItemDecorator & InitialRenderer { 144 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 145 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 146 | guard let last = last else { 147 | return 148 | } 149 | var frame = current.frame 150 | frame.origin.y = last.frame.minY - (customOffset ?? offset) - frame.height 151 | current.frame = frame 152 | } 153 | 154 | init(customOffset: CGFloat? = nil) { 155 | self.customOffset = customOffset 156 | } 157 | 158 | let customOffset: CGFloat? 159 | 160 | } 161 | return Anonymous(customOffset: customOffset) 162 | } 163 | 164 | /** 165 | InitialRenderer 166 | 167 | Aligns the first item at the right border so that it is not visible in the beginning 168 | 169 | This is used in the rightToLeft Rendering option 170 | 171 | - Parameter customOffset: A custom offset to the border 172 | - Parameter force: This forces this Initial Renderer to be executed 173 | */ 174 | public static func prepareAtRightOuterBorder(with customOffset: CGFloat? = nil, force: Bool = false) -> SwiftTickerItemDecorator & InitialRenderer { 175 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 176 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 177 | if last == nil || force { 178 | var frame = current.frame 179 | frame.origin.x = tickerView.frame.maxX + (customOffset ?? 0) 180 | current.frame = frame 181 | } 182 | } 183 | 184 | init(customOffset: CGFloat? = nil, force: Bool = false) { 185 | self.customOffset = customOffset 186 | self.force = force 187 | } 188 | 189 | let customOffset: CGFloat? 190 | private let force: Bool 191 | } 192 | return Anonymous(customOffset: customOffset, force: force) 193 | } 194 | 195 | /** 196 | InitialRenderer 197 | 198 | Aligns the first item at the right border so that it is visible in the beginning 199 | 200 | - Parameter customOffset: A custom offset to the border 201 | - Parameter force: This forces this Initial Renderer to be executed 202 | */ 203 | public static func prepareAtRightInnerBorder(with customOffset: CGFloat? = nil, force: Bool = false) -> SwiftTickerItemDecorator & InitialRenderer { 204 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 205 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 206 | if last == nil || force { 207 | var frame = current.frame 208 | frame.origin.x = tickerView.frame.maxX - frame.width - (customOffset ?? 0) 209 | current.frame = frame 210 | } 211 | } 212 | 213 | init(customOffset: CGFloat? = nil, force: Bool = false) { 214 | self.customOffset = customOffset 215 | self.force = force 216 | } 217 | 218 | let customOffset: CGFloat? 219 | private let force: Bool 220 | } 221 | return Anonymous(customOffset: customOffset, force: force) 222 | } 223 | 224 | /** 225 | InitialRenderer 226 | 227 | Aligns the first item at the left border so that it is not visible in the beginning 228 | 229 | This is used in the leftToRight Rendering option 230 | 231 | - Parameter customOffset: A custom offset to the border 232 | - Parameter force: This forces this Initial Renderer to be executed 233 | */ 234 | public static func prepareAtLeftOuterBorder(with customOffset: CGFloat? = nil, force: Bool = false) -> SwiftTickerItemDecorator & InitialRenderer { 235 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 236 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 237 | if last == nil || force { 238 | var frame = current.frame 239 | frame.origin.x = -frame.width - (customOffset ?? 0) 240 | current.frame = frame 241 | } 242 | } 243 | 244 | init(customOffset: CGFloat? = nil, force: Bool = false) { 245 | self.customOffset = customOffset 246 | self.force = force 247 | } 248 | 249 | let customOffset: CGFloat? 250 | private let force: Bool 251 | } 252 | return Anonymous(customOffset: customOffset, force: force) 253 | } 254 | 255 | /** 256 | InitialRenderer 257 | 258 | Aligns the first item at the left border so that it is visible in the beginning 259 | 260 | - Parameter customOffset: A custom offset to the border 261 | - Parameter force: This forces this Initial Renderer to be executed 262 | */ 263 | public static func prepareAtLeftInnerBorder(with customOffset: CGFloat? = nil, force: Bool = false) -> SwiftTickerItemDecorator & InitialRenderer { 264 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 265 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 266 | if last == nil || force { 267 | var frame = current.frame 268 | frame.origin.x = customOffset ?? offset 269 | current.frame = frame 270 | } 271 | } 272 | 273 | init(customOffset: CGFloat? = nil, force: Bool = false) { 274 | self.customOffset = customOffset 275 | self.force = force 276 | } 277 | 278 | let customOffset: CGFloat? 279 | private let force: Bool 280 | } 281 | return Anonymous(customOffset: customOffset, force: force) 282 | } 283 | 284 | /** 285 | InitialRenderer 286 | 287 | Aligns the first item at the bottom border so that it is not visible in the beginning 288 | 289 | This is used in the bottomToTop Rendering option 290 | 291 | - Parameter customOffset: A custom offset to the border 292 | - Parameter force: This forces this Initial Renderer to be executed 293 | */ 294 | public static func prepareAtBottomOuterBorder(with customOffset: CGFloat? = nil, force: Bool = false) -> SwiftTickerItemDecorator & InitialRenderer { 295 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 296 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 297 | if last == nil || force { 298 | var frame = current.frame 299 | frame.origin.y = tickerView.bounds.maxY + (customOffset ?? 0) 300 | current.frame = frame 301 | } 302 | } 303 | 304 | init(customOffset: CGFloat? = nil, force: Bool = false) { 305 | self.customOffset = customOffset 306 | self.force = force 307 | } 308 | 309 | let customOffset: CGFloat? 310 | private let force: Bool 311 | } 312 | return Anonymous(customOffset: customOffset, force: force) 313 | } 314 | 315 | /** 316 | InitialRenderer 317 | 318 | Aligns the first item at the left border so that it is visible in the beginning 319 | 320 | - Parameter customOffset: A custom offset to the border 321 | - Parameter force: This forces this Initial Renderer to be executed 322 | */ 323 | public static func prepareAtBottomInnerBorder(with customOffset: CGFloat? = nil, force: Bool = false) -> SwiftTickerItemDecorator & InitialRenderer { 324 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 325 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 326 | if last == nil || force { 327 | var frame = current.frame 328 | frame.origin.y = tickerView.frame.height - frame.height - (customOffset ?? 0) 329 | current.frame = frame 330 | } 331 | } 332 | 333 | init(customOffset: CGFloat? = nil, force: Bool = false) { 334 | self.customOffset = customOffset 335 | self.force = force 336 | } 337 | 338 | let customOffset: CGFloat? 339 | private let force: Bool 340 | } 341 | return Anonymous(customOffset: customOffset, force: force) 342 | } 343 | 344 | /** 345 | InitialRenderer 346 | 347 | Aligns the first item at the top border so that it is not visible in the beginning 348 | 349 | This is used in the topToBottom Rendering option 350 | 351 | - Parameter customOffset: A custom offset to the border 352 | - Parameter force: This forces this Initial Renderer to be executed 353 | */ 354 | public static func prepareAtTopOuterBorder(with customOffset: CGFloat? = nil, force: Bool = false) -> SwiftTickerItemDecorator & InitialRenderer { 355 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 356 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 357 | if last == nil || force { 358 | var frame = current.frame 359 | frame.origin.y = -frame.height + (customOffset ?? 0) 360 | current.frame = frame 361 | } 362 | } 363 | 364 | init(customOffset: CGFloat? = nil, force: Bool = false) { 365 | self.customOffset = customOffset 366 | self.force = force 367 | } 368 | 369 | let customOffset: CGFloat? 370 | private let force: Bool 371 | } 372 | return Anonymous(customOffset: customOffset, force: force) 373 | } 374 | 375 | /** 376 | InitialRenderer 377 | 378 | Aligns the first item at top border so that it is visible in the beginning 379 | 380 | - Parameter customOffset: A custom offset to the border 381 | - Parameter force: This forces this Initial Renderer to be executed 382 | */ 383 | public static func prepareAtTopInnerBorder(with customOffset: CGFloat? = nil, force: Bool = false) -> SwiftTickerItemDecorator & InitialRenderer { 384 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 385 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 386 | if last == nil || force { 387 | var frame = current.frame 388 | frame.origin.y = customOffset ?? 0 389 | current.frame = frame 390 | } 391 | } 392 | 393 | init(customOffset: CGFloat? = nil, force: Bool = false) { 394 | self.customOffset = customOffset 395 | self.force = force 396 | } 397 | 398 | let customOffset: CGFloat? 399 | private let force: Bool 400 | } 401 | return Anonymous(customOffset: customOffset, force: force) 402 | } 403 | 404 | /** 405 | InitialRenderer 406 | 407 | Aligns the items vertically centered in the view 408 | 409 | This is used in the leftToRight and rightToLeft Rendering option 410 | 411 | - Parameter customOffset: A custom offset from the vertical center 412 | */ 413 | public static func centerVertical(with offset: CGFloat? = nil) -> SwiftTickerItemDecorator & InitialRenderer { 414 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 415 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 416 | var frame = current.frame 417 | frame.origin.y = ((tickerView.frame.height - frame.height) / 2) + (customOffset ?? 0) 418 | current.frame = frame 419 | } 420 | 421 | init(customOffset: CGFloat? = nil) { 422 | self.customOffset = customOffset 423 | } 424 | 425 | let customOffset: CGFloat? 426 | } 427 | return Anonymous(customOffset: offset) 428 | } 429 | 430 | /** 431 | InitialRenderer 432 | 433 | Aligns the items horizontally centered in the view 434 | 435 | This is used in the topToBottom and bottomToTop Rendering option 436 | 437 | - Parameter customOffset: A custom offset from the horizontal center 438 | */ 439 | public static func centerHorizontal(with offset: CGFloat? = nil) -> SwiftTickerItemDecorator & InitialRenderer { 440 | struct Anonymous: SwiftTickerItemDecorator, InitialRenderer { 441 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) { 442 | var frame = current.frame 443 | frame.origin.x = ((tickerView.frame.width - frame.width) / 2) + (customOffset ?? 0) 444 | current.frame = frame 445 | } 446 | 447 | init(customOffset: CGFloat? = nil) { 448 | self.customOffset = customOffset 449 | } 450 | 451 | let customOffset: CGFloat? 452 | } 453 | return Anonymous(customOffset: offset) 454 | } 455 | 456 | // /** 457 | // UpdateRenderer 458 | // 459 | // Updates the x position of the view 460 | // 461 | // This is used in the leftToRight and rightToLeft Rendering option 462 | // 463 | // - Parameter function: Use an oparator eg (+, -, *, /,...) 464 | // */ 465 | // public static func accellerateX(_ function: @escaping (CGFloat, CGFloat, to finalSpeed: ) -> CGFloat) -> SwiftTickerItemDecorator & UpdateRenderer { 466 | // struct Anonymous: SwiftTickerItemDecorator, UpdateRenderer { 467 | // func updateWith(current: UIView, offset: CGFloat) { 468 | // var frame = current.frame 469 | // frame.origin.x = function(frame.origin.x, offset) 470 | // current.frame = frame 471 | // } 472 | // 473 | // init(_ function: @escaping (CGFloat, CGFloat) -> CGFloat) { 474 | // self.function = function 475 | // } 476 | // 477 | // let function: (CGFloat, CGFloat) -> CGFloat 478 | // } 479 | // return Anonymous(function) 480 | // } 481 | 482 | // MARK: - Update Renderer 483 | 484 | /** 485 | UpdateRendererClosure 486 | 487 | Used in the initialRendere(closure:) method 488 | 489 | - Parameter node: the node view, that shall be updated 490 | - Parameter offset: the calculated offset, you can use this to calculate the next position or implement your own update position logic 491 | */ 492 | public typealias UpdateRendererClosure = ((UIView, CGFloat) -> Void) 493 | 494 | /** 495 | UpdateRenderer 496 | 497 | Use this option, if you want the Ticker Nodes to be completely customizable updated 498 | 499 | - Parameter closure: InitialRendererClosure 500 | */ 501 | public static func updateRenderer(closure: @escaping UpdateRendererClosure) -> SwiftTickerItemDecorator & UpdateRenderer { 502 | struct Anonymous: SwiftTickerItemDecorator, UpdateRenderer { 503 | func updateWith(current: UIView, offset: CGFloat) { 504 | closure(current, offset) 505 | } 506 | 507 | init(closure: @escaping UpdateRendererClosure) { 508 | self.closure = closure 509 | } 510 | 511 | let closure: UpdateRendererClosure 512 | } 513 | return Anonymous(closure: closure) 514 | } 515 | 516 | /** 517 | UpdateRenderer 518 | 519 | Updates the x position of the view 520 | 521 | This is used in the leftToRight and rightToLeft Rendering option 522 | 523 | - Parameter function: Use an oparator eg (+, -, *, /,...) 524 | */ 525 | public static func updateX(_ function: @escaping (CGFloat, CGFloat) -> CGFloat) -> SwiftTickerItemDecorator & UpdateRenderer { 526 | struct Anonymous: SwiftTickerItemDecorator, UpdateRenderer { 527 | func updateWith(current: UIView, offset: CGFloat) { 528 | var frame = current.frame 529 | frame.origin.x = function(current.frame.origin.x, offset) 530 | current.frame = frame 531 | } 532 | 533 | init(_ function: @escaping (CGFloat, CGFloat) -> CGFloat) { 534 | self.function = function 535 | } 536 | 537 | let function: (CGFloat, CGFloat) -> CGFloat 538 | } 539 | return Anonymous(function) 540 | } 541 | 542 | /** 543 | UpdateRenderer 544 | 545 | Updates the y position of the view 546 | 547 | This is used in the topToBottom and bottomToTop Rendering option 548 | 549 | - Parameter function: Use an oparator eg (+, -, *, /,...) 550 | */ 551 | public static func updateY(_ function: @escaping (CGFloat, CGFloat) -> CGFloat) -> SwiftTickerItemDecorator & UpdateRenderer { 552 | struct Anonymous: SwiftTickerItemDecorator, UpdateRenderer { 553 | func updateWith(current: UIView, offset: CGFloat) { 554 | var frame = current.frame 555 | frame.origin.y = function(current.frame.origin.y, offset) 556 | current.frame = frame 557 | } 558 | 559 | init(_ function: @escaping (CGFloat, CGFloat) -> CGFloat) { 560 | self.function = function 561 | } 562 | 563 | let function: (CGFloat, CGFloat) -> CGFloat 564 | } 565 | return Anonymous(function) 566 | } 567 | } 568 | -------------------------------------------------------------------------------- /Sources/SwiftTickerView/SwiftTickerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftTickerView.swift 3 | // Pods 4 | // 5 | // Created by Martin Eberl on 15.08.17. 6 | // 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol SwiftTickerProviderProtocol { 12 | var hasContent: Bool { get } 13 | var nextObject: Any { get } 14 | } 15 | 16 | public protocol SwiftTickerDelegate: class { 17 | func tickerView(willResume ticker: SwiftTickerView) 18 | func tickerView(willStart ticker: SwiftTickerView) 19 | func tickerView(willStop ticker: SwiftTickerView) 20 | func tickerView(didPress view: UIView, content: Any?) 21 | // func tickerViewDidStartDragging(_ ticker: SwiftTickerView) 22 | // func tickerViewDidEndDragging(_ ticker: SwiftTickerView) 23 | } 24 | 25 | public protocol SwiftTickerViewProvider { 26 | func tickerView(_ tickerView: SwiftTickerView, prepareSeparator separator: UIView) 27 | func tickerView(_ tickerView: SwiftTickerView, viewFor: Any) -> (UIView, reuseIdentifier: String?) 28 | } 29 | 30 | public protocol SwiftTickerContentRenderer { 31 | func tickerView(_ tickerView: SwiftTickerView, render nodeView: UIView, with identifier: String) 32 | func tickerViewUpdate(_ tickerView: SwiftTickerView, render nodeView: UIView, offset: CGFloat) 33 | func tickerViewShouldAddNext(_ tickerView: SwiftTickerView, current nodeView: UIView) -> Bool 34 | func tickerViewShouldRemove(_ tickerView: SwiftTickerView, nodeView: UIView) -> Bool 35 | } 36 | 37 | public protocol InitialRenderer { 38 | func updateWith(current: UIView, last: UIView?, tickerView: SwiftTickerView, offset: CGFloat) 39 | } 40 | 41 | public protocol UpdateRenderer { 42 | func updateWith(current: UIView, offset: CGFloat) 43 | } 44 | 45 | public protocol Condition { 46 | func meets(nodeView: UIView, tickerView: SwiftTickerView) -> Bool 47 | } 48 | 49 | public enum ReturnBehavior { 50 | case `continue` 51 | case `return` 52 | case `break` 53 | } 54 | 55 | public typealias Action = (Renderer, SwiftTickerView) -> ReturnBehavior 56 | 57 | public protocol SwiftTickerItemDecorator { } 58 | 59 | open class SwiftTickerView: UIView { 60 | private let separatorIdentifier = "SeparatorIdentifier" 61 | private let dontReuseIdentifier = "DontReuseIdentifier" 62 | 63 | public enum Decorator: SwiftTickerItemDecorator { 64 | case ignoreFirstSeparator 65 | case draggingEnabled 66 | } 67 | 68 | private var isDragging = false { 69 | didSet { 70 | guard oldValue != isDragging else { 71 | return 72 | } 73 | if isDragging { 74 | wasRunningBeforeDragging = isRunning 75 | stop() 76 | // tickerDelegate?.tickerViewDidStartDragging(self) 77 | } else { 78 | if wasRunningBeforeDragging { 79 | resume() 80 | } 81 | // tickerDelegate?.tickerViewDidEndDragging(self) 82 | } 83 | } 84 | } 85 | 86 | private var decorators = [Decorator]() 87 | 88 | /** 89 | Assign a custom renderer to allow the content to be rendered on the ticker view. 90 | Default is rightToLeft 91 | */ 92 | public var render: SwiftTickerContentRenderer = Renderer.rightToLeft { 93 | didSet { 94 | guard isRunning else { 95 | return 96 | } 97 | stop() 98 | resume() 99 | } 100 | } 101 | 102 | /** 103 | Set a custom pixelPerSeconds to increase or decrease the update interval of the content. 104 | Default is 60 105 | WARNING: The more you increase this value, the more it looks stuttering 106 | */ 107 | public var pixelPerSecond: CGFloat = 60 { 108 | didSet { 109 | guard pixelPerSecond > 0 else { 110 | stop() 111 | return 112 | } 113 | renewDisplayLink() 114 | } 115 | } 116 | 117 | /** 118 | Asign a custom separator 119 | */ 120 | public var separator: String? 121 | private var separatorView: UIView.Type? 122 | private var separatorNib: UINib? 123 | 124 | /** 125 | Use this as offset between the items rendered on the ticker view 126 | Default is 8 pixel 127 | */ 128 | public var distanceBetweenNodes: CGFloat = 8 129 | 130 | /** 131 | Determine if the tickerview is rendering the content or has been stopped 132 | */ 133 | private var wasRunningBeforeDragging = false 134 | public private(set) var isRunning = false 135 | 136 | private var lastNodeWasSeparator = false 137 | private var displayLink: CADisplayLink? 138 | private var nodeViews = [(key: String, view: UIView, content: Any?)]() 139 | private var reusableSeparatorViews = [(key: String, view: UIView)]() 140 | private var reusableNodeViews = [(key: String, view: UIView)]() 141 | private var registeredNodeViews = [String: Any]() 142 | 143 | /** 144 | Asign a custom content provider. 145 | */ 146 | public var contentProvider: SwiftTickerProviderProtocol? 147 | /** 148 | Asign a custom view provider 149 | */ 150 | public var viewProvider: SwiftTickerViewProvider? 151 | /** 152 | Asign a custom delegate 153 | */ 154 | public weak var tickerDelegate: SwiftTickerDelegate? 155 | 156 | @IBOutlet public weak var button: UIButton! 157 | 158 | open override func awakeFromNib() { 159 | super.awakeFromNib() 160 | 161 | setupUI() 162 | } 163 | 164 | required public init?(coder aDecoder: NSCoder) { 165 | super.init(coder: aDecoder) 166 | } 167 | 168 | public override init(frame: CGRect) { 169 | super.init(frame: frame) 170 | 171 | setupUI() 172 | } 173 | 174 | deinit { 175 | displayLink?.invalidate() 176 | } 177 | 178 | /** 179 | Adds a decorator to the tickerview 180 | 181 | - Parameter decorator: a protocol to customize the view behavior 182 | */ 183 | open func add(decorator: Decorator) { 184 | guard !decorators.contains(decorator) else { 185 | return 186 | } 187 | 188 | decorators.append(decorator) 189 | apply(decorator: decorator) 190 | } 191 | 192 | /** 193 | Starts the ticker view rendering 194 | */ 195 | open func start() { 196 | tickerDelegate?.tickerView(willStart: self) 197 | if isRunning { 198 | renewDisplayLink() 199 | } else { 200 | resume() 201 | } 202 | } 203 | 204 | /** 205 | Stops the ticker from rendering the content 206 | */ 207 | open func stop() { 208 | guard isRunning else { 209 | return 210 | } 211 | 212 | tickerDelegate?.tickerView(willStop: self) 213 | isRunning = false 214 | displayLink?.isPaused = true 215 | } 216 | 217 | /** 218 | Sets a custom separator view that will be created during runtime 219 | 220 | - Parameter separator: custom separator view type 221 | */ 222 | open func registerView(for separator: UIView.Type) { 223 | separatorView = separator 224 | } 225 | 226 | /** 227 | Sets a separator nip that will be created during runtime 228 | 229 | - Parameter separator: custom separator nib 230 | */ 231 | open func registerNib(for separator: UINib) { 232 | separatorNib = separator 233 | } 234 | 235 | /** 236 | Register a nodeview view type for a specific identifier, that can be dequed during runtime 237 | 238 | - Parameter nodeView: custom node view type 239 | 240 | - Parameter identifier: reused identifier 241 | */ 242 | open func registerNodeView(_ nodeView: UIView.Type, for identifier: String) { 243 | registeredNodeViews[identifier] = nodeView 244 | } 245 | 246 | /** 247 | Register a nodeview view nib for a specific identifier, that can be dequed during runtime 248 | 249 | - Parameter nodeView: custom node view nib 250 | 251 | - Parameter identifier: reused identifier 252 | */ 253 | open func registerNodeViewNib(_ nodeView: UINib, for identifier: String) { 254 | registeredNodeViews[identifier] = nodeView 255 | } 256 | 257 | /** 258 | Returns a dequed separator. If there is nothing to deque and a 'separator' e.g. '+++' is given, a label is being instantiated of if a 'separatorView' type is given, it will be instantiated of if a 'separatorNib' is given, the nib will be instantiated 259 | 260 | - Return: dequed or created separator view 261 | */ 262 | open func dequeueReusableSeparator() -> UIView? { 263 | if let index = reusableSeparatorViews.firstIndex(where: { $0.key == separatorIdentifier }) { 264 | let view = reusableSeparatorViews[index].view 265 | reusableSeparatorViews.remove(at: index) 266 | return view 267 | } else if let separator = separator { 268 | let label = UILabel(frame: CGRect(x: 0, y: 0, width: 1, height: 1)) 269 | label.text = separator 270 | label.numberOfLines = 1 271 | label.sizeToFit() 272 | return label 273 | } else if let separatorView = separatorView { 274 | return separatorView.init(frame: CGRect(x: 0, y: 0, width: 1, height: 1)) 275 | } else if let separatorNib = separatorNib { 276 | return separatorNib.instantiate(withOwner: nil, options: nil).first as? UIView 277 | } 278 | return nil 279 | } 280 | 281 | /** 282 | Returns a dequed node view by the given identifier. If there is nothing to deque and a 'nodeView' type is given, it will be instantiated of if a nib is given, the nib will be instantiated 283 | 284 | - Return: dequed or created separator view 285 | */ 286 | open func dequeReusableNodeView(for identifier: String) -> UIView? { 287 | if let index = reusableNodeViews.firstIndex(where: { $0.key == identifier }) { 288 | let view = reusableNodeViews[index].view 289 | reusableNodeViews.remove(at: index) 290 | return view 291 | } 292 | 293 | guard let any = registeredNodeViews[identifier] else { 294 | return nil 295 | } 296 | 297 | if let anyclass = any as? UIView.Type { 298 | return anyclass.init(frame: CGRect(x: 0, y: 0, width: 1, height: 1)) 299 | } else if let nib = any as? UINib { 300 | return nib.instantiate(withOwner: nil, options: nil).first as? UIView 301 | } 302 | 303 | return nil 304 | } 305 | 306 | /** 307 | Clears all nodes from the ticker view. If the view is still running, it will instantly start to render the content if provided 308 | 309 | WARNING: use carefully. If the ticker view is still running, this may look edgy 310 | */ 311 | open func reloadData() { 312 | nodeViews.forEach { 313 | removeNode($0.view) 314 | } 315 | decorators.forEach { [weak self] decorator in 316 | self?.apply(decorator: decorator) 317 | } 318 | while addNewNodeIfNeeded() { 319 | } 320 | } 321 | 322 | //MARK: - Private 323 | 324 | private func setupUI() { 325 | NotificationCenter.default.addObserver(self, 326 | selector: #selector(application(didBecomeActive:)), 327 | name: UIApplication.didBecomeActiveNotification, 328 | object: nil) 329 | 330 | NotificationCenter.default.addObserver(self, 331 | selector: #selector(application(willResignActive:)), 332 | name: UIApplication.willResignActiveNotification, 333 | object: nil) 334 | 335 | if button == nil { 336 | let button = UIButton(frame: bounds) 337 | addSubview(button) 338 | self.button = button 339 | } 340 | 341 | button.addTarget(self, 342 | action: #selector(button(touchedDown:)), 343 | for: .touchDown) 344 | button.addTarget(self, 345 | action: #selector(button(touchedUpInside:with:)), 346 | for: .touchUpInside) 347 | button.addTarget(self, 348 | action: #selector(button(touchedUpOutside:)), 349 | for: .touchUpOutside) 350 | 351 | let panGestureRecognizer = UIPanGestureRecognizer(target: self, 352 | action: #selector(panDetected(_:))) 353 | button.addGestureRecognizer(panGestureRecognizer) 354 | } 355 | 356 | @objc private func panDetected(_ sender: UIPanGestureRecognizer) { 357 | if !isDragging { 358 | isDragging = true 359 | } 360 | // 361 | // switch sender.state { 362 | // case .changed: 363 | // let velocity = sender.velocity(in: self) 364 | // case .ended: 365 | // } 366 | // 367 | 368 | } 369 | 370 | @objc private func application(willResignActive application: UIApplication) { 371 | stop() 372 | } 373 | 374 | @objc private func application(didBecomeActive application: UIApplication) { 375 | start() 376 | } 377 | 378 | @objc private func button(touchedDown button: UIButton) { 379 | stop() 380 | } 381 | 382 | @objc private func button(touchedUpInside button: UIButton, with event: UIEvent) { 383 | guard let origin = event.allTouches?.first?.location(in: self) else { 384 | return 385 | } 386 | let rect = CGRect(origin: origin, size: CGSize(width: 1, height: 1)) 387 | if let view = nodeViews.first(where: { 388 | $0.key != separatorIdentifier && $0.view.frame.intersects(rect) 389 | }) { 390 | tickerDelegate?.tickerView(didPress: view.view, content: view.content) 391 | } 392 | start() 393 | } 394 | 395 | @objc private func button(touchedUpOutside button: UIButton) { 396 | resume() 397 | isDragging = false 398 | } 399 | 400 | private func renewDisplayLink() { 401 | guard pixelPerSecond > 0 else { 402 | return 403 | } 404 | guard displayLink == nil else { 405 | displayLink?.isPaused = false 406 | if #available(iOS 10.0, tvOS 10.0, *) { 407 | displayLink?.preferredFramesPerSecond = Int(pixelPerSecond) 408 | } else { 409 | displayLink?.frameInterval = Int(pixelPerSecond/60) 410 | } 411 | return 412 | } 413 | 414 | displayLink = CADisplayLink(target: self, 415 | selector: #selector(rendering)) 416 | if #available(iOS 10.0, tvOS 10.0, *) { 417 | displayLink?.preferredFramesPerSecond = Int(pixelPerSecond) 418 | } else { 419 | displayLink?.frameInterval = Int(pixelPerSecond/60) 420 | } 421 | displayLink?.add(to: .main, forMode: RunLoop.Mode.common) 422 | } 423 | 424 | private func apply(decorator: Decorator) { 425 | switch decorator { 426 | case .ignoreFirstSeparator: 427 | if !isRunning { 428 | lastNodeWasSeparator = true 429 | } 430 | case .draggingEnabled: 431 | break 432 | } 433 | } 434 | 435 | private func resume() { 436 | guard !isRunning, 437 | let contentProvider = contentProvider, 438 | contentProvider.hasContent else { return } 439 | 440 | tickerDelegate?.tickerView(willResume: self) 441 | isRunning = true 442 | 443 | renewDisplayLink() 444 | } 445 | 446 | @objc private func rendering() { 447 | guard isRunning else { 448 | return 449 | } 450 | updateTickerNodeViewPosition() 451 | } 452 | 453 | private func update(node: UIView, offset: CGFloat) { 454 | render.tickerViewUpdate(self, render: node, offset: offset) 455 | } 456 | 457 | private func viewIsOutOfBounds(_ nodeView: UIView?) -> Bool { 458 | guard let nodeView = nodeView else { 459 | return false 460 | } 461 | 462 | return render.tickerViewShouldRemove(self, nodeView: nodeView) 463 | } 464 | 465 | private var shouldAddView: Bool { 466 | guard let nodeView = nodeViews.last else { 467 | return true 468 | } 469 | 470 | return render.tickerViewShouldAddNext(self, current: nodeView.view) 471 | } 472 | 473 | private func removeNodeIfNeeded(_ nodeView: UIView?) { 474 | guard let nodeView = nodeView else { return } 475 | 476 | if viewIsOutOfBounds(nodeView) { 477 | removeNode(nodeView) 478 | } 479 | } 480 | 481 | private func removeNode(_ nodeView: UIView) { 482 | if let index = nodeViews.firstIndex(where: { $0.view === nodeView }) { 483 | let nodeView = nodeViews[index] 484 | if nodeView.key == separatorIdentifier { 485 | reusableSeparatorViews.append((nodeView.key, nodeView.view)) 486 | } else if nodeView.key != dontReuseIdentifier { 487 | reusableNodeViews.append((nodeView.key, nodeView.view)) 488 | } 489 | nodeViews.remove(at: index) 490 | nodeView.view.removeFromSuperview() 491 | } 492 | } 493 | 494 | @discardableResult private func addNewNodeIfNeeded() -> Bool { 495 | guard shouldAddView else { 496 | return false 497 | } 498 | addNode() 499 | return true 500 | } 501 | 502 | private var hasSepatator: Bool { 503 | return separator != nil || separatorNib != nil || separatorView != nil 504 | } 505 | 506 | private func addNode() { 507 | if hasSepatator && !lastNodeWasSeparator { 508 | lastNodeWasSeparator = true 509 | let separator = dequeueReusableSeparator() 510 | if let separator = separator { 511 | viewProvider?.tickerView(self, prepareSeparator: separator) 512 | addNode(separator, 513 | for: separatorIdentifier, 514 | content: nil) 515 | } 516 | return 517 | } 518 | lastNodeWasSeparator = false 519 | 520 | if let content = contentProvider?.nextObject, 521 | let nodeView = viewProvider?.tickerView(self, viewFor: content) { 522 | addNode(nodeView.0, 523 | for: nodeView.reuseIdentifier ?? dontReuseIdentifier, 524 | content: content) 525 | } 526 | } 527 | 528 | private func addNode(_ nodeView: UIView?, for identifier: String, content: Any?) { 529 | guard let nodeView = nodeView else { 530 | return 531 | } 532 | 533 | addSubview(nodeView) 534 | render.tickerView(self, render: nodeView, with: identifier) 535 | nodeViews.append((identifier, nodeView, content)) 536 | } 537 | 538 | private var framesPerSecond: Int { 539 | guard let displayLink = displayLink, 540 | displayLink.duration > 0 else { 541 | return 0 542 | } 543 | return Int(round(1000 / displayLink.duration)/1000) 544 | } 545 | 546 | fileprivate func updateTickerNodeViewPosition() { 547 | let offset = pixelPerSecond / CGFloat(framesPerSecond) 548 | guard offset != CGFloat.infinity, offset != -CGFloat.infinity else { 549 | return 550 | } 551 | nodeViews.forEach { [weak self] in 552 | self?.update(node: $0.view, offset: offset) 553 | } 554 | 555 | removeNodeIfNeeded(nodeViews.first?.view) 556 | addNewNodeIfNeeded() 557 | } 558 | } 559 | -------------------------------------------------------------------------------- /SwiftTickerView.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint SwiftTickerView.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'SwiftTickerView' 11 | s.version = '1.5.0' 12 | s.summary = 'A simple news ticker view' 13 | s.swift_version = '4.2' 14 | 15 | s.description = <<-DESC 16 | A swift ticker, written in swift. The one, with those '+++' separators ;) 17 | DESC 18 | 19 | s.homepage = 'https://github.com/EMart86/SwiftTickerView' 20 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 21 | s.license = { :type => 'MIT', :file => 'LICENSE' } 22 | s.author = { 'Martin Eberl' => 'eberl_ma@gmx.at' } 23 | s.source = { :git => 'https://github.com/EMart86/SwiftTickerView.git', :tag => s.version.to_s } 24 | # s.social_media_url = 'https://twitter.com/' 25 | 26 | s.ios.deployment_target = '9.0' 27 | s.tvos.deployment_target = '9.0' 28 | 29 | s.source_files = 'Sources/SwiftTickerView/*' 30 | end 31 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------