|
|
@ -1,5 +1,10 @@
|
|
|
|
|
|
|
|
// Grabbed from: https://github.com/cbpowell/MarqueeLabel-Swift/blob/cd331f3cfc3f9d7114ffa5aa4f243f1d5eda9d0d/Classes/MarqueeLabel.swift
|
|
|
|
|
|
|
|
// License: MIT License
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
|
|
|
// MarqueeLabel.swift
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Created by Charles Powell on 8/6/14.
|
|
|
|
|
|
|
|
// Copyright (c) 2015 Charles Powell. All rights reserved.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
import UIKit
|
|
|
@ -327,11 +332,13 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
The length of delay in seconds that the label pauses at the completion of a scroll.
|
|
|
|
The length of delay in seconds that the label pauses at the completion of a scroll.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@IBInspectable open var animationDelay: CGFloat = 1.0
|
|
|
|
@IBInspectable open var animationDelay: CGFloat = 1.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** The read-only duration of the scroll animation (not including delay).
|
|
|
|
/** The read-only duration of the scroll animation (not including delay).
|
|
|
|
|
|
|
|
|
|
|
|
The value of this property is calculated from the value set to the `speed` property. If a .duration value is
|
|
|
|
The value of this property is calculated from the value set to the `speed` property. If a .duration value is
|
|
|
@ -412,6 +419,7 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
MarqueeLabel.notifyController(controller, message: .Animate)
|
|
|
|
MarqueeLabel.notifyController(controller, message: .Animate)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// MARK: - Initialization
|
|
|
|
// MARK: - Initialization
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -588,7 +596,7 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
awayOffset = 0.0
|
|
|
|
awayOffset = 0.0
|
|
|
|
|
|
|
|
|
|
|
|
// Remove an additional sublabels (for continuous types)
|
|
|
|
// Remove an additional sublabels (for continuous types)
|
|
|
|
repliLayer?.instanceCount = 1
|
|
|
|
repliLayer?.instanceCount = 1;
|
|
|
|
|
|
|
|
|
|
|
|
// Set the sublabel frame to calculated labelFrame
|
|
|
|
// Set the sublabel frame to calculated labelFrame
|
|
|
|
sublabel.frame = labelFrame
|
|
|
|
sublabel.frame = labelFrame
|
|
|
@ -693,11 +701,13 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
ScrollStep(timeStep: animationDuration, timingFunction: animationCurve, // Away position, using animationCurve transition, with only leading edge faded in
|
|
|
|
ScrollStep(timeStep: animationDuration, timingFunction: animationCurve, // Away position, using animationCurve transition, with only leading edge faded in
|
|
|
|
position: .away, edgeFades: .leading),
|
|
|
|
position: .away, edgeFades: .leading),
|
|
|
|
ScrollStep(timeStep: 60*60*24*365.0, // "Delay" at away, for huge time to effectie stay at away permanently
|
|
|
|
ScrollStep(timeStep: 60*60*24*365.0, // "Delay" at away, for huge time to effectie stay at away permanently
|
|
|
|
position: .away, edgeFades: .leading)
|
|
|
|
position: .away, edgeFades: .leading),
|
|
|
|
]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Configure gradient for current condition
|
|
|
|
// Configure gradient for current condition
|
|
|
|
applyGradientMask(fadeLength, animated: !self.labelize)
|
|
|
|
applyGradientMask(fadeLength, animated: !self.labelize)
|
|
|
|
|
|
|
|
|
|
|
@ -832,10 +842,10 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
fader = nil
|
|
|
|
fader = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#else
|
|
|
|
fader = nil
|
|
|
|
fader = nil;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
scrollCompletionBlock = { [weak self] (finished: Bool) -> Void in
|
|
|
|
scrollCompletionBlock = { [weak self] (finished: Bool) -> () in
|
|
|
|
guard finished else {
|
|
|
|
guard finished else {
|
|
|
|
// Do not continue into the next loop
|
|
|
|
// Do not continue into the next loop
|
|
|
|
return
|
|
|
|
return
|
|
|
@ -993,7 +1003,7 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
animation.keyTimes = fadeKeyTimes
|
|
|
|
animation.keyTimes = fadeKeyTimes
|
|
|
|
animation.timingFunctions = fadeTimingFunctions
|
|
|
|
animation.timingFunctions = fadeTimingFunctions
|
|
|
|
|
|
|
|
|
|
|
|
return (anim: animation, duration: max(totalTime, totalDuration))
|
|
|
|
return (anim: animation, duration: max(totalTime,totalDuration))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private func applyGradientMask(_ fadeLength: CGFloat, animated: Bool, firstStep: MarqueeStep? = nil) {
|
|
|
|
private func applyGradientMask(_ fadeLength: CGFloat, animated: Bool, firstStep: MarqueeStep? = nil) {
|
|
|
@ -1122,6 +1132,7 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// MARK: - Private details
|
|
|
|
// MARK: - Private details
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -1151,8 +1162,8 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
|
|
|
|
|
|
|
|
// Draw only background color
|
|
|
|
// Draw only background color
|
|
|
|
if let bgColor = backgroundColor {
|
|
|
|
if let bgColor = backgroundColor {
|
|
|
|
ctx.setFillColor(bgColor.cgColor)
|
|
|
|
ctx.setFillColor(bgColor.cgColor);
|
|
|
|
ctx.fill(layer.bounds)
|
|
|
|
ctx.fill(layer.bounds);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1191,6 +1202,7 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// MARK: - Label Control
|
|
|
|
// MARK: - Label Control
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -1561,6 +1573,7 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// MARK: - Support
|
|
|
|
// MARK: - Support
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -1579,6 +1592,7 @@ open class MarqueeLabel: UILabel, CAAnimationDelegate {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// MARK: - Support
|
|
|
|
// MARK: - Support
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -1588,6 +1602,7 @@ public protocol MarqueeStep {
|
|
|
|
var edgeFades: EdgeFade { get }
|
|
|
|
var edgeFades: EdgeFade { get }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
`ScrollStep` types define the label position at a specified time delta since the last `ScrollStep` step, as well as
|
|
|
|
`ScrollStep` types define the label position at a specified time delta since the last `ScrollStep` step, as well as
|
|
|
|
the animation curve to that position and edge fade state at the position
|
|
|
|
the animation curve to that position and edge fade state at the position
|
|
|
@ -1646,6 +1661,7 @@ public struct ScrollStep: MarqueeStep {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
`FadeStep` types allow additional edge fade state definitions, around the states defined by the `ScrollStep` steps of
|
|
|
|
`FadeStep` types allow additional edge fade state definitions, around the states defined by the `ScrollStep` steps of
|
|
|
|
a sequence. `FadeStep` steps are defined by the time delta to the preceding or subsequent `ScrollStep` step and the timing
|
|
|
|
a sequence. `FadeStep` steps are defined by the time delta to the preceding or subsequent `ScrollStep` step and the timing
|
|
|
@ -1690,21 +1706,21 @@ public struct FadeStep: MarqueeStep {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public struct EdgeFade: OptionSet {
|
|
|
|
public struct EdgeFade : OptionSet {
|
|
|
|
public let rawValue: Int
|
|
|
|
public let rawValue: Int
|
|
|
|
public static let leading = EdgeFade(rawValue: 1 << 0)
|
|
|
|
public static let leading = EdgeFade(rawValue: 1 << 0)
|
|
|
|
public static let trailing = EdgeFade(rawValue: 1 << 1)
|
|
|
|
public static let trailing = EdgeFade(rawValue: 1 << 1)
|
|
|
|
|
|
|
|
|
|
|
|
public init(rawValue: Int) {
|
|
|
|
public init(rawValue: Int) {
|
|
|
|
self.rawValue = rawValue
|
|
|
|
self.rawValue = rawValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Define helpful typealiases
|
|
|
|
// Define helpful typealiases
|
|
|
|
fileprivate typealias MLAnimationCompletionBlock = (_ finished: Bool) -> Void
|
|
|
|
fileprivate typealias MLAnimationCompletionBlock = (_ finished: Bool) -> ()
|
|
|
|
fileprivate typealias MLAnimation = (anim: CAKeyframeAnimation, duration: CGFloat)
|
|
|
|
fileprivate typealias MLAnimation = (anim: CAKeyframeAnimation, duration: CGFloat)
|
|
|
|
|
|
|
|
|
|
|
|
private class GradientSetupAnimation: CABasicAnimation {
|
|
|
|
fileprivate class GradientSetupAnimation: CABasicAnimation {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fileprivate extension UIResponder {
|
|
|
|
fileprivate extension UIResponder {
|
|
|
@ -1780,14 +1796,14 @@ fileprivate extension CAMediaTimingFunction {
|
|
|
|
return t0
|
|
|
|
return t0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func YforCurveAt(_ t: CGFloat, controlPoints: [CGPoint]) -> CGFloat {
|
|
|
|
func YforCurveAt(_ t: CGFloat, controlPoints:[CGPoint]) -> CGFloat {
|
|
|
|
let P0 = controlPoints[0]
|
|
|
|
let P0 = controlPoints[0]
|
|
|
|
let P1 = controlPoints[1]
|
|
|
|
let P1 = controlPoints[1]
|
|
|
|
let P2 = controlPoints[2]
|
|
|
|
let P2 = controlPoints[2]
|
|
|
|
let P3 = controlPoints[3]
|
|
|
|
let P3 = controlPoints[3]
|
|
|
|
|
|
|
|
|
|
|
|
// Per http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves
|
|
|
|
// Per http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves
|
|
|
|
let y0 = (pow((1.0 - t), 3.0) * P0.y)
|
|
|
|
let y0 = (pow((1.0 - t),3.0) * P0.y)
|
|
|
|
let y1 = (3.0 * pow(1.0 - t, 2.0) * t * P1.y)
|
|
|
|
let y1 = (3.0 * pow(1.0 - t, 2.0) * t * P1.y)
|
|
|
|
let y2 = (3.0 * (1.0 - t) * pow(t, 2.0) * P2.y)
|
|
|
|
let y2 = (3.0 * (1.0 - t) * pow(t, 2.0) * P2.y)
|
|
|
|
let y3 = (pow(t, 3.0) * P3.y)
|
|
|
|
let y3 = (pow(t, 3.0) * P3.y)
|
|
|
@ -1803,7 +1819,7 @@ fileprivate extension CAMediaTimingFunction {
|
|
|
|
|
|
|
|
|
|
|
|
// Per http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves
|
|
|
|
// Per http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves
|
|
|
|
|
|
|
|
|
|
|
|
let x0 = (pow((1.0 - t), 3.0) * P0.x)
|
|
|
|
let x0 = (pow((1.0 - t),3.0) * P0.x)
|
|
|
|
let x1 = (3.0 * pow(1.0 - t, 2.0) * t * P1.x)
|
|
|
|
let x1 = (3.0 * pow(1.0 - t, 2.0) * t * P1.x)
|
|
|
|
let x2 = (3.0 * (1.0 - t) * pow(t, 2.0) * P2.x)
|
|
|
|
let x2 = (3.0 * (1.0 - t) * pow(t, 2.0) * P2.x)
|
|
|
|
let x3 = (pow(t, 3.0) * P3.x)
|
|
|
|
let x3 = (pow(t, 3.0) * P3.x)
|
|
|
@ -1836,3 +1852,4 @@ fileprivate extension CAMediaTimingFunction {
|
|
|
|
return pointArray
|
|
|
|
return pointArray
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|