diff --git a/.gitignore b/.gitignore index 6851188e..40c5d1f5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,11 +8,15 @@ MarqueeLabelDemo/build/* !default.mode2v3 *.perspectivev3 !default.perspectivev3 -*.xcworkspace -!default.xcworkspace xcuserdata profile *.moved-aside +*.xccheckout +*.moved-aside +*.xcuserstate # Exclude OS X folder attributes -.DS_Store \ No newline at end of file +.DS_Store + +# Excluse Carthage build artifacts +Carthage diff --git a/MarqueeLabel.h b/Classes/ObjC/MarqueeLabel.h similarity index 100% rename from MarqueeLabel.h rename to Classes/ObjC/MarqueeLabel.h diff --git a/MarqueeLabel.m b/Classes/ObjC/MarqueeLabel.m similarity index 99% rename from MarqueeLabel.m rename to Classes/ObjC/MarqueeLabel.m index 0b3dbcc3..1044a5d5 100755 --- a/MarqueeLabel.m +++ b/Classes/ObjC/MarqueeLabel.m @@ -215,6 +215,7 @@ - (void)setupLabel { [self addSubview:self.subLabel]; // Setup default values + _marqueeType = MLContinuous; _awayOffset = 0.0f; _animationCurve = UIViewAnimationOptionCurveLinear; _labelize = NO; @@ -458,7 +459,8 @@ - (BOOL)labelShouldScroll { } BOOL labelTooLarge = ([self subLabelSize].width + self.leadingBuffer > self.bounds.size.width); - return (!self.labelize && labelTooLarge); + BOOL animationHasDuration = (self.scrollDuration > 0.0f || self.rate > 0.0f); + return (!self.labelize && labelTooLarge && animationHasDuration); } - (BOOL)labelReadyForScroll { diff --git a/Classes/Swift/MarqueeLabel.swift b/Classes/Swift/MarqueeLabel.swift new file mode 100644 index 00000000..499ddf50 --- /dev/null +++ b/Classes/Swift/MarqueeLabel.swift @@ -0,0 +1,1750 @@ +// +// MarqueeLabel.swift +// +// Created by Charles Powell on 8/6/14. +// Copyright (c) 2015 Charles Powell. All rights reserved. +// + +import UIKit +import QuartzCore + + +public class MarqueeLabel: UILabel { + + /** + An enum that defines the types of `MarqueeLabel` scrolling + + - LeftRight: Scrolls left first, then back right to the original position. + - RightLeft: Scrolls right first, then back left to the original position. + - Continuous: Continuously scrolls left (with a pause at the original position if animationDelay is set). + - ContinuousReverse: Continuously scrolls right (with a pause at the original position if animationDelay is set). + */ + public enum Type { + case LeftRight + case RightLeft + case Continuous + case ContinuousReverse + } + + // + // MARK: - Public properties + // + + /** + Defines the direction and method in which the `MarqueeLabel` instance scrolls. + `MarqueeLabel` supports four types of scrolling: `MLLeftRight`, `MLRightLeft`, `MLContinuous`, and `MLContinuousReverse`. + + Given the nature of how text direction works, the options for the `marqueeType` property require specific text alignments + and will set the textAlignment property accordingly. + + - `MLLeftRight` type is ONLY compatible with a label text alignment of `NSTextAlignmentLeft`. + - `MLRightLeft` type is ONLY compatible with a label text alignment of `NSTextAlignmentRight`. + - `MLContinuous` does not require a text alignment (it is effectively centered). + - `MLContinuousReverse` does not require a text alignment (it is effectively centered). + + Defaults to `MLContinuous`. + + - SeeAlso: Type + - SeeAlso: textAlignment + */ + public var type: Type = .Continuous { + didSet { + if type == oldValue { + return + } + updateAndScroll() + } + } + + /** + Specifies the animation curve used in the scrolling motion of the labels. + Allowable options: + + - `UIViewAnimationOptionCurveEaseInOut` + - `UIViewAnimationOptionCurveEaseIn` + - `UIViewAnimationOptionCurveEaseOut` + - `UIViewAnimationOptionCurveLinear` + + Defaults to `UIViewAnimationOptionCurveEaseInOut`. + */ + public var animationCurve: UIViewAnimationCurve = .Linear + + /** + A boolean property that sets whether the `MarqueeLabel` should behave like a normal `UILabel`. + + When set to `true` the `MarqueeLabel` will behave and look like a normal `UILabel`, and will not begin any scrolling animations. + Changes to this property take effect immediately, removing any in-flight animation as well as any edge fade. Note that `MarqueeLabel` + will respect the current values of the `lineBreakMode` and `textAlignment`properties while labelized. + + To simply prevent automatic scrolling, use the `holdScrolling` property. + + Defaults to `false`. + + - SeeAlso: holdScrolling + - SeeAlso: lineBreakMode + @warning The label will not automatically scroll when this property is set to `YES`. + @warning The UILabel default setting for the `lineBreakMode` property is `NSLineBreakByTruncatingTail`, which truncates + the text adds an ellipsis glyph (...). Set the `lineBreakMode` property to `NSLineBreakByClipping` in order to avoid the + ellipsis, especially if using an edge transparency fade. + */ + @IBInspectable public var labelize: Bool = false { + didSet { + if labelize != oldValue { + updateAndScroll() + } + } + } + + /** + A boolean property that sets whether the `MarqueeLabel` should hold (prevent) automatic label scrolling. + + When set to `true`, `MarqueeLabel` will not automatically scroll even its text is larger than the specified frame, + although the specified edge fades will remain. + + To set `MarqueeLabel` to act like a normal UILabel, use the `labelize` property. + + Defaults to `false`. + + - SeeAlso: labelize + @warning The label will not automatically scroll when this property is set to `YES`. + */ + @IBInspectable public var holdScrolling: Bool = false { + didSet { + if holdScrolling != oldValue { + if oldValue == true && !(awayFromHome || labelize || tapToScroll ) && labelShouldScroll() { + beginScroll() + } + } + } + } + + /** + A boolean property that sets whether the `MarqueeLabel` should only begin a scroll when tapped. + + If this property is set to `true`, the `MarqueeLabel` will only begin a scroll animation cycle when tapped. The label will + not automatically being a scroll. This setting overrides the setting of the `holdScrolling` property. + + Defaults to `false`. + + @warning The label will not automatically scroll when this property is set to `false`. + - SeeAlso: holdScrolling + */ + @IBInspectable public var tapToScroll: Bool = false { + didSet { + if tapToScroll != oldValue { + if tapToScroll { + let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(MarqueeLabel.labelWasTapped(_:))) + self.addGestureRecognizer(tapRecognizer) + userInteractionEnabled = true + } else { + if let recognizer = self.gestureRecognizers!.first as UIGestureRecognizer? { + self.removeGestureRecognizer(recognizer) + } + userInteractionEnabled = false + } + } + } + } + + /** + A read-only boolean property that indicates if the label's scroll animation has been paused. + + - SeeAlso: pauseLabel + - SeeAlso: unpauseLabel + */ + public var isPaused: Bool { + return (sublabel.layer.speed == 0.0) + } + + /** + A boolean property that indicates if the label is currently away from the home location. + + The "home" location is the traditional location of `UILabel` text. This property essentially reflects if a scroll animation is underway. + */ + public var awayFromHome: Bool { + if let presentationLayer = sublabel.layer.presentationLayer() as? CALayer { + return !(presentationLayer.position.x == homeLabelFrame.origin.x) + } + + return false + } + + /** + The `MarqueeLabel` scrolling speed may be defined by one of two ways: + - Rate(CGFloat): The speed is defined by a rate of motion, in units of points per second. + - Duration(CGFloat): The speed is defined by the time to complete a scrolling animation cycle, in units of seconds. + + Each case takes an associated `CGFloat` value, which is the rate/duration desired. + */ + public enum SpeedLimit { + case Rate(CGFloat) + case Duration(CGFloat) + + var value: CGFloat { + switch self { + case .Rate(let rate): + return rate + case .Duration(let duration): + return duration + } + } + } + + /** + Defines the speed of the `MarqueeLabel` scrolling animation. + + The speed is set by specifying a case of the `SpeedLimit` enum along with an associated value. + + - SeeAlso: SpeedLimit + */ + public var speed: SpeedLimit = .Duration(7.0) { + didSet { + switch (speed, oldValue) { + case (.Rate(let a), .Rate(let b)) where a == b: + return + case (.Duration(let a), .Duration(let b)) where a == b: + return + default: + updateAndScroll() + } + } + } + + // @available attribute seems to cause SourceKit to crash right now + // @available(*, deprecated = 2.6, message = "Use speed property instead") + @IBInspectable public var scrollDuration: CGFloat? { + get { + switch speed { + case .Duration(let duration): return duration + case .Rate(_): return nil + } + } + set { + if let duration = newValue { + speed = .Duration(duration) + } + } + } + + // @available attribute seems to cause SourceKit to crash right now + // @available(*, deprecated = 2.6, message = "Use speed property instead") + @IBInspectable public var scrollRate: CGFloat? { + get { + switch speed { + case .Duration(_): return nil + case .Rate(let rate): return rate + } + } + set { + if let rate = newValue { + speed = .Rate(rate) + } + } + } + + /** + A buffer (offset) between the leading edge of the label text and the label frame. + + This property adds additional space between the leading edge of the label text and the label frame. The + leading edge is the edge of the label text facing the direction of scroll (i.e. the edge that animates + offscreen first during scrolling). + + Defaults to `0`. + + - Note: The value set to this property affects label positioning at all times (including when `labelize` is set to `true`), + including when the text string length is short enough that the label does not need to scroll. + - Note: For Continuous-type labels, the smallest value of `leadingBuffer`, `trailingBuffer`, and `fadeLength` + is used as spacing between the two label instances. Zero is an allowable value for all three properties. + + - SeeAlso: trailingBuffer + */ + @IBInspectable public var leadingBuffer: CGFloat = 0.0 { + didSet { + if leadingBuffer != oldValue { + updateAndScroll() + } + } + } + + /** + A buffer (offset) between the trailing edge of the label text and the label frame. + + This property adds additional space (buffer) between the trailing edge of the label text and the label frame. The + trailing edge is the edge of the label text facing away from the direction of scroll (i.e. the edge that animates + offscreen last during scrolling). + + Defaults to `0`. + + - Note: The value set to this property has no effect when the `labelize` property is set to `true`. + + - Note: For Continuous-type labels, the smallest value of `leadingBuffer`, `trailingBuffer`, and `fadeLength` + is used as spacing between the two label instances. Zero is an allowable value for all three properties. + + - SeeAlso: leadingBuffer + */ + @IBInspectable public var trailingBuffer: CGFloat = 0.0 { + didSet { + if trailingBuffer != oldValue { + updateAndScroll() + } + } + } + + /** + The length of transparency fade at the left and right edges of the frame. + + This propery sets the size (in points) of the view edge transparency fades on the left and right edges of a `MarqueeLabel`. The + transparency fades from an alpha of 1.0 (fully visible) to 0.0 (fully transparent) over this distance. Values set to this property + will be sanitized to prevent a fade length greater than 1/2 of the frame width. + + Defaults to `0`. + */ + @IBInspectable public var fadeLength: CGFloat = 0.0 { + didSet { + if fadeLength != oldValue { + applyGradientMask(fadeLength, animated: true) + updateAndScroll() + } + } + } + + /** + The length of delay in seconds that the label pauses at the completion of a scroll. + */ + @IBInspectable public var animationDelay: CGFloat = 1.0 + + // + // MARK: - Class Functions and Helpers + // + + /** + Convenience method to restart all `MarqueeLabel` instances that have the specified view controller in their next responder chain. + + - Parameter controller: The view controller for which to restart all `MarqueeLabel` instances. + + - Warning: View controllers that appear with animation (such as from underneath a modal-style controller) can cause some `MarqueeLabel` text + position "jumping" when this method is used in `viewDidAppear` if scroll animations are already underway. Use this method inside `viewWillAppear:` + instead to avoid this problem. + + - Warning: This method may not function properly if passed the parent view controller when using view controller containment. + + - SeeAlso: restartLabel + - SeeAlso: controllerViewDidAppear: + - SeeAlso: controllerViewWillAppear: + */ + class func restartLabelsOfController(controller: UIViewController) { + MarqueeLabel.notifyController(controller, message: .Restart) + } + + /** + Convenience method to restart all `MarqueeLabel` instances that have the specified view controller in their next responder chain. + + Alternative to `restartLabelsOfController`. This method is retained for backwards compatibility and future enhancements. + + - Parameter controller: The view controller that will appear. + - SeeAlso: restartLabel + - SeeAlso: controllerViewDidAppear + */ + class func controllerViewWillAppear(controller: UIViewController) { + MarqueeLabel.restartLabelsOfController(controller) + } + + /** + Convenience method to restart all `MarqueeLabel` instances that have the specified view controller in their next responder chain. + + Alternative to `restartLabelsOfController`. This method is retained for backwards compatibility and future enhancements. + + - Parameter controller: The view controller that did appear. + - SeeAlso: restartLabel + - SeeAlso: controllerViewWillAppear + */ + class func controllerViewDidAppear(controller: UIViewController) { + MarqueeLabel.restartLabelsOfController(controller) + } + + /** + Labelizes all `MarqueeLabel` instances that have the specified view controller in their next responder chain. + + The `labelize` property of all recognized `MarqueeLabel` instances will be set to `true`. + + - Parameter controller: The view controller for which all `MarqueeLabel` instances should be labelized. + - SeeAlso: labelize + */ + class func controllerLabelsLabelize(controller: UIViewController) { + MarqueeLabel.notifyController(controller, message: .Labelize) + } + + /** + De-labelizes all `MarqueeLabel` instances that have the specified view controller in their next responder chain. + + The `labelize` property of all recognized `MarqueeLabel` instances will be set to `false`. + + - Parameter controller: The view controller for which all `MarqueeLabel` instances should be de-labelized. + - SeeAlso: labelize + */ + class func controllerLabelsAnimate(controller: UIViewController) { + MarqueeLabel.notifyController(controller, message: .Animate) + } + + + // + // MARK: - Initialization + // + + /** + Returns a newly initialized `MarqueeLabel` instance with the specified scroll rate and edge transparency fade length. + + - Parameter frame: A rectangle specifying the initial location and size of the view in its superview's coordinates. Text (for the given font, font size, etc.) that does not fit in this frame will automatically scroll. + - Parameter pixelsPerSec: A rate of scroll for the label scroll animation. Must be non-zero. Note that this will be the peak (mid-transition) rate for ease-type animation. + - Parameter fadeLength: A length of transparency fade at the left and right edges of the `MarqueeLabel` instance's frame. + - Returns: An initialized `MarqueeLabel` object or nil if the object couldn't be created. + - SeeAlso: fadeLength + */ + init(frame: CGRect, rate: CGFloat, fadeLength fade: CGFloat) { + speed = .Rate(rate) + fadeLength = CGFloat(min(fade, frame.size.width/2.0)) + super.init(frame: frame) + setup() + } + + /** + Returns a newly initialized `MarqueeLabel` instance with the specified scroll rate and edge transparency fade length. + + - Parameter frame: A rectangle specifying the initial location and size of the view in its superview's coordinates. Text (for the given font, font size, etc.) that does not fit in this frame will automatically scroll. + - Parameter scrollDuration: A scroll duration the label scroll animation. Must be non-zero. This will be the duration that the animation takes for one-half of the scroll cycle in the case of left-right and right-left marquee types, and for one loop of a continuous marquee type. + - Parameter fadeLength: A length of transparency fade at the left and right edges of the `MarqueeLabel` instance's frame. + - Returns: An initialized `MarqueeLabel` object or nil if the object couldn't be created. + - SeeAlso: fadeLength + */ + init(frame: CGRect, duration: CGFloat, fadeLength fade: CGFloat) { + speed = .Duration(duration) + fadeLength = CGFloat(min(fade, frame.size.width/2.0)) + super.init(frame: frame) + setup() + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setup() + } + + /** + Returns a newly initialized `MarqueeLabel` instance. + + The default scroll duration of 7.0 seconds and fade length of 0.0 are used. + + - Parameter frame: A rectangle specifying the initial location and size of the view in its superview's coordinates. Text (for the given font, font size, etc.) that does not fit in this frame will automatically scroll. + - Returns: An initialized `MarqueeLabel` object or nil if the object couldn't be created. + */ + convenience public override init(frame: CGRect) { + self.init(frame: frame, duration:7.0, fadeLength:0.0) + } + + private func setup() { + // Create sublabel + sublabel = UILabel(frame: self.bounds) + sublabel.tag = 700 + sublabel.layer.anchorPoint = CGPoint.zero + + // Add sublabel + addSubview(sublabel) + + // Configure self + super.clipsToBounds = true + super.numberOfLines = 1 + + // Add notification observers + // Custom class notifications + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MarqueeLabel.restartForViewController(_:)), name: MarqueeKeys.Restart.rawValue, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MarqueeLabel.labelizeForController(_:)), name: MarqueeKeys.Labelize.rawValue, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MarqueeLabel.animateForController(_:)), name: MarqueeKeys.Animate.rawValue, object: nil) + // UIApplication state notifications + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MarqueeLabel.restartLabel), name: UIApplicationDidBecomeActiveNotification, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MarqueeLabel.shutdownLabel), name: UIApplicationDidEnterBackgroundNotification, object: nil) + } + + override public func awakeFromNib() { + super.awakeFromNib() + forwardPropertiesToSublabel() + } + + private func forwardPropertiesToSublabel() { + /* + Note that this method is currently ONLY called from awakeFromNib, i.e. when + text properties are set via a Storyboard. As the Storyboard/IB doesn't currently + support attributed strings, there's no need to "forward" the super attributedString value. + */ + + // Since we're a UILabel, we actually do implement all of UILabel's properties. + // We don't care about these values, we just want to forward them on to our sublabel. + let properties = ["baselineAdjustment", "enabled", "highlighted", "highlightedTextColor", + "minimumFontSize", "shadowOffset", "textAlignment", + "userInteractionEnabled", "adjustsFontSizeToFitWidth", + "lineBreakMode", "numberOfLines"] + + // Iterate through properties + sublabel.text = super.text + sublabel.font = super.font + sublabel.textColor = super.textColor + sublabel.backgroundColor = super.backgroundColor ?? UIColor.clearColor() + sublabel.shadowColor = super.shadowColor + sublabel.shadowOffset = super.shadowOffset + for prop in properties { + let value: AnyObject! = super.valueForKey(prop) + sublabel.setValue(value, forKeyPath: prop) + } + } + + // + // MARK: - MarqueeLabel Heavy Lifting + // + + override public func layoutSubviews() { + super.layoutSubviews() + + updateAndScroll(true) + } + + override public func willMoveToWindow(newWindow: UIWindow?) { + if newWindow == nil { + shutdownLabel() + } + } + + override public func didMoveToWindow() { + if self.window == nil { + shutdownLabel() + } else { + updateAndScroll() + } + } + + private func updateAndScroll() { + updateAndScroll(true) + } + + private func updateAndScroll(shouldBeginScroll: Bool) { + // Check if scrolling can occur + if !labelReadyForScroll() { + return + } + + // Calculate expected size + let expectedLabelSize = sublabelSize() + + // Invalidate intrinsic size + invalidateIntrinsicContentSize() + + // Move label to home + returnLabelToHome() + + // Check if label should scroll + // Note that the holdScrolling propery does not affect this + if !labelShouldScroll() { + // Set text alignment and break mode to act like a normal label + sublabel.textAlignment = super.textAlignment + sublabel.lineBreakMode = super.lineBreakMode + + var unusedFrame = CGRect.zero + var labelFrame = CGRect.zero + + switch type { + case .ContinuousReverse, .RightLeft: + CGRectDivide(bounds, &unusedFrame, &labelFrame, leadingBuffer, CGRectEdge.MaxXEdge) + labelFrame = CGRectIntegral(labelFrame) + default: + labelFrame = CGRectIntegral(CGRectMake(leadingBuffer, 0.0, bounds.size.width - leadingBuffer, bounds.size.height)) + } + + homeLabelFrame = labelFrame + awayOffset = 0.0 + + // Remove an additional sublabels (for continuous types) + repliLayer.instanceCount = 1; + + // Set the sublabel frame to calculated labelFrame + sublabel.frame = labelFrame + + // Configure fade + applyGradientMask(fadeLength, animated: !labelize) + + return + } + + // Label DOES need to scroll + + // Spacing between primary and second sublabel must be at least equal to leadingBuffer, and at least equal to the fadeLength + let minTrailing = max(max(leadingBuffer, trailingBuffer), fadeLength) + + switch type { + case .Continuous, .ContinuousReverse: + if (type == .Continuous) { + homeLabelFrame = CGRectIntegral(CGRectMake(leadingBuffer, 0.0, expectedLabelSize.width, bounds.size.height)) + awayOffset = -(homeLabelFrame.size.width + minTrailing) + } else { // .ContinuousReverse + homeLabelFrame = CGRectIntegral(CGRectMake(bounds.size.width - (expectedLabelSize.width + leadingBuffer), 0.0, expectedLabelSize.width, bounds.size.height)) + awayOffset = (homeLabelFrame.size.width + minTrailing) + } + + // Set frame and text + sublabel.frame = homeLabelFrame + + // Configure replication + repliLayer.instanceCount = 2 + repliLayer.instanceTransform = CATransform3DMakeTranslation(-awayOffset, 0.0, 0.0) + + case .RightLeft: + homeLabelFrame = CGRectIntegral(CGRectMake(bounds.size.width - (expectedLabelSize.width + leadingBuffer), 0.0, expectedLabelSize.width, bounds.size.height)) + awayOffset = (expectedLabelSize.width + trailingBuffer + leadingBuffer) - bounds.size.width + + // Set frame and text + sublabel.frame = homeLabelFrame + + // Remove any replication + repliLayer.instanceCount = 1 + + // Enforce text alignment for this type + sublabel.textAlignment = NSTextAlignment.Right + + case .LeftRight: + homeLabelFrame = CGRectIntegral(CGRectMake(leadingBuffer, 0.0, expectedLabelSize.width, expectedLabelSize.height)) + awayOffset = bounds.size.width - (expectedLabelSize.width + leadingBuffer + trailingBuffer) + + // Set frame and text + sublabel.frame = homeLabelFrame + + // Remove any replication + self.repliLayer.instanceCount = 1 + + // Enforce text alignment for this type + sublabel.textAlignment = NSTextAlignment.Left + + // Default case not required + } + + // Recompute the animation duration + animationDuration = { + switch self.speed { + case .Rate(let rate): + return CGFloat(fabs(self.awayOffset) / rate) + case .Duration(let duration): + return duration + } + }() + + // Configure gradient for current condition + applyGradientMask(fadeLength, animated: !self.labelize) + + if !tapToScroll && !holdScrolling && shouldBeginScroll { + beginScroll() + } + } + + func sublabelSize() -> CGSize { + // Bound the expected size + let maximumLabelSize = CGSizeMake(CGFloat.max, CGFloat.max) + // Calculate the expected size + var expectedLabelSize = sublabel.sizeThatFits(maximumLabelSize) + // Sanitize width to 5461.0 (largest width a UILabel will draw on an iPhone 6S Plus) + expectedLabelSize.width = min(expectedLabelSize.width, 5461.0) + + // Adjust to own height (make text baseline match normal label) + expectedLabelSize.height = bounds.size.height + return expectedLabelSize + } + + override public func sizeThatFits(size: CGSize) -> CGSize { + var fitSize = sublabel.sizeThatFits(size) + fitSize.width += leadingBuffer + return fitSize + } + + // + // MARK: - Animation Handling + // + + private func labelShouldScroll() -> Bool { + // Check for nil string + if sublabel.text == nil { + return false + } + + // Check for empty string + if sublabel.text!.isEmpty { + return false + } + + // Check if the label string fits + let labelTooLarge = (sublabelSize().width + leadingBuffer) > self.bounds.size.width + let animationHasDuration = speed.value > 0.0 + return (!labelize && labelTooLarge && animationHasDuration) + } + + private func labelReadyForScroll() -> Bool { + // Check if we have a superview + if superview == nil { + return false + } + + // Check if we are attached to a window + if window == nil { + return false + } + + // Check if our view controller is ready + let viewController = firstAvailableViewController() + if viewController != nil { + if !viewController!.isViewLoaded() { + return false + } + } + + return true + } + + private func beginScroll() { + beginScroll(true) + } + + private func beginScroll(delay: Bool) { + switch self.type { + case .LeftRight, .RightLeft: + scrollAway(animationDuration, delay: animationDelay) + default: + scrollContinuous(animationDuration, delay: animationDelay) + } + } + + private func returnLabelToHome() { + // Remove any gradient animation + maskLayer?.removeAllAnimations() + + // Remove all sublabel position animations + sublabel.layer.removeAllAnimations() + } + + // Define animation completion closure type + private typealias MLAnimationCompletion = (finished: Bool) -> () + + private func scroll(interval: CGFloat, delay: CGFloat = 0.0, scroller: Scroller, fader: CAKeyframeAnimation?) { + var scroller = scroller + // Check for conditions which would prevent scrolling + if !labelReadyForScroll() { + return + } + + // Call pre-animation hook + labelWillBeginScroll() + + // Start animation transactions + CATransaction.begin() + let transDuration = transactionDurationType(type, interval: interval, delay: delay) + CATransaction.setAnimationDuration(transDuration) + + // Create gradient animation, if needed + let gradientAnimation: CAKeyframeAnimation? + if fadeLength > 0.0 { + // Remove any setup animation, but apply final values + if let setupAnim = maskLayer?.animationForKey("setupFade") as? CABasicAnimation, finalColors = setupAnim.toValue as? [CGColorRef] { + maskLayer?.colors = finalColors + } + maskLayer?.removeAnimationForKey("setupFade") + + // Generate animation if needed + if let previousAnimation = fader { + gradientAnimation = previousAnimation + } else { + gradientAnimation = keyFrameAnimationForGradient(fadeLength, interval: interval, delay: delay) + } + + // Apply scrolling animation + maskLayer?.addAnimation(gradientAnimation!, forKey: "gradient") + } else { + // No animation needed + gradientAnimation = nil + } + + let completion = CompletionBlock({ (finished: Bool) -> () in + guard finished else { + // Do not continue into the next loop + return + } + + // Call returned home function + self.labelReturnedToHome(true) + + // Check to ensure that: + // 1) We don't double fire if an animation already exists + // 2) The instance is still attached to a window - this completion block is called for + // many reasons, including if the animation is removed due to the view being removed + // from the UIWindow (typically when the view controller is no longer the "top" view) + guard self.window != nil else { + return + } + + guard self.sublabel.layer.animationForKey("position") == nil else { + return + } + + // Begin again, if conditions met + if (self.labelShouldScroll() && !self.tapToScroll && !self.holdScrolling) { + // Perform completion callback + self.scroll(interval, delay: delay, scroller: scroller, fader: gradientAnimation) + } + }) + + // Call scroller + let scrolls = scroller.generate(interval, delay: delay) + + // Perform all animations in scrolls + for (index, scroll) in scrolls.enumerate() { + let layer = scroll.layer + let anim = scroll.anim + + // Add callback to single animation + if index == 0 { + anim.setValue(completion as AnyObject, forKey: MarqueeKeys.CompletionClosure.rawValue) + anim.delegate = self + } + + // Add animation + layer.addAnimation(anim, forKey: "position") + } + + CATransaction.commit() + } + + private func scrollAway(interval: CGFloat, delay: CGFloat = 0.0) { + // Create scroller, which defines the animation to perform + let homeOrigin = homeLabelFrame.origin + let awayOrigin = offsetCGPoint(homeLabelFrame.origin, offset: awayOffset) + let scroller = Scroller(generator: {(interval: CGFloat, delay: CGFloat) -> [(layer: CALayer, anim: CAKeyframeAnimation)] in + // Create animation for position + let values: [NSValue] = [ + NSValue(CGPoint: homeOrigin), // Start at home + NSValue(CGPoint: homeOrigin), // Stay at home for delay + NSValue(CGPoint: awayOrigin), // Move to away + NSValue(CGPoint: awayOrigin), // Stay at away for delay + NSValue(CGPoint: homeOrigin) // Move back to home + ] + + let layer = self.sublabel.layer + let anim = self.keyFrameAnimationForProperty("position", values: values, interval: interval, delay: delay) + + return [(layer: layer, anim: anim)] + }) + + // Scroll + scroll(interval, delay: delay, scroller: scroller, fader: nil) + } + + + private func scrollContinuous(interval: CGFloat, delay: CGFloat) { + // Create scroller, which defines the animation to perform + let homeOrigin = homeLabelFrame.origin + let awayOrigin = offsetCGPoint(homeLabelFrame.origin, offset: awayOffset) + let scroller = Scroller(generator: { (interval: CGFloat, delay: CGFloat) -> [(layer: CALayer, anim: CAKeyframeAnimation)] in + // Create animation for position + let values: [NSValue] = [ + NSValue(CGPoint: homeOrigin), // Start at home + NSValue(CGPoint: homeOrigin), // Stay at home for delay + NSValue(CGPoint: awayOrigin) // Move to away + ] + + // Generate animation + let layer = self.sublabel.layer + let anim = self.keyFrameAnimationForProperty("position", values: values, interval: interval, delay: delay) + + + return [(layer: layer, anim: anim)] + }) + + // Scroll + scroll(interval, delay: delay, scroller: scroller, fader: nil) + } + + private func applyGradientMask(fadeLength: CGFloat, animated: Bool) { + // Remove any in-flight animations + maskLayer?.removeAllAnimations() + + // Check for zero-length fade + if (fadeLength <= 0.0) { + removeGradientMask() + return + } + + // Configure gradient mask without implicit animations + CATransaction.begin() + CATransaction.setDisableActions(true) + + // Determine if gradient mask needs to be created + let gradientMask: CAGradientLayer + if let currentMask = self.maskLayer { + // Mask layer already configured + gradientMask = currentMask + } else { + // No mask exists, create new mask + gradientMask = CAGradientLayer() + gradientMask.shouldRasterize = true + gradientMask.rasterizationScale = UIScreen.mainScreen().scale + gradientMask.startPoint = CGPointMake(0.0, 0.5) + gradientMask.endPoint = CGPointMake(1.0, 0.5) + // Adjust stops based on fade length + let leftFadeStop = fadeLength/self.bounds.size.width + let rightFadeStop = fadeLength/self.bounds.size.width + gradientMask.locations = [0.0, leftFadeStop, (1.0 - rightFadeStop), 1.0] + } + + // Set up colors + let transparent = UIColor.clearColor().CGColor + let opaque = UIColor.blackColor().CGColor + + // Set mask + self.layer.mask = gradientMask + + gradientMask.bounds = self.layer.bounds + gradientMask.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)) + + // Determine colors for non-scrolling label (i.e. at home) + let adjustedColors: [CGColorRef] + let trailingFadeNeeded = self.labelShouldScroll() + + switch (type) { + case .ContinuousReverse, .RightLeft: + adjustedColors = [(trailingFadeNeeded ? transparent : opaque), opaque, opaque, opaque] + + // .MLContinuous, .MLLeftRight + default: + adjustedColors = [opaque, opaque, opaque, (trailingFadeNeeded ? transparent : opaque)] + break + } + + if (animated) { + // Finish transaction + CATransaction.commit() + + // Create animation for color change + let colorAnimation = GradientAnimation(keyPath: "colors") + colorAnimation.fromValue = gradientMask.colors + colorAnimation.toValue = adjustedColors + colorAnimation.fillMode = kCAFillModeForwards + colorAnimation.removedOnCompletion = false + colorAnimation.delegate = self + gradientMask.addAnimation(colorAnimation, forKey: "setupFade") + } else { + gradientMask.colors = adjustedColors + CATransaction.commit() + } + } + + private func removeGradientMask() { + self.layer.mask = nil + } + + private func keyFrameAnimationForGradient(fadeLength: CGFloat, interval: CGFloat, delay: CGFloat) -> CAKeyframeAnimation { + // Setup + let values: [[CGColorRef]] + let keyTimes: [CGFloat] + let transp = UIColor.clearColor().CGColor + let opaque = UIColor.blackColor().CGColor + + // Create new animation + let animation = CAKeyframeAnimation(keyPath: "colors") + + // Get timing function + let timingFunction = timingFunctionForAnimationCurve(animationCurve) + + // Define keyTimes + switch (type) { + case .LeftRight, .RightLeft: + // Calculate total animation duration + let totalDuration = 2.0 * (delay + interval) + keyTimes = + [ + 0.0, // 1) Initial gradient + delay/totalDuration, // 2) Begin of LE fade-in, just as scroll away starts + (delay + 0.4)/totalDuration, // 3) End of LE fade in [LE fully faded] + (delay + interval - 0.4)/totalDuration, // 4) Begin of TE fade out, just before scroll away finishes + (delay + interval)/totalDuration, // 5) End of TE fade out [TE fade removed] + (delay + interval + delay)/totalDuration, // 6) Begin of TE fade back in, just as scroll home starts + (delay + interval + delay + 0.4)/totalDuration, // 7) End of TE fade back in [TE fully faded] + (totalDuration - 0.4)/totalDuration, // 8) Begin of LE fade out, just before scroll home finishes + 1.0 // 9) End of LE fade out, just as scroll home finishes + ] + + // .MLContinuous, .MLContinuousReverse + default: + // Calculate total animation duration + let totalDuration = delay + interval + + // Find when the lead label will be totally offscreen + let offsetDistance = awayOffset + let startFadeFraction = fabs((sublabel.bounds.size.width + leadingBuffer) / offsetDistance) + // Find when the animation will hit that point + let startFadeTimeFraction = timingFunction.durationPercentageForPositionPercentage(startFadeFraction, duration: totalDuration) + let startFadeTime = delay + CGFloat(startFadeTimeFraction) * interval + + keyTimes = [ + 0.0, // Initial gradient + delay/totalDuration, // Begin of fade in + (delay + 0.2)/totalDuration, // End of fade in, just as scroll away starts + startFadeTime/totalDuration, // Begin of fade out, just before scroll home completes + (startFadeTime + 0.1)/totalDuration, // End of fade out, as scroll home completes + 1.0 // Buffer final value (used on continuous types) + ] + break + } + + // Define values + // Get current layer values + let mask = maskLayer?.presentationLayer() as? CAGradientLayer + let currentValues = mask?.colors as? [CGColorRef] + + switch (type) { + case .ContinuousReverse: + values = [ + currentValues ?? [transp, opaque, opaque, opaque], // Initial gradient + [transp, opaque, opaque, opaque], // Begin of fade in + [transp, opaque, opaque, transp], // End of fade in, just as scroll away starts + [transp, opaque, opaque, transp], // Begin of fade out, just before scroll home completes + [transp, opaque, opaque, opaque], // End of fade out, as scroll home completes + [transp, opaque, opaque, opaque] // Final "home" value + ] + break + + case .RightLeft: + values = [ + currentValues ?? [transp, opaque, opaque, opaque], // 1) + [transp, opaque, opaque, opaque], // 2) + [transp, opaque, opaque, transp], // 3) + [transp, opaque, opaque, transp], // 4) + [opaque, opaque, opaque, transp], // 5) + [opaque, opaque, opaque, transp], // 6) + [transp, opaque, opaque, transp], // 7) + [transp, opaque, opaque, transp], // 8) + [transp, opaque, opaque, opaque] // 9) + ] + break + + case .Continuous: + values = [ + currentValues ?? [opaque, opaque, opaque, transp], // Initial gradient + [opaque, opaque, opaque, transp], // Begin of fade in + [transp, opaque, opaque, transp], // End of fade in, just as scroll away starts + [transp, opaque, opaque, transp], // Begin of fade out, just before scroll home completes + [opaque, opaque, opaque, transp], // End of fade out, as scroll home completes + [opaque, opaque, opaque, transp] // Final "home" value + ] + break + + case .LeftRight: + values = [ + currentValues ?? [opaque, opaque, opaque, transp], // 1) + [opaque, opaque, opaque, transp], // 2) + [transp, opaque, opaque, transp], // 3) + [transp, opaque, opaque, transp], // 4) + [transp, opaque, opaque, opaque], // 5) + [transp, opaque, opaque, opaque], // 6) + [transp, opaque, opaque, transp], // 7) + [transp, opaque, opaque, transp], // 8) + [opaque, opaque, opaque, transp] // 9) + ] + break + } + + animation.values = values + animation.keyTimes = keyTimes + animation.timingFunctions = [timingFunction, timingFunction, timingFunction, timingFunction] + + return animation + } + + private func keyFrameAnimationForProperty(property: String, values: [NSValue], interval: CGFloat, delay: CGFloat) -> CAKeyframeAnimation { + // Create new animation + let animation = CAKeyframeAnimation(keyPath: property) + + // Get timing function + let timingFunction = timingFunctionForAnimationCurve(animationCurve) + + // Calculate times based on marqueeType + let totalDuration: CGFloat + switch (type) { + case .LeftRight, .RightLeft: + //NSAssert(values.count == 5, @"Incorrect number of values passed for MLLeftRight-type animation") + totalDuration = 2.0 * (delay + interval) + // Set up keyTimes + animation.keyTimes = [ + 0.0, // Initial location, home + delay/totalDuration, // Initial delay, at home + (delay + interval)/totalDuration, // Animation to away + (delay + interval + delay)/totalDuration, // Delay at away + 1.0 // Animation to home + ] + + animation.timingFunctions = [ + timingFunction, + timingFunction, + timingFunction, + timingFunction + ] + + // .Continuous + // .ContinuousReverse + default: + //NSAssert(values.count == 3, @"Incorrect number of values passed for MLContinous-type animation") + totalDuration = delay + interval + // Set up keyTimes + animation.keyTimes = [ + 0.0, // Initial location, home + delay/totalDuration, // Initial delay, at home + 1.0 // Animation to away + ] + + animation.timingFunctions = [ + timingFunction, + timingFunction + ] + } + + // Set values + animation.values = values + + return animation + } + + private func timingFunctionForAnimationCurve(curve: UIViewAnimationCurve) -> CAMediaTimingFunction { + let timingFunction: String? + + switch curve { + case .EaseIn: + timingFunction = kCAMediaTimingFunctionEaseIn + case .EaseInOut: + timingFunction = kCAMediaTimingFunctionEaseInEaseOut + case .EaseOut: + timingFunction = kCAMediaTimingFunctionEaseOut + default: + timingFunction = kCAMediaTimingFunctionLinear + } + + return CAMediaTimingFunction(name: timingFunction!) + } + + private func transactionDurationType(labelType: Type, interval: CGFloat, delay: CGFloat) -> NSTimeInterval { + switch (labelType) { + case .LeftRight, .RightLeft: + return NSTimeInterval(2.0 * (delay + interval)) + default: + return NSTimeInterval(delay + interval) + } + } + + override public func animationDidStop(anim: CAAnimation, finished flag: Bool) { + if anim is GradientAnimation { + if let setupAnim = maskLayer?.animationForKey("setupFade") as? CABasicAnimation, finalColors = setupAnim.toValue as? [CGColorRef] { + maskLayer?.colors = finalColors + } + // Remove regardless, since we set removeOnCompletion = false + maskLayer?.removeAnimationForKey("setupFade") + } else { + let completion = anim.valueForKey(MarqueeKeys.CompletionClosure.rawValue) as? CompletionBlock + completion?.f(finished: flag) + } + } + + + // + // MARK: - Private details + // + + private var sublabel = UILabel() + private var animationDuration: CGFloat = 0.0 + + private var homeLabelFrame = CGRect.zero + private var awayOffset: CGFloat = 0.0 + + override public class func layerClass() -> AnyClass { + return CAReplicatorLayer.self + } + + private var repliLayer: CAReplicatorLayer { + return self.layer as! CAReplicatorLayer + } + + private var maskLayer: CAGradientLayer? { + return self.layer.mask as! CAGradientLayer? + } + + override public func drawLayer(layer: CALayer, inContext ctx: CGContext) { + // Do NOT call super, to prevent UILabel superclass from drawing into context + // Label drawing is handled by sublabel and CAReplicatorLayer layer class + + // Draw only background color + if let bgColor = backgroundColor { + CGContextSetFillColorWithColor(ctx, bgColor.CGColor); + CGContextFillRect(ctx, layer.bounds); + } + } + + private enum MarqueeKeys: String { + case Restart = "MLViewControllerRestart" + case Labelize = "MLShouldLabelize" + case Animate = "MLShouldAnimate" + case CompletionClosure = "MLAnimationCompletion" + } + + class private func notifyController(controller: UIViewController, message: MarqueeKeys) { + NSNotificationCenter.defaultCenter().postNotificationName(message.rawValue, object: nil, userInfo: ["controller" : controller]) + } + + public func restartForViewController(notification: NSNotification) { + if let controller = notification.userInfo?["controller"] as? UIViewController { + if controller === self.firstAvailableViewController() { + self.restartLabel() + } + } + } + + public func labelizeForController(notification: NSNotification) { + if let controller = notification.userInfo?["controller"] as? UIViewController { + if controller === self.firstAvailableViewController() { + self.labelize = true + } + } + } + + public func animateForController(notification: NSNotification) { + if let controller = notification.userInfo?["controller"] as? UIViewController { + if controller === self.firstAvailableViewController() { + self.labelize = false + } + } + } + + + // + // MARK: - Label Control + // + + /** + Overrides any non-size condition which is preventing the receiver from automatically scrolling, and begins a scroll animation. + + Currently the only non-size conditions which can prevent a label from scrolling are the `tapToScroll` and `holdScrolling` properties. This + method will not force a label with a string that fits inside the label bounds (i.e. that would not automatically scroll) to begin a scroll + animation. + + Upon the completion of the first forced scroll animation, the receiver will not automatically continue to scroll unless the conditions + preventing scrolling have been removed. + + - Note: This method has no effect if called during an already in-flight scroll animation. + + - SeeAlso: restartLabel + */ + public func triggerScrollStart() { + if labelShouldScroll() && !awayFromHome { + beginScroll() + } + } + + /** + Immediately resets the label to the home position, cancelling any in-flight scroll animation, and restarts the scroll animation if the appropriate conditions are met. + + - SeeAlso: resetLabel + - SeeAlso: triggerScrollStart + */ + public func restartLabel() { + // Shutdown the label + shutdownLabel() + // Restart scrolling if appropriate + if labelShouldScroll() && !tapToScroll && !holdScrolling { + beginScroll() + } + } + + /** + Resets the label text, recalculating the scroll animation. + + The text is immediately returned to the home position, and the scroll animation positions are cleared. Scrolling will not resume automatically after + a call to this method. To re-initiate scrolling, use either a call to `restartLabel` or make a change to a UILabel property such as text, bounds/frame, + font, font size, etc. + + - SeeAlso: restartLabel + */ + public func resetLabel() { + returnLabelToHome() + homeLabelFrame = CGRect.null + awayOffset = 0.0 + } + + /** + Immediately resets the label to the home position, cancelling any in-flight scroll animation. + + The text is immediately returned to the home position. Scrolling will not resume automatically after a call to this method. + To re-initiate scrolling use a call to `restartLabel` or `triggerScrollStart`, or make a change to a UILabel property such as text, bounds/frame, + font, font size, etc. + + - SeeAlso: restartLabel + - SeeAlso: triggerScrollStart + */ + public func shutdownLabel() { + // Bring label to home location + returnLabelToHome() + // Apply gradient mask for home location + applyGradientMask(fadeLength, animated: false) + } + + /** + Pauses the text scrolling animation, at any point during an in-progress animation. + + - Note: This method has no effect if a scroll animation is NOT already in progress. To prevent automatic scrolling on a newly-initialized label prior to its presentation onscreen, see the `holdScrolling` property. + + - SeeAlso: holdScrolling + - SeeAlso: unpauseLabel + */ + public func pauseLabel() { + // Prevent pausing label while not in scrolling animation, or when already paused + guard (!isPaused && awayFromHome) else { + return + } + + // Pause sublabel position animations + let labelPauseTime = sublabel.layer.convertTime(CACurrentMediaTime(), fromLayer: nil) + sublabel.layer.speed = 0.0 + sublabel.layer.timeOffset = labelPauseTime + + // Pause gradient fade animation + let gradientPauseTime = maskLayer?.convertTime(CACurrentMediaTime(), fromLayer:nil) + maskLayer?.speed = 0.0 + maskLayer?.timeOffset = gradientPauseTime! + } + + /** + Un-pauses a previously paused text scrolling animation. This method has no effect if the label was not previously paused using `pauseLabel`. + + - SeeAlso: pauseLabel + */ + public func unpauseLabel() { + // Only unpause if label was previously paused + guard (isPaused) else { + return + } + + // Unpause sublabel position animations + let labelPausedTime = sublabel.layer.timeOffset + sublabel.layer.speed = 1.0 + sublabel.layer.timeOffset = 0.0 + sublabel.layer.beginTime = 0.0 + sublabel.layer.beginTime = sublabel.layer.convertTime(CACurrentMediaTime(), fromLayer:nil) - labelPausedTime + + // Unpause gradient fade animation + let gradientPauseTime = maskLayer?.timeOffset + maskLayer?.speed = 1.0 + maskLayer?.timeOffset = 0.0 + maskLayer?.beginTime = 0.0 + maskLayer?.beginTime = maskLayer!.convertTime(CACurrentMediaTime(), fromLayer:nil) - gradientPauseTime! + } + + public func labelWasTapped(recognizer: UIGestureRecognizer) { + if labelShouldScroll() && !awayFromHome { + beginScroll(true) + } + } + + /** + Called when the label animation is about to begin. + + The default implementation of this method does nothing. Subclasses may override this method in order to perform any custom actions just as + the label animation begins. This is only called in the event that the conditions for scrolling to begin are met. + */ + public func labelWillBeginScroll() { + // Default implementation does nothing - override to customize + return + } + + /** + Called when the label animation has finished, and the label is at the home position. + + The default implementation of this method does nothing. Subclasses may override this method in order to perform any custom actions jas as + the label animation completes, and before the next animation would begin (assuming the scroll conditions are met). + + - Parameter finished: A Boolean that indicates whether or not the scroll animation actually finished before the completion handler was called. + + - Warning: This method will be called, and the `finished` parameter will be `NO`, when any property changes are made that would cause the label + scrolling to be automatically reset. This includes changes to label text and font/font size changes. + */ + public func labelReturnedToHome(finished: Bool) { + // Default implementation does nothing - override to customize + return + } + + // + // MARK: - Modified UILabel Functions/Getters/Setters + // + + #if os(iOS) + override public func viewForBaselineLayout() -> UIView { + // Use subLabel view for handling baseline layouts + return sublabel + } + + public override var viewForLastBaselineLayout: UIView { + // Use subLabel view for handling baseline layouts + return sublabel + } + #endif + + public override var text: String? { + get { + return sublabel.text + } + + set { + if sublabel.text == newValue { + return + } + sublabel.text = newValue + updateAndScroll() + super.text = text + } + } + + public override var attributedText: NSAttributedString? { + get { + return sublabel.attributedText + } + + set { + if sublabel.attributedText == newValue { + return + } + sublabel.attributedText = newValue + updateAndScroll() + super.attributedText = attributedText + } + } + + public override var font: UIFont! { + get { + return sublabel.font + } + + set { + if sublabel.font == newValue { + return + } + sublabel.font = newValue + super.font = newValue + + updateAndScroll() + } + } + + public override var textColor: UIColor! { + get { + return sublabel.textColor + } + + set { + sublabel.textColor = newValue + super.textColor = newValue + } + } + + public override var backgroundColor: UIColor? { + get { + return sublabel.backgroundColor + } + + set { + sublabel.backgroundColor = newValue + super.backgroundColor = newValue + } + } + + public override var shadowColor: UIColor? { + get { + return sublabel.shadowColor + } + + set { + sublabel.shadowColor = newValue + super.shadowColor = newValue + } + } + + public override var shadowOffset: CGSize { + get { + return sublabel.shadowOffset + } + + set { + sublabel.shadowOffset = newValue + super.shadowOffset = newValue + } + } + + public override var highlightedTextColor: UIColor? { + get { + return sublabel.highlightedTextColor + } + + set { + sublabel.highlightedTextColor = newValue + super.highlightedTextColor = newValue + } + } + + public override var highlighted: Bool { + get { + return sublabel.highlighted + } + + set { + sublabel.highlighted = newValue + super.highlighted = newValue + } + } + + public override var enabled: Bool { + get { + return sublabel.enabled + } + + set { + sublabel.enabled = newValue + super.enabled = newValue + } + } + + public override var numberOfLines: Int { + get { + return super.numberOfLines + } + + set { + // By the nature of MarqueeLabel, this is 1 + super.numberOfLines = 1 + } + } + + public override var adjustsFontSizeToFitWidth: Bool { + get { + return super.adjustsFontSizeToFitWidth + } + + set { + // By the nature of MarqueeLabel, this is false + self.adjustsFontSizeToFitWidth = false + } + } + + public override var minimumScaleFactor: CGFloat { + get { + return super.minimumScaleFactor + } + + set { + self.minimumScaleFactor = 0.0 + } + } + + public override var baselineAdjustment: UIBaselineAdjustment { + get { + return sublabel.baselineAdjustment + } + + set { + sublabel.baselineAdjustment = newValue + super.baselineAdjustment = newValue + } + } + + public override func intrinsicContentSize() -> CGSize { + var content = sublabel.intrinsicContentSize() + content.width += leadingBuffer + return content + } + + + // + // MARK: - Support + // + + private func offsetCGPoint(point: CGPoint, offset: CGFloat) -> CGPoint { + return CGPointMake(point.x + offset, point.y) + } + + // + // MARK: - Deinit + // + + deinit { + NSNotificationCenter.defaultCenter().removeObserver(self) + } + +} + + +// +// MARK: - Support +// + +// Solution from: http://stackoverflow.com/a/24760061/580913 +private class CompletionBlock { + let f : T + init (_ f: T) { self.f = f } +} + +private class GradientAnimation: CABasicAnimation { + +} + +private struct Scroller { + typealias Scroll = (layer: CALayer, anim: CAKeyframeAnimation) + + init(generator gen: (interval: CGFloat, delay: CGFloat) -> [Scroll]) { + self.generator = gen + } + + let generator: (interval: CGFloat, delay: CGFloat) -> [Scroll] + var scrolls: [Scroll]? = nil + + mutating func generate(interval: CGFloat, delay: CGFloat) -> [Scroll] { + if let existing = scrolls { + return existing + } else { + scrolls = generator(interval: interval, delay: delay) + return scrolls! + } + } +} + +private extension UIResponder { + // Thanks to Phil M + // http://stackoverflow.com/questions/1340434/get-to-uiviewcontroller-from-uiview-on-iphone + + func firstAvailableViewController() -> UIViewController? { + // convenience function for casting and to "mask" the recursive function + return self.traverseResponderChainForFirstViewController() + } + + func traverseResponderChainForFirstViewController() -> UIViewController? { + if let nextResponder = self.nextResponder() { + if nextResponder.isKindOfClass(UIViewController) { + return nextResponder as? UIViewController + } else if (nextResponder.isKindOfClass(UIView)) { + return nextResponder.traverseResponderChainForFirstViewController() + } else { + return nil + } + } + return nil + } +} + +private extension CAMediaTimingFunction { + + func durationPercentageForPositionPercentage(positionPercentage: CGFloat, duration: CGFloat) -> CGFloat { + // Finds the animation duration percentage that corresponds with the given animation "position" percentage. + // Utilizes Newton's Method to solve for the parametric Bezier curve that is used by CAMediaAnimation. + + let controlPoints = self.controlPoints() + let epsilon: CGFloat = 1.0 / (100.0 * CGFloat(duration)) + + // Find the t value that gives the position percentage we want + let t_found = solveTforY(positionPercentage, epsilon: epsilon, controlPoints: controlPoints) + + // With that t, find the corresponding animation percentage + let durationPercentage = XforCurveAt(t_found, controlPoints: controlPoints) + + return durationPercentage + } + + func solveTforY(y_0: CGFloat, epsilon: CGFloat, controlPoints: [CGPoint]) -> CGFloat { + // Use Newton's Method: http://en.wikipedia.org/wiki/Newton's_method + // For first guess, use t = y (i.e. if curve were linear) + var t0 = y_0 + var t1 = y_0 + var f0, df0: CGFloat + + for _ in 0..<15 { + // Base this iteration of t1 calculated from last iteration + t0 = t1 + // Calculate f(t0) + f0 = YforCurveAt(t0, controlPoints:controlPoints) - y_0 + // Check if this is close (enough) + if (fabs(f0) < epsilon) { + // Done! + return t0 + } + // Else continue Newton's Method + df0 = derivativeCurveYValueAt(t0, controlPoints:controlPoints) + // Check if derivative is small or zero ( http://en.wikipedia.org/wiki/Newton's_method#Failure_analysis ) + if (fabs(df0) < 1e-6) { + break + } + // Else recalculate t1 + t1 = t0 - f0/df0 + } + + // Give up - shouldn't ever get here...I hope + print("MarqueeLabel: Failed to find t for Y input!") + return t0 + } + + func YforCurveAt(t: CGFloat, controlPoints:[CGPoint]) -> CGFloat { + let P0 = controlPoints[0] + let P1 = controlPoints[1] + let P2 = controlPoints[2] + let P3 = controlPoints[3] + + // Per http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves + let y0 = (pow((1.0 - t),3.0) * P0.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 y3 = (pow(t, 3.0) * P3.y) + + return y0 + y1 + y2 + y3 + } + + func XforCurveAt(t: CGFloat, controlPoints: [CGPoint]) -> CGFloat { + let P0 = controlPoints[0] + let P1 = controlPoints[1] + let P2 = controlPoints[2] + let P3 = controlPoints[3] + + // Per http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves + + let x0 = (pow((1.0 - t),3.0) * P0.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 x3 = (pow(t, 3.0) * P3.x) + + return x0 + x1 + x2 + x3 + } + + func derivativeCurveYValueAt(t: CGFloat, controlPoints: [CGPoint]) -> CGFloat { + let P0 = controlPoints[0] + let P1 = controlPoints[1] + let P2 = controlPoints[2] + let P3 = controlPoints[3] + + let dy0 = (P0.y + 3.0 * P1.y + 3.0 * P2.y - P3.y) * -3.0 + let dy1 = t * (6.0 * P0.y + 6.0 * P2.y) + let dy2 = (-3.0 * P0.y + 3.0 * P1.y) + + return dy0 * pow(t, 2.0) + dy1 + dy2 + } + + func controlPoints() -> [CGPoint] { + // Create point array to point to + var point: [Float] = [0.0, 0.0] + var pointArray = [CGPoint]() + for i in 0...3 { + self.getControlPointAtIndex(i, values: &point) + pointArray.append(CGPoint(x: CGFloat(point[0]), y: CGFloat(point[1]))) + } + + return pointArray + } +} + diff --git a/MarqueeLabel.podspec b/MarqueeLabel.podspec index 163fc553..24e1903a 100644 --- a/MarqueeLabel.podspec +++ b/MarqueeLabel.podspec @@ -1,14 +1,28 @@ Pod::Spec.new do |s| s.name = "MarqueeLabel" - s.version = "2.4.1" + s.version = "2.7.0" s.summary = "A drop-in replacement for UILabel, which automatically adds a scrolling marquee effect when needed." s.homepage = "https://github.com/cbpowell/MarqueeLabel" s.license = { :type => 'MIT', :file => 'LICENSE' } - s.author = { "Charles Powell" => "cbpowell@gmail.com" } + s.author = "Charles Powell" s.source = { :git => "https://github.com/cbpowell/MarqueeLabel.git", :tag => s.version.to_s } + s.public_header_files = 'Classes/ObjC/MarqueeLabel.h' + s.frameworks = 'UIKit', 'QuartzCore' + s.requires_arc = true s.ios.deployment_target = '6.0' s.tvos.deployment_target = '9.0' - s.source_files = 'MarqueeLabel.{h,m}' - s.frameworks = 'QuartzCore' - s.requires_arc = true + + s.default_subspec = 'ObjC' + + s.subspec 'ObjC' do |ss| + ss.ios.deployment_target = '6.0' + ss.tvos.deployment_target = '9.0' + ss.source_files = 'Classes/**/*.{h,m}' + end + + s.subspec 'Swift' do |ss| + ss.ios.deployment_target = '8.0' + ss.tvos.deployment_target = '9.0' + ss.source_files = 'Classes/**/*.swift' + end end diff --git a/MarqueeLabel.xcworkspace/contents.xcworkspacedata b/MarqueeLabel.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..a54462d6 --- /dev/null +++ b/MarqueeLabel.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/MarqueeLabel/AppDelegate.h b/MarqueeLabel/AppDelegate.h new file mode 100644 index 00000000..a8bc3e69 --- /dev/null +++ b/MarqueeLabel/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// MarqueeLabel +// +// Created by Charles Powell on 3/27/16. +// Copyright © 2016 Charles Powell. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/MarqueeLabel/AppDelegate.m b/MarqueeLabel/AppDelegate.m new file mode 100644 index 00000000..51082052 --- /dev/null +++ b/MarqueeLabel/AppDelegate.m @@ -0,0 +1,45 @@ +// +// AppDelegate.m +// MarqueeLabel +// +// Created by Charles Powell on 3/27/16. +// Copyright © 2016 Charles Powell. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // 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. + // 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. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // 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. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // 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. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // 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. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/MarqueeLabel/Assets.xcassets/AppIcon.appiconset/Contents.json b/MarqueeLabel/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..118c98f7 --- /dev/null +++ b/MarqueeLabel/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabel/Base.lproj/LaunchScreen.storyboard b/MarqueeLabel/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..323bd431 --- /dev/null +++ b/MarqueeLabel/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MarqueeLabel/Info.plist b/MarqueeLabel/Info.plist new file mode 100644 index 00000000..c9c43bab --- /dev/null +++ b/MarqueeLabel/Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + MarqueeLabel + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/MarqueeLabelDemo/MLHeader.xib b/MarqueeLabel/MLHeader.xib similarity index 100% rename from MarqueeLabelDemo/MLHeader.xib rename to MarqueeLabel/MLHeader.xib diff --git a/MarqueeLabelDemo/MarqueeLabel.storyboard b/MarqueeLabel/MarqueeLabel.storyboard similarity index 100% rename from MarqueeLabelDemo/MarqueeLabel.storyboard rename to MarqueeLabel/MarqueeLabel.storyboard diff --git a/MarqueeLabel/MarqueeLabel.xcodeproj/project.pbxproj b/MarqueeLabel/MarqueeLabel.xcodeproj/project.pbxproj new file mode 100644 index 00000000..6d04f73d --- /dev/null +++ b/MarqueeLabel/MarqueeLabel.xcodeproj/project.pbxproj @@ -0,0 +1,484 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + EAE4AC071CA8B5A6006C1ECC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = EAE4AC051CA8B5A6006C1ECC /* AppDelegate.m */; }; + EAE4AC081CA8B5A6006C1ECC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAE4AC061CA8B5A6006C1ECC /* Assets.xcassets */; }; + EAE4AC0A1CA8B5D0006C1ECC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = EAE4AC091CA8B5D0006C1ECC /* main.m */; }; + EAE4AC0C1CA8B5D5006C1ECC /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = EAE4AC0B1CA8B5D5006C1ECC /* Info.plist */; }; + EAE4AC0E1CA8B5DD006C1ECC /* MarqueeLabel.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EAE4AC0D1CA8B5DD006C1ECC /* MarqueeLabel.storyboard */; }; + EAE4AC241CA8B756006C1ECC /* MarqueeLabelDemoPushController.m in Sources */ = {isa = PBXBuildFile; fileRef = EAE4AC1D1CA8B756006C1ECC /* MarqueeLabelDemoPushController.m */; }; + EAE4AC251CA8B756006C1ECC /* MarqueeLabelDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EAE4AC1F1CA8B756006C1ECC /* MarqueeLabelDemoViewController.m */; }; + EAE4AC261CA8B756006C1ECC /* MarqueeLabelTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EAE4AC211CA8B756006C1ECC /* MarqueeLabelTableViewController.m */; }; + EAE4AC271CA8B756006C1ECC /* ModalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EAE4AC231CA8B756006C1ECC /* ModalViewController.m */; }; + EAE4AC2D1CA8B794006C1ECC /* MLHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = EAE4AC2C1CA8B794006C1ECC /* MLHeader.xib */; }; + EAE4AC541CA8B83D006C1ECC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EAE4AC521CA8B83D006C1ECC /* LaunchScreen.storyboard */; }; + EAE4AC741CA8DCBB006C1ECC /* MarqueeLabel_Umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE4AC731CA8DCBB006C1ECC /* MarqueeLabel_Umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EAE4ACD31CAA24E2006C1ECC /* MarqueeLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE4ACD11CAA24E2006C1ECC /* MarqueeLabel.h */; }; + EAE4ACD41CAA24E2006C1ECC /* MarqueeLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = EAE4ACD21CAA24E2006C1ECC /* MarqueeLabel.m */; }; + EAE4ACD51CAA24E2006C1ECC /* MarqueeLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = EAE4ACD21CAA24E2006C1ECC /* MarqueeLabel.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + EA167CDF1CA8B40C00DBF930 /* MarqueeLabelDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MarqueeLabelDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + EAE4AC041CA8B5A6006C1ECC /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; }; + EAE4AC051CA8B5A6006C1ECC /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; }; + EAE4AC061CA8B5A6006C1ECC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = SOURCE_ROOT; }; + EAE4AC091CA8B5D0006C1ECC /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = SOURCE_ROOT; }; + EAE4AC0B1CA8B5D5006C1ECC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; + EAE4AC0D1CA8B5DD006C1ECC /* MarqueeLabel.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MarqueeLabel.storyboard; sourceTree = SOURCE_ROOT; }; + EAE4AC1C1CA8B756006C1ECC /* MarqueeLabelDemoPushController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MarqueeLabelDemoPushController.h; path = Support/MarqueeLabelDemoPushController.h; sourceTree = SOURCE_ROOT; }; + EAE4AC1D1CA8B756006C1ECC /* MarqueeLabelDemoPushController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MarqueeLabelDemoPushController.m; path = Support/MarqueeLabelDemoPushController.m; sourceTree = SOURCE_ROOT; }; + EAE4AC1E1CA8B756006C1ECC /* MarqueeLabelDemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MarqueeLabelDemoViewController.h; path = Support/MarqueeLabelDemoViewController.h; sourceTree = SOURCE_ROOT; }; + EAE4AC1F1CA8B756006C1ECC /* MarqueeLabelDemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MarqueeLabelDemoViewController.m; path = Support/MarqueeLabelDemoViewController.m; sourceTree = SOURCE_ROOT; }; + EAE4AC201CA8B756006C1ECC /* MarqueeLabelTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MarqueeLabelTableViewController.h; path = Support/MarqueeLabelTableViewController.h; sourceTree = SOURCE_ROOT; }; + EAE4AC211CA8B756006C1ECC /* MarqueeLabelTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MarqueeLabelTableViewController.m; path = Support/MarqueeLabelTableViewController.m; sourceTree = SOURCE_ROOT; }; + EAE4AC221CA8B756006C1ECC /* ModalViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModalViewController.h; path = Support/ModalViewController.h; sourceTree = SOURCE_ROOT; }; + EAE4AC231CA8B756006C1ECC /* ModalViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ModalViewController.m; path = Support/ModalViewController.m; sourceTree = SOURCE_ROOT; }; + EAE4AC2C1CA8B794006C1ECC /* MLHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MLHeader.xib; sourceTree = SOURCE_ROOT; }; + EAE4AC531CA8B83D006C1ECC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = SOURCE_ROOT; }; + EAE4AC711CA8DCBB006C1ECC /* MarqueeLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MarqueeLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EAE4AC731CA8DCBB006C1ECC /* MarqueeLabel_Umbrella.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MarqueeLabel_Umbrella.h; sourceTree = ""; }; + EAE4AC751CA8DCBB006C1ECC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EAE4AC791CA8DE27006C1ECC /* module.map */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.map; sourceTree = ""; }; + EAE4ACD11CAA24E2006C1ECC /* MarqueeLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MarqueeLabel.h; path = ../../Classes/ObjC/MarqueeLabel.h; sourceTree = ""; }; + EAE4ACD21CAA24E2006C1ECC /* MarqueeLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MarqueeLabel.m; path = ../../Classes/ObjC/MarqueeLabel.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + EA167CDC1CA8B40C00DBF930 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAE4AC6D1CA8DCBB006C1ECC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + EA167CD61CA8B40C00DBF930 = { + isa = PBXGroup; + children = ( + EA167CE11CA8B40C00DBF930 /* MarqueeLabel Demo */, + EAE4AC721CA8DCBB006C1ECC /* MarqueeLabel Framework */, + EA167CE01CA8B40C00DBF930 /* Products */, + ); + sourceTree = ""; + }; + EA167CE01CA8B40C00DBF930 /* Products */ = { + isa = PBXGroup; + children = ( + EA167CDF1CA8B40C00DBF930 /* MarqueeLabelDemo.app */, + EAE4AC711CA8DCBB006C1ECC /* MarqueeLabel.framework */, + ); + name = Products; + sourceTree = ""; + }; + EA167CE11CA8B40C00DBF930 /* MarqueeLabel Demo */ = { + isa = PBXGroup; + children = ( + EAE4AC281CA8B75E006C1ECC /* Classes */, + EAE4AC0F1CA8B624006C1ECC /* Support */, + EAE4AC2E1CA8B79B006C1ECC /* Interface */, + EA167CE21CA8B40C00DBF930 /* Supporting Files */, + ); + name = "MarqueeLabel Demo"; + path = MarqueeLabel; + sourceTree = ""; + }; + EA167CE21CA8B40C00DBF930 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + EAE4AC061CA8B5A6006C1ECC /* Assets.xcassets */, + EAE4AC0B1CA8B5D5006C1ECC /* Info.plist */, + EAE4AC041CA8B5A6006C1ECC /* AppDelegate.h */, + EAE4AC051CA8B5A6006C1ECC /* AppDelegate.m */, + EAE4AC091CA8B5D0006C1ECC /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + EAE4AC0F1CA8B624006C1ECC /* Support */ = { + isa = PBXGroup; + children = ( + EAE4AC1E1CA8B756006C1ECC /* MarqueeLabelDemoViewController.h */, + EAE4AC1F1CA8B756006C1ECC /* MarqueeLabelDemoViewController.m */, + EAE4AC1C1CA8B756006C1ECC /* MarqueeLabelDemoPushController.h */, + EAE4AC1D1CA8B756006C1ECC /* MarqueeLabelDemoPushController.m */, + EAE4AC201CA8B756006C1ECC /* MarqueeLabelTableViewController.h */, + EAE4AC211CA8B756006C1ECC /* MarqueeLabelTableViewController.m */, + EAE4AC221CA8B756006C1ECC /* ModalViewController.h */, + EAE4AC231CA8B756006C1ECC /* ModalViewController.m */, + ); + name = Support; + sourceTree = ""; + }; + EAE4AC281CA8B75E006C1ECC /* Classes */ = { + isa = PBXGroup; + children = ( + EAE4ACD11CAA24E2006C1ECC /* MarqueeLabel.h */, + EAE4ACD21CAA24E2006C1ECC /* MarqueeLabel.m */, + ); + name = Classes; + sourceTree = ""; + }; + EAE4AC2E1CA8B79B006C1ECC /* Interface */ = { + isa = PBXGroup; + children = ( + EAE4AC521CA8B83D006C1ECC /* LaunchScreen.storyboard */, + EAE4AC0D1CA8B5DD006C1ECC /* MarqueeLabel.storyboard */, + EAE4AC2C1CA8B794006C1ECC /* MLHeader.xib */, + ); + name = Interface; + sourceTree = ""; + }; + EAE4AC721CA8DCBB006C1ECC /* MarqueeLabel Framework */ = { + isa = PBXGroup; + children = ( + EAE4AC731CA8DCBB006C1ECC /* MarqueeLabel_Umbrella.h */, + EAE4AC751CA8DCBB006C1ECC /* Info.plist */, + EAE4AC791CA8DE27006C1ECC /* module.map */, + ); + name = "MarqueeLabel Framework"; + path = MarqueeLabel; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + EAE4AC6E1CA8DCBB006C1ECC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + EAE4ACD31CAA24E2006C1ECC /* MarqueeLabel.h in Headers */, + EAE4AC741CA8DCBB006C1ECC /* MarqueeLabel_Umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + EA167CDE1CA8B40C00DBF930 /* MarqueeLabelDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = EA167CF61CA8B40C00DBF930 /* Build configuration list for PBXNativeTarget "MarqueeLabelDemo" */; + buildPhases = ( + EA167CDB1CA8B40C00DBF930 /* Sources */, + EA167CDC1CA8B40C00DBF930 /* Frameworks */, + EA167CDD1CA8B40C00DBF930 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MarqueeLabelDemo; + productName = MarqueeLabel; + productReference = EA167CDF1CA8B40C00DBF930 /* MarqueeLabelDemo.app */; + productType = "com.apple.product-type.application"; + }; + EAE4AC701CA8DCBB006C1ECC /* MarqueeLabel */ = { + isa = PBXNativeTarget; + buildConfigurationList = EAE4AC761CA8DCBB006C1ECC /* Build configuration list for PBXNativeTarget "MarqueeLabel" */; + buildPhases = ( + EAE4AC6C1CA8DCBB006C1ECC /* Sources */, + EAE4AC6D1CA8DCBB006C1ECC /* Frameworks */, + EAE4AC6E1CA8DCBB006C1ECC /* Headers */, + EAE4AC6F1CA8DCBB006C1ECC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MarqueeLabel; + productName = MarqueeLabel; + productReference = EAE4AC711CA8DCBB006C1ECC /* MarqueeLabel.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + EA167CD71CA8B40C00DBF930 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = "Charles Powell"; + TargetAttributes = { + EA167CDE1CA8B40C00DBF930 = { + CreatedOnToolsVersion = 7.3; + }; + EAE4AC701CA8DCBB006C1ECC = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = EA167CDA1CA8B40C00DBF930 /* Build configuration list for PBXProject "MarqueeLabel" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = EA167CD61CA8B40C00DBF930; + productRefGroup = EA167CE01CA8B40C00DBF930 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + EA167CDE1CA8B40C00DBF930 /* MarqueeLabelDemo */, + EAE4AC701CA8DCBB006C1ECC /* MarqueeLabel */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + EA167CDD1CA8B40C00DBF930 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EAE4AC081CA8B5A6006C1ECC /* Assets.xcassets in Resources */, + EAE4AC0E1CA8B5DD006C1ECC /* MarqueeLabel.storyboard in Resources */, + EAE4AC0C1CA8B5D5006C1ECC /* Info.plist in Resources */, + EAE4AC541CA8B83D006C1ECC /* LaunchScreen.storyboard in Resources */, + EAE4AC2D1CA8B794006C1ECC /* MLHeader.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAE4AC6F1CA8DCBB006C1ECC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + EA167CDB1CA8B40C00DBF930 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EAE4AC0A1CA8B5D0006C1ECC /* main.m in Sources */, + EAE4AC261CA8B756006C1ECC /* MarqueeLabelTableViewController.m in Sources */, + EAE4AC271CA8B756006C1ECC /* ModalViewController.m in Sources */, + EAE4ACD41CAA24E2006C1ECC /* MarqueeLabel.m in Sources */, + EAE4AC071CA8B5A6006C1ECC /* AppDelegate.m in Sources */, + EAE4AC251CA8B756006C1ECC /* MarqueeLabelDemoViewController.m in Sources */, + EAE4AC241CA8B756006C1ECC /* MarqueeLabelDemoPushController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAE4AC6C1CA8DCBB006C1ECC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EAE4ACD51CAA24E2006C1ECC /* MarqueeLabel.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + EAE4AC521CA8B83D006C1ECC /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + EAE4AC531CA8B83D006C1ECC /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + EA167CF41CA8B40C00DBF930 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + EA167CF51CA8B40C00DBF930 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + EA167CF71CA8B40C00DBF930 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + EA167CF81CA8B40C00DBF930 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + EAE4AC771CA8DCBB006C1ECC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = MarqueeLabel/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "$(PRODUCT_NAME)/module.map"; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabel; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + EAE4AC781CA8DCBB006C1ECC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = MarqueeLabel/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "$(PRODUCT_NAME)/module.map"; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabel; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + EA167CDA1CA8B40C00DBF930 /* Build configuration list for PBXProject "MarqueeLabel" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EA167CF41CA8B40C00DBF930 /* Debug */, + EA167CF51CA8B40C00DBF930 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EA167CF61CA8B40C00DBF930 /* Build configuration list for PBXNativeTarget "MarqueeLabelDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EA167CF71CA8B40C00DBF930 /* Debug */, + EA167CF81CA8B40C00DBF930 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EAE4AC761CA8DCBB006C1ECC /* Build configuration list for PBXNativeTarget "MarqueeLabel" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EAE4AC771CA8DCBB006C1ECC /* Debug */, + EAE4AC781CA8DCBB006C1ECC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = EA167CD71CA8B40C00DBF930 /* Project object */; +} diff --git a/MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/xcshareddata/xcschemes/MarqueeLabel.xcscheme b/MarqueeLabel/MarqueeLabel.xcodeproj/xcshareddata/xcschemes/MarqueeLabel.xcscheme similarity index 84% rename from MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/xcshareddata/xcschemes/MarqueeLabel.xcscheme rename to MarqueeLabel/MarqueeLabel.xcodeproj/xcshareddata/xcschemes/MarqueeLabel.xcscheme index e04b4804..34e121d2 100644 --- a/MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/xcshareddata/xcschemes/MarqueeLabel.xcscheme +++ b/MarqueeLabel/MarqueeLabel.xcodeproj/xcshareddata/xcschemes/MarqueeLabel.xcscheme @@ -1,6 +1,6 @@ + ReferencedContainer = "container:MarqueeLabel.xcodeproj"> @@ -45,10 +45,10 @@ + ReferencedContainer = "container:MarqueeLabel.xcodeproj"> @@ -63,10 +63,10 @@ + ReferencedContainer = "container:MarqueeLabel.xcodeproj"> diff --git a/MarqueeLabelDemo/MarqueeLabel/Info.plist b/MarqueeLabel/MarqueeLabel/Info.plist similarity index 100% rename from MarqueeLabelDemo/MarqueeLabel/Info.plist rename to MarqueeLabel/MarqueeLabel/Info.plist diff --git a/MarqueeLabelDemo/MarqueeLabel/MarqueeLabel_Umbrella.h b/MarqueeLabel/MarqueeLabel/MarqueeLabel_Umbrella.h old mode 100644 new mode 100755 similarity index 92% rename from MarqueeLabelDemo/MarqueeLabel/MarqueeLabel_Umbrella.h rename to MarqueeLabel/MarqueeLabel/MarqueeLabel_Umbrella.h index 4f90d76f..08a14a53 --- a/MarqueeLabelDemo/MarqueeLabel/MarqueeLabel_Umbrella.h +++ b/MarqueeLabel/MarqueeLabel/MarqueeLabel_Umbrella.h @@ -15,4 +15,4 @@ FOUNDATION_EXPORT double MarqueeLabelVersionNumber; FOUNDATION_EXPORT const unsigned char MarqueeLabelVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import -#import +#import \ No newline at end of file diff --git a/MarqueeLabel/MarqueeLabel/module.map b/MarqueeLabel/MarqueeLabel/module.map new file mode 100644 index 00000000..6e20303d --- /dev/null +++ b/MarqueeLabel/MarqueeLabel/module.map @@ -0,0 +1,6 @@ +framework module MarqueeLabel { + umbrella header "MarqueeLabel_Umbrella.h" + + export * + module * { export * } +} \ No newline at end of file diff --git a/MarqueeLabelDemo/MarqueeLabelDemo_Prefix.pch b/MarqueeLabel/MarqueeLabelDemo_Prefix.pch similarity index 100% rename from MarqueeLabelDemo/MarqueeLabelDemo_Prefix.pch rename to MarqueeLabel/MarqueeLabelDemo_Prefix.pch diff --git a/MarqueeLabelDemo/Classes/MarqueeLabelDemoPushController.h b/MarqueeLabel/Support/MarqueeLabelDemoPushController.h similarity index 100% rename from MarqueeLabelDemo/Classes/MarqueeLabelDemoPushController.h rename to MarqueeLabel/Support/MarqueeLabelDemoPushController.h diff --git a/MarqueeLabelDemo/Classes/MarqueeLabelDemoPushController.m b/MarqueeLabel/Support/MarqueeLabelDemoPushController.m similarity index 100% rename from MarqueeLabelDemo/Classes/MarqueeLabelDemoPushController.m rename to MarqueeLabel/Support/MarqueeLabelDemoPushController.m diff --git a/MarqueeLabelDemo/Classes/MarqueeLabelDemoViewController.h b/MarqueeLabel/Support/MarqueeLabelDemoViewController.h similarity index 100% rename from MarqueeLabelDemo/Classes/MarqueeLabelDemoViewController.h rename to MarqueeLabel/Support/MarqueeLabelDemoViewController.h diff --git a/MarqueeLabelDemo/Classes/MarqueeLabelDemoViewController.m b/MarqueeLabel/Support/MarqueeLabelDemoViewController.m similarity index 100% rename from MarqueeLabelDemo/Classes/MarqueeLabelDemoViewController.m rename to MarqueeLabel/Support/MarqueeLabelDemoViewController.m diff --git a/MarqueeLabelDemo/Classes/MarqueeLabelTableViewController.h b/MarqueeLabel/Support/MarqueeLabelTableViewController.h similarity index 100% rename from MarqueeLabelDemo/Classes/MarqueeLabelTableViewController.h rename to MarqueeLabel/Support/MarqueeLabelTableViewController.h diff --git a/MarqueeLabelDemo/Classes/MarqueeLabelTableViewController.m b/MarqueeLabel/Support/MarqueeLabelTableViewController.m similarity index 100% rename from MarqueeLabelDemo/Classes/MarqueeLabelTableViewController.m rename to MarqueeLabel/Support/MarqueeLabelTableViewController.m diff --git a/MarqueeLabelDemo/Classes/ModalViewController.h b/MarqueeLabel/Support/ModalViewController.h similarity index 100% rename from MarqueeLabelDemo/Classes/ModalViewController.h rename to MarqueeLabel/Support/ModalViewController.h diff --git a/MarqueeLabelDemo/Classes/ModalViewController.m b/MarqueeLabel/Support/ModalViewController.m similarity index 100% rename from MarqueeLabelDemo/Classes/ModalViewController.m rename to MarqueeLabel/Support/ModalViewController.m diff --git a/MarqueeLabelDemo/main.m b/MarqueeLabel/main.m similarity index 52% rename from MarqueeLabelDemo/main.m rename to MarqueeLabel/main.m index aba72d2b..43dd41f9 100644 --- a/MarqueeLabelDemo/main.m +++ b/MarqueeLabel/main.m @@ -3,15 +3,14 @@ // MarqueeLabelDemo // // Created by Charles Powell on 1/31/11. -// Copyright 2011 __MyCompanyName__. All rights reserved. +// Copyright 2011 Charles Powell. All rights reserved. // #import +#import "AppDelegate.h" -#import "MarqueeLabelDemoAppDelegate.h" - -int main(int argc, char *argv[]) { +int main(int argc, char * argv[]) { @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([MarqueeLabelDemoAppDelegate class])); + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } -} +} \ No newline at end of file diff --git a/MarqueeLabelDemo-Swift/MarqueeLabelDemo-Swift/MarqueeLabelDemoViewController.swift b/MarqueeLabelDemo-Swift/MarqueeLabelDemo-Swift/MarqueeLabelDemoViewController.swift new file mode 100644 index 00000000..e69de29b diff --git a/MarqueeLabelDemo.gif b/MarqueeLabelDemo.gif index 464121b2..2811a0ed 100644 Binary files a/MarqueeLabelDemo.gif and b/MarqueeLabelDemo.gif differ diff --git a/MarqueeLabelDemo/Classes/MarqueeLabelDemoAppDelegate.h b/MarqueeLabelDemo/Classes/MarqueeLabelDemoAppDelegate.h deleted file mode 100644 index e0266e7b..00000000 --- a/MarqueeLabelDemo/Classes/MarqueeLabelDemoAppDelegate.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// MarqueeLabelDemoAppDelegate.h -// MarqueeLabelDemo -// -// Created by Charles Powell on 1/31/11. -// Copyright 2011 __MyCompanyName__. All rights reserved. -// - -#import - -@class MarqueeLabelDemoViewController; - -@interface MarqueeLabelDemoAppDelegate : NSObject { - UIWindow *window; - MarqueeLabelDemoViewController *viewController; -} - -@property (nonatomic, strong) IBOutlet UIWindow *window; -@property (nonatomic, strong) IBOutlet MarqueeLabelDemoViewController *viewController; - -@end - diff --git a/MarqueeLabelDemo/Classes/MarqueeLabelDemoAppDelegate.m b/MarqueeLabelDemo/Classes/MarqueeLabelDemoAppDelegate.m deleted file mode 100644 index c84fd031..00000000 --- a/MarqueeLabelDemo/Classes/MarqueeLabelDemoAppDelegate.m +++ /dev/null @@ -1,75 +0,0 @@ -// -// MarqueeLabelDemoAppDelegate.m -// MarqueeLabelDemo -// -// Created by Charles Powell on 1/31/11. -// Copyright 2011 __MyCompanyName__. All rights reserved. -// - -#import "MarqueeLabelDemoAppDelegate.h" -#import "MarqueeLabelDemoViewController.h" - -@implementation MarqueeLabelDemoAppDelegate - -@synthesize window; -@synthesize viewController; - - -#pragma mark - -#pragma mark Application lifecycle - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - return YES; -} - -- (void)applicationWillResignActive:(UIApplication *)application { - /* - 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. - 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. - */ -} - - -- (void)applicationDidEnterBackground:(UIApplication *)application { - /* - 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. - If your application supports background execution, called instead of applicationWillTerminate: when the user quits. - */ -} - - -- (void)applicationWillEnterForeground:(UIApplication *)application { - /* - Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background. - */ -} - - -- (void)applicationDidBecomeActive:(UIApplication *)application { - /* - 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. - */ -} - - -- (void)applicationWillTerminate:(UIApplication *)application { - /* - Called when the application is about to terminate. - See also applicationDidEnterBackground:. - */ -} - - -#pragma mark - -#pragma mark Memory management - -- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { - /* - Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. - */ -} - - - - -@end diff --git a/MarqueeLabelDemo/MarqueeLabel/module.map b/MarqueeLabelDemo/MarqueeLabel/module.map deleted file mode 100644 index 7cc0194b..00000000 --- a/MarqueeLabelDemo/MarqueeLabel/module.map +++ /dev/null @@ -1,6 +0,0 @@ -framework module MarqueeLabel { - umbrella header "MarqueeLabel_Umbrella.h" - - export * - module * { export * } -} diff --git a/MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/project.pbxproj b/MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/project.pbxproj deleted file mode 100755 index f0938ce7..00000000 --- a/MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/project.pbxproj +++ /dev/null @@ -1,501 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1D3623260D0F684500981E51 /* MarqueeLabelDemoAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* MarqueeLabelDemoAppDelegate.m */; }; - 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; - 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; - 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; - 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; }; - 28D7ACF80DDB3853001CB0EB /* MarqueeLabelDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D7ACF70DDB3853001CB0EB /* MarqueeLabelDemoViewController.m */; }; - 46EB5C141BB316DF005D2672 /* MarqueeLabel_Umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 46EB5C131BB316DF005D2672 /* MarqueeLabel_Umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 46EB5C191BB316FE005D2672 /* MarqueeLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = EA646A1312F7A5B000F31B16 /* MarqueeLabel.m */; }; - 46EB5C241BB31A69005D2672 /* MarqueeLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = EA646A1212F7A5B000F31B16 /* MarqueeLabel.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 46EB5C2A1BB31D90005D2672 /* module.map in Resources */ = {isa = PBXBuildFile; fileRef = 46EB5C291BB31D90005D2672 /* module.map */; }; - EA0E9AD41974C20200033CD7 /* MarqueeLabel.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EA0E9AD31974C20200033CD7 /* MarqueeLabel.storyboard */; }; - EA1BAE471CA7242D00D709A9 /* MLHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = EA1BAE461CA7242D00D709A9 /* MLHeader.xib */; }; - EA646A1412F7A5B000F31B16 /* MarqueeLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = EA646A1312F7A5B000F31B16 /* MarqueeLabel.m */; }; - EABFD31A150D55CC00216FCE /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EABFD319150D55CC00216FCE /* QuartzCore.framework */; }; - EAC1338E1CA501FD00E1A50D /* MarqueeLabelDemoPushController.m in Sources */ = {isa = PBXBuildFile; fileRef = EAC1338D1CA501FD00E1A50D /* MarqueeLabelDemoPushController.m */; }; - EAC133911CA61CF300E1A50D /* MarqueeLabelTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EAC133901CA61CF300E1A50D /* MarqueeLabelTableViewController.m */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 1D3623240D0F684500981E51 /* MarqueeLabelDemoAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarqueeLabelDemoAppDelegate.h; sourceTree = ""; }; - 1D3623250D0F684500981E51 /* MarqueeLabelDemoAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MarqueeLabelDemoAppDelegate.m; sourceTree = ""; }; - 1D6058910D05DD3D006BFB54 /* MarqueeLabelDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MarqueeLabelDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 28D7ACF60DDB3853001CB0EB /* MarqueeLabelDemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarqueeLabelDemoViewController.h; sourceTree = ""; }; - 28D7ACF70DDB3853001CB0EB /* MarqueeLabelDemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MarqueeLabelDemoViewController.m; sourceTree = ""; }; - 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 32CA4F630368D1EE00C91783 /* MarqueeLabelDemo_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarqueeLabelDemo_Prefix.pch; sourceTree = ""; }; - 46EB5C111BB316DF005D2672 /* MarqueeLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MarqueeLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 46EB5C131BB316DF005D2672 /* MarqueeLabel_Umbrella.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MarqueeLabel_Umbrella.h; sourceTree = ""; }; - 46EB5C151BB316DF005D2672 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 46EB5C291BB31D90005D2672 /* module.map */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.map; sourceTree = ""; }; - 8B660C7D16BCFEEF007F9463 /* MarqueeLabelDemoNibs-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "MarqueeLabelDemoNibs-Info.plist"; path = "/Users/cbpowell/Projects/MarqueeLabel/MarqueeLabelDemo/MarqueeLabelDemoNibs-Info.plist"; sourceTree = ""; }; - 8D1107310486CEB800E47090 /* MarqueeLabelDemo-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MarqueeLabelDemo-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; - EA0E9AD31974C20200033CD7 /* MarqueeLabel.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MarqueeLabel.storyboard; sourceTree = ""; }; - EA1BAE461CA7242D00D709A9 /* MLHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MLHeader.xib; sourceTree = ""; }; - EA41461716D340B4004A3B02 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; - EA646A1212F7A5B000F31B16 /* MarqueeLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MarqueeLabel.h; path = ../MarqueeLabel.h; sourceTree = SOURCE_ROOT; }; - EA646A1312F7A5B000F31B16 /* MarqueeLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MarqueeLabel.m; path = ../MarqueeLabel.m; sourceTree = SOURCE_ROOT; }; - EABFD319150D55CC00216FCE /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - EAC1338C1CA501FD00E1A50D /* MarqueeLabelDemoPushController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarqueeLabelDemoPushController.h; sourceTree = ""; }; - EAC1338D1CA501FD00E1A50D /* MarqueeLabelDemoPushController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MarqueeLabelDemoPushController.m; sourceTree = ""; }; - EAC1338F1CA61CF300E1A50D /* MarqueeLabelTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarqueeLabelTableViewController.h; sourceTree = ""; }; - EAC133901CA61CF300E1A50D /* MarqueeLabelTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MarqueeLabelTableViewController.m; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EABFD31A150D55CC00216FCE /* QuartzCore.framework in Frameworks */, - 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, - 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, - 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 46EB5C0D1BB316DF005D2672 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 080E96DDFE201D6D7F000001 /* Classes */ = { - isa = PBXGroup; - children = ( - 28D7ACF60DDB3853001CB0EB /* MarqueeLabelDemoViewController.h */, - 28D7ACF70DDB3853001CB0EB /* MarqueeLabelDemoViewController.m */, - 1D3623240D0F684500981E51 /* MarqueeLabelDemoAppDelegate.h */, - 1D3623250D0F684500981E51 /* MarqueeLabelDemoAppDelegate.m */, - EAC1338C1CA501FD00E1A50D /* MarqueeLabelDemoPushController.h */, - EAC1338D1CA501FD00E1A50D /* MarqueeLabelDemoPushController.m */, - EAC1338F1CA61CF300E1A50D /* MarqueeLabelTableViewController.h */, - EAC133901CA61CF300E1A50D /* MarqueeLabelTableViewController.m */, - ); - path = Classes; - sourceTree = ""; - }; - 19C28FACFE9D520D11CA2CBB /* Products */ = { - isa = PBXGroup; - children = ( - 1D6058910D05DD3D006BFB54 /* MarqueeLabelDemo.app */, - 46EB5C111BB316DF005D2672 /* MarqueeLabel.framework */, - ); - name = Products; - sourceTree = ""; - }; - 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { - isa = PBXGroup; - children = ( - EA0E9AD31974C20200033CD7 /* MarqueeLabel.storyboard */, - EA0E9AD51974C2AA00033CD7 /* Sources */, - 080E96DDFE201D6D7F000001 /* Classes */, - 29B97315FDCFA39411CA2CEA /* Other Sources */, - 29B97317FDCFA39411CA2CEA /* Resources */, - 46EB5C121BB316DF005D2672 /* MarqueeLabel */, - 29B97323FDCFA39411CA2CEA /* Frameworks */, - 19C28FACFE9D520D11CA2CBB /* Products */, - ); - name = CustomTemplate; - sourceTree = ""; - }; - 29B97315FDCFA39411CA2CEA /* Other Sources */ = { - isa = PBXGroup; - children = ( - 32CA4F630368D1EE00C91783 /* MarqueeLabelDemo_Prefix.pch */, - 29B97316FDCFA39411CA2CEA /* main.m */, - ); - name = "Other Sources"; - sourceTree = ""; - }; - 29B97317FDCFA39411CA2CEA /* Resources */ = { - isa = PBXGroup; - children = ( - 8D1107310486CEB800E47090 /* MarqueeLabelDemo-Info.plist */, - 8B660C7D16BCFEEF007F9463 /* MarqueeLabelDemoNibs-Info.plist */, - EA1BAE461CA7242D00D709A9 /* MLHeader.xib */, - ); - name = Resources; - sourceTree = ""; - }; - 29B97323FDCFA39411CA2CEA /* Frameworks */ = { - isa = PBXGroup; - children = ( - EA41461716D340B4004A3B02 /* CoreText.framework */, - EABFD319150D55CC00216FCE /* QuartzCore.framework */, - 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, - 1D30AB110D05D00D00671497 /* Foundation.framework */, - 288765A40DF7441C002DB57D /* CoreGraphics.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 46EB5C121BB316DF005D2672 /* MarqueeLabel */ = { - isa = PBXGroup; - children = ( - 46EB5C131BB316DF005D2672 /* MarqueeLabel_Umbrella.h */, - 46EB5C151BB316DF005D2672 /* Info.plist */, - 46EB5C291BB31D90005D2672 /* module.map */, - ); - path = MarqueeLabel; - sourceTree = ""; - }; - EA0E9AD51974C2AA00033CD7 /* Sources */ = { - isa = PBXGroup; - children = ( - EA646A1212F7A5B000F31B16 /* MarqueeLabel.h */, - EA646A1312F7A5B000F31B16 /* MarqueeLabel.m */, - ); - name = Sources; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 46EB5C0E1BB316DF005D2672 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 46EB5C141BB316DF005D2672 /* MarqueeLabel_Umbrella.h in Headers */, - 46EB5C241BB31A69005D2672 /* MarqueeLabel.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 1D6058900D05DD3D006BFB54 /* MarqueeLabelDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "MarqueeLabelDemo" */; - buildPhases = ( - 1D60588D0D05DD3D006BFB54 /* Resources */, - 1D60588E0D05DD3D006BFB54 /* Sources */, - 1D60588F0D05DD3D006BFB54 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = MarqueeLabelDemo; - productName = MarqueeLabelDemo; - productReference = 1D6058910D05DD3D006BFB54 /* MarqueeLabelDemo.app */; - productType = "com.apple.product-type.application"; - }; - 46EB5C101BB316DF005D2672 /* MarqueeLabel */ = { - isa = PBXNativeTarget; - buildConfigurationList = 46EB5C181BB316DF005D2672 /* Build configuration list for PBXNativeTarget "MarqueeLabel" */; - buildPhases = ( - 46EB5C0C1BB316DF005D2672 /* Sources */, - 46EB5C0D1BB316DF005D2672 /* Frameworks */, - 46EB5C0E1BB316DF005D2672 /* Headers */, - 46EB5C0F1BB316DF005D2672 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = MarqueeLabel; - productName = MarqueeLabel; - productReference = 46EB5C111BB316DF005D2672 /* MarqueeLabel.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 29B97313FDCFA39411CA2CEA /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0700; - TargetAttributes = { - 1D6058900D05DD3D006BFB54 = { - DevelopmentTeam = K573DL86KG; - }; - 46EB5C101BB316DF005D2672 = { - CreatedOnToolsVersion = 7.0; - }; - }; - }; - buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MarqueeLabelDemo" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 1; - knownRegions = ( - English, - Japanese, - French, - German, - ); - mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 1D6058900D05DD3D006BFB54 /* MarqueeLabelDemo */, - 46EB5C101BB316DF005D2672 /* MarqueeLabel */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 1D60588D0D05DD3D006BFB54 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - EA0E9AD41974C20200033CD7 /* MarqueeLabel.storyboard in Resources */, - EA1BAE471CA7242D00D709A9 /* MLHeader.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 46EB5C0F1BB316DF005D2672 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 46EB5C2A1BB31D90005D2672 /* module.map in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 1D60588E0D05DD3D006BFB54 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1D60589B0D05DD56006BFB54 /* main.m in Sources */, - 1D3623260D0F684500981E51 /* MarqueeLabelDemoAppDelegate.m in Sources */, - 28D7ACF80DDB3853001CB0EB /* MarqueeLabelDemoViewController.m in Sources */, - EAC133911CA61CF300E1A50D /* MarqueeLabelTableViewController.m in Sources */, - EAC1338E1CA501FD00E1A50D /* MarqueeLabelDemoPushController.m in Sources */, - EA646A1412F7A5B000F31B16 /* MarqueeLabel.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 46EB5C0C1BB316DF005D2672 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 46EB5C191BB316FE005D2672 /* MarqueeLabel.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 1D6058940D05DD3E006BFB54 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = MarqueeLabelDemo_Prefix.pch; - INFOPLIST_FILE = "MarqueeLabelDemo-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelDemo; - PRODUCT_NAME = MarqueeLabelDemo; - PROVISIONING_PROFILE = ""; - }; - name = Debug; - }; - 1D6058950D05DD3E006BFB54 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = MarqueeLabelDemo_Prefix.pch; - INFOPLIST_FILE = "MarqueeLabelDemo-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelDemo; - PRODUCT_NAME = MarqueeLabelDemo; - PROVISIONING_PROFILE = ""; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 46EB5C161BB316DF005D2672 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - INFOPLIST_FILE = MarqueeLabel/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "$(PRODUCT_NAME)/module.map"; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabel; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 46EB5C171BB316DF005D2672 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - INFOPLIST_FILE = MarqueeLabel/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "$(PRODUCT_NAME)/module.map"; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabel; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - C01FCF4F08A954540054247B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - C01FCF5008A954540054247B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - SDKROOT = iphoneos; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "MarqueeLabelDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1D6058940D05DD3E006BFB54 /* Debug */, - 1D6058950D05DD3E006BFB54 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 46EB5C181BB316DF005D2672 /* Build configuration list for PBXNativeTarget "MarqueeLabel" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 46EB5C161BB316DF005D2672 /* Debug */, - 46EB5C171BB316DF005D2672 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MarqueeLabelDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C01FCF4F08A954540054247B /* Debug */, - C01FCF5008A954540054247B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; -} diff --git a/MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/MarqueeLabelSwift/AppDelegate.swift b/MarqueeLabelSwift/AppDelegate.swift new file mode 100644 index 00000000..60c375fc --- /dev/null +++ b/MarqueeLabelSwift/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// MarqueeLabelSwift +// +// Created by Charles Powell on 3/27/16. +// Copyright © 2016 Charles Powell. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(application: UIApplication) { + // 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. + // 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. + } + + func applicationDidEnterBackground(application: UIApplication) { + // 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. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(application: UIApplication) { + // 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. + } + + func applicationDidBecomeActive(application: UIApplication) { + // 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. + } + + func applicationWillTerminate(application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/MarqueeLabelSwift/Assets.xcassets/AppIcon.appiconset/Contents.json b/MarqueeLabelSwift/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..118c98f7 --- /dev/null +++ b/MarqueeLabelSwift/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelSwift/Assets.xcassets/Contents.json b/MarqueeLabelSwift/Assets.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelSwift/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelSwift/Base.lproj/LaunchScreen.storyboard b/MarqueeLabelSwift/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..323bd431 --- /dev/null +++ b/MarqueeLabelSwift/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MarqueeLabelSwift/Info.plist b/MarqueeLabelSwift/Info.plist new file mode 100644 index 00000000..ddef8d2f --- /dev/null +++ b/MarqueeLabelSwift/Info.plist @@ -0,0 +1,44 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIcons + + CFBundleIcons~ipad + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + MarqueeLabel + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/MarqueeLabelSwift/MLHeader.xib b/MarqueeLabelSwift/MLHeader.xib new file mode 100644 index 00000000..a2e1b51c --- /dev/null +++ b/MarqueeLabelSwift/MLHeader.xib @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MarqueeLabelSwift/MarqueeLabel.storyboard b/MarqueeLabelSwift/MarqueeLabel.storyboard new file mode 100644 index 00000000..71daa7e5 --- /dev/null +++ b/MarqueeLabelSwift/MarqueeLabel.storyboard @@ -0,0 +1,503 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MarqueeLabelSwift/MarqueeLabelDemoPushController.swift b/MarqueeLabelSwift/MarqueeLabelDemoPushController.swift new file mode 100644 index 00000000..39ffe1a9 --- /dev/null +++ b/MarqueeLabelSwift/MarqueeLabelDemoPushController.swift @@ -0,0 +1,32 @@ +// +// MarqueeLabelDemoPushController.swift +// MarqueeLabelDemo +// +// Created by Charles Powell on 3/26/16. +// +// + +import UIKit + +class MarqueeLabelDemoPushController: UIViewController { + @IBOutlet weak var demoLabel: MarqueeLabel! + + override func viewDidLoad() { + super.viewDidLoad() + + demoLabel.type = .Continuous + demoLabel.speed = .Duration(15) + demoLabel.animationCurve = .EaseInOut + demoLabel.fadeLength = 10.0 + demoLabel.leadingBuffer = 30.0 + + let strings = ["When shall we three meet again in thunder, lightning, or in rain? When the hurlyburly's done, When the battle 's lost and won.", + "I have no spur to prick the sides of my intent, but only vaulting ambition, which o'erleaps itself, and falls on the other.", + "Double, double toil and trouble; Fire burn, and cauldron bubble.", + "By the pricking of my thumbs, Something wicked this way comes.", + "My favorite things in life don't cost any money. It's really clear that the most precious resource we all have is time.", + "Be a yardstick of quality. Some people aren't used to an environment where excellence is expected."] + + demoLabel.text = strings[Int(arc4random_uniform(UInt32(strings.count)))] + } +} \ No newline at end of file diff --git a/MarqueeLabelSwift/MarqueeLabelDemoViewController.swift b/MarqueeLabelSwift/MarqueeLabelDemoViewController.swift new file mode 100644 index 00000000..f3edd805 --- /dev/null +++ b/MarqueeLabelSwift/MarqueeLabelDemoViewController.swift @@ -0,0 +1,230 @@ +/** +* Copyright (c) 2014 Charles Powell +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +// +// MarqueeLabelDemoViewController.swift +// MarqueeLabelDemo-Swift +// + +import UIKit + +class MarqueeLabelDemoViewController : UIViewController { + + @IBOutlet weak var demoLabel1: MarqueeLabel! + @IBOutlet weak var demoLabel2: MarqueeLabel! + @IBOutlet weak var demoLabel3: MarqueeLabel! + @IBOutlet weak var demoLabel4: MarqueeLabel! + @IBOutlet weak var demoLabel5: MarqueeLabel! + @IBOutlet weak var demoLabel6: MarqueeLabel! + + @IBOutlet weak var labelizeSwitch: UISwitch! + @IBOutlet weak var holdLabelsSwitch: UISwitch! + @IBOutlet weak var pauseLabelsSwitch: UISwitch! + + override func viewDidLoad() { + super.viewDidLoad() + + // Continuous Type + demoLabel1.tag = 101 + demoLabel1.type = .Continuous + demoLabel1.speed = .Duration(15) + demoLabel1.animationCurve = .EaseInOut + demoLabel1.fadeLength = 10.0 + demoLabel1.leadingBuffer = 30.0 + demoLabel1.trailingBuffer = 20.0 + // Text string for this label is set via Interface Builder! + + + // Reverse Continuous Type, with attributed string + demoLabel2.tag = 201 + demoLabel2.type = .ContinuousReverse + demoLabel2.textAlignment = .Right + demoLabel2.lineBreakMode = .ByTruncatingHead + demoLabel2.speed = .Duration(8.0) + demoLabel2.fadeLength = 15.0 + demoLabel2.leadingBuffer = 40.0 + + let attributedString2 = NSMutableAttributedString(string:"This is a long string, that's also an attributed string, which works just as well!") + attributedString2.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size: 18)!, range: NSMakeRange(0, 21)) + attributedString2.addAttribute(NSBackgroundColorAttributeName, value: UIColor.lightGrayColor(), range: NSMakeRange(0, 14)) + attributedString2.addAttribute(NSForegroundColorAttributeName, value: UIColor(red: 0.234, green: 0.234, blue: 0.234, alpha: 1.0), range: NSMakeRange(0, attributedString2.length)) + attributedString2.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue-Light", size: 18)!, range: NSMakeRange(21, attributedString2.length - 21)) + demoLabel2.attributedText = attributedString2 + + + // Left/right example, with rate usage + demoLabel3.tag = 301 + demoLabel3.type = .LeftRight + demoLabel3.speed = .Rate(60) + demoLabel3.fadeLength = 10.0 + demoLabel3.leadingBuffer = 30.0 + demoLabel3.trailingBuffer = 20.0 + demoLabel3.textAlignment = .Center + demoLabel3.text = "This is another long label that scrolls at a specific rate, rather than scrolling its length in a defined time window!" + + + // Right/left example, with tap to scroll + demoLabel4.tag = 401 + demoLabel4.type = .RightLeft + demoLabel4.textAlignment = .Right + demoLabel4.lineBreakMode = .ByTruncatingHead + demoLabel4.tapToScroll = true + demoLabel4.trailingBuffer = 20.0 + demoLabel4.text = "This label will not scroll until tapped, and then it performs its scroll cycle only once. Tap me!" + + + // Continuous, with tap to pause + demoLabel5.tag = 501 + demoLabel5.type = .Continuous + demoLabel5.speed = .Duration(10) + demoLabel5.fadeLength = 10.0 + demoLabel5.trailingBuffer = 30.0 + demoLabel5.text = "This text is long, and can be paused with a tap - handled via a UIGestureRecognizer!" + + demoLabel5.userInteractionEnabled = true // Don't forget this, otherwise the gesture recognizer will fail (UILabel has this as NO by default) + let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(pauseTap)) + tapRecognizer.numberOfTapsRequired = 1 + tapRecognizer.numberOfTouchesRequired = 1 + demoLabel5.addGestureRecognizer(tapRecognizer) + + // Continuous, with attributed text + demoLabel6.tag = 601 + demoLabel6.type = .Continuous + demoLabel6.speed = .Duration(15.0) + demoLabel6.fadeLength = 10.0 + demoLabel6.trailingBuffer = 30.0 + + let attributedString6 = NSMutableAttributedString(string:"This is a long, attributed string, that's set up to loop in a continuous fashion!") + attributedString6.addAttribute(NSForegroundColorAttributeName, value: UIColor(red: 0.123, green: 0.331, blue: 0.657, alpha: 1.000), range: NSMakeRange(0,34)) + attributedString6.addAttribute(NSForegroundColorAttributeName, value: UIColor(red: 0.657, green: 0.096, blue: 0.088, alpha: 1.000), range: NSMakeRange(34, attributedString6.length - 34)) + attributedString6.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue-Light", size:18.0)!, range: NSMakeRange(0, 16)) + attributedString6.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue-Light", size:18.0)!, range: NSMakeRange(33, attributedString6.length - 33)) + demoLabel6.attributedText = attributedString6; + } + + override func viewWillAppear(animated: Bool) { + super.viewWillAppear(animated) + + // If you have trouble with MarqueeLabel instances not automatically scrolling, implement the + // viewWillAppear bulk method as seen below. This will attempt to restart scrolling on all + // MarqueeLabels associated (in the view hierarchy) with the calling view controller + + // MarqueeLabel.controllerViewWillAppear(self) + + // Or.... (see below) + } + + override func viewDidAppear(animated: Bool) { + super.viewDidAppear(animated) + + // Or you could use viewDidAppear bulk method - try both to see which works best for you! + + // MarqueeLabel.controllerViewDidAppear(self) + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + @IBAction func changeLabelTexts(sender: AnyObject) { + // Use demoLabel1 tag to store "state" + if (demoLabel1.tag == 101) { + demoLabel1.text = "This label is not as long." + demoLabel3.text = "This is a short, centered label." + + let attributedString2 = NSMutableAttributedString(string: "This is a different longer string, but still an attributed string, with new different attributes!") + attributedString2.addAttribute(NSForegroundColorAttributeName, value: UIColor.blackColor(), range: NSMakeRange(0, attributedString2.length)) + attributedString2.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size:18.0)!, range:NSMakeRange(0, attributedString2.length)) + attributedString2.addAttribute(NSBackgroundColorAttributeName, value: UIColor(white:0.600, alpha:1.000), range:NSMakeRange(0,33)) + attributedString2.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue-Light", size:18.0)!, range:NSMakeRange(19, attributedString2.length - 19)) + demoLabel2.attributedText = attributedString2; + + let attributedString6 = NSMutableAttributedString(string: "This is a different, longer, attributed string, that's set up to loop in a continuous fashion!") + attributedString6.addAttribute(NSForegroundColorAttributeName, value:UIColor(red:0.657, green:0.078, blue:0.067, alpha:1.000), range:NSMakeRange(0,attributedString6.length)) + attributedString6.addAttribute(NSFontAttributeName, value:UIFont(name: "HelveticaNeue-Light", size:18.0)!, range:NSMakeRange(0, 16)) + attributedString6.addAttribute(NSFontAttributeName, value:UIFont(name: "HelveticaNeue-Light", size:18.0)!, range:NSMakeRange(33, attributedString6.length - 33)) + attributedString6.addAttribute(NSForegroundColorAttributeName, value: UIColor(red:0.123, green:0.331, blue:0.657, alpha:1.000), range:NSMakeRange(33, attributedString6.length - 33)) + demoLabel6.attributedText = attributedString6; + + demoLabel1.tag = 102; + } else { + demoLabel1.text = "This is a test of MarqueeLabel - the text is long enough that it needs to scroll to see the whole thing."; + demoLabel3.text = "That also scrolls left, then right, rather than in a continuous loop!" + + let attributedString2 = NSMutableAttributedString(string: "This is a long string, that's also an attributed string, which works just as well!") + attributedString2.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size:18.0)!, range:NSMakeRange(0, 21)) + attributedString2.addAttribute(NSBackgroundColorAttributeName, value: UIColor.lightGrayColor(), range:NSMakeRange(10,11)) + attributedString2.addAttribute(NSForegroundColorAttributeName, value: UIColor(red:0.234, green:0.234, blue:0.234, alpha:1.000), range:NSMakeRange(0,attributedString2.length)) + attributedString2.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue-Light", size:18.0)!, range: NSMakeRange(21, attributedString2.length - 21)) + demoLabel2.attributedText = attributedString2 + + let attributedString6 = NSMutableAttributedString(string: "This is a long, attributed string, that's set up to loop in a continuous fashion!") + attributedString6.addAttribute(NSForegroundColorAttributeName, value:UIColor(red:0.123, green:0.331, blue:0.657, alpha:1.000), range:NSMakeRange(0,attributedString6.length)) + attributedString6.addAttribute(NSFontAttributeName, value:UIFont(name: "HelveticaNeue-Light", size:18.0)!, range:NSMakeRange(0, 16)) + attributedString6.addAttribute(NSFontAttributeName, value:UIFont(name: "HelveticaNeue-Light", size:18.0)!, range:NSMakeRange(33, attributedString6.length - 33)) + demoLabel6.attributedText = attributedString6 + + demoLabel1.tag = 101; + } + } + + func pauseTap(recognizer: UIGestureRecognizer) { + let continuousLabel2 = recognizer.view as! MarqueeLabel + if recognizer.state == .Ended { + continuousLabel2.isPaused ? continuousLabel2.unpauseLabel() : continuousLabel2.pauseLabel() + } + } + + @IBAction func labelizeSwitched(sender: UISwitch) { + if sender.on { + MarqueeLabel.controllerLabelsLabelize(self) + } else { + MarqueeLabel.controllerLabelsAnimate(self) + } + } + + @IBAction func holdLabelsSwitched(sender: UISwitch) { + for pv in view.subviews as [UIView] { + if let v = pv as? MarqueeLabel { + v.holdScrolling = sender.on + } + } + } + + @IBAction func togglePause(sender: UISwitch) { + for pv in view.subviews as [UIView] { + if let v = pv as? MarqueeLabel { + sender.on ? v.pauseLabel() : v.unpauseLabel() + } + } + } + + @IBAction func unwindModalPopoverSegue(segue: UIStoryboardSegue) { + // Empty by design + } + +} + diff --git a/MarqueeLabelSwift/MarqueeLabelSwift.xcodeproj/project.pbxproj b/MarqueeLabelSwift/MarqueeLabelSwift.xcodeproj/project.pbxproj new file mode 100644 index 00000000..01f25999 --- /dev/null +++ b/MarqueeLabelSwift/MarqueeLabelSwift.xcodeproj/project.pbxproj @@ -0,0 +1,454 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + EAE4AC591CA8DAC0006C1ECC /* MLHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = EAE4AC581CA8DAC0006C1ECC /* MLHeader.xib */; }; + EAE4AC5B1CA8DAC8006C1ECC /* MarqueeLabel.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EAE4AC5A1CA8DAC8006C1ECC /* MarqueeLabel.storyboard */; }; + EAE4AC5F1CA8DAFB006C1ECC /* MarqueeLabelDemoPushController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4AC5C1CA8DAFB006C1ECC /* MarqueeLabelDemoPushController.swift */; }; + EAE4AC601CA8DAFB006C1ECC /* MarqueeLabelDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4AC5D1CA8DAFB006C1ECC /* MarqueeLabelDemoViewController.swift */; }; + EAE4AC611CA8DAFB006C1ECC /* MarqueeLabelTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4AC5E1CA8DAFB006C1ECC /* MarqueeLabelTableViewController.swift */; }; + EAE4AC661CA8DBBA006C1ECC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4AC651CA8DBBA006C1ECC /* AppDelegate.swift */; }; + EAE4AC691CA8DBDC006C1ECC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EAE4AC671CA8DBDC006C1ECC /* LaunchScreen.storyboard */; }; + EAE4AC6B1CA8DC10006C1ECC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAE4AC6A1CA8DC10006C1ECC /* Assets.xcassets */; }; + EAE4ACCF1CAA2495006C1ECC /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4ACCE1CAA2495006C1ECC /* MarqueeLabel.swift */; }; + EAE4ACD01CAA2495006C1ECC /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4ACCE1CAA2495006C1ECC /* MarqueeLabel.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + EA167D021CA8B43700DBF930 /* MarqueeLabelSwiftDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MarqueeLabelSwiftDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + EA167D111CA8B43700DBF930 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EAE4AC581CA8DAC0006C1ECC /* MLHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MLHeader.xib; sourceTree = SOURCE_ROOT; }; + EAE4AC5A1CA8DAC8006C1ECC /* MarqueeLabel.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MarqueeLabel.storyboard; sourceTree = SOURCE_ROOT; }; + EAE4AC5C1CA8DAFB006C1ECC /* MarqueeLabelDemoPushController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarqueeLabelDemoPushController.swift; sourceTree = SOURCE_ROOT; }; + EAE4AC5D1CA8DAFB006C1ECC /* MarqueeLabelDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarqueeLabelDemoViewController.swift; sourceTree = SOURCE_ROOT; }; + EAE4AC5E1CA8DAFB006C1ECC /* MarqueeLabelTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarqueeLabelTableViewController.swift; sourceTree = SOURCE_ROOT; }; + EAE4AC651CA8DBBA006C1ECC /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = SOURCE_ROOT; }; + EAE4AC681CA8DBDC006C1ECC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = SOURCE_ROOT; }; + EAE4AC6A1CA8DC10006C1ECC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = SOURCE_ROOT; }; + EAE4AC7F1CA8DE70006C1ECC /* MarqueeLabelSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MarqueeLabelSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EAE4AC831CA8DE70006C1ECC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EAE4ACCE1CAA2495006C1ECC /* MarqueeLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MarqueeLabel.swift; path = ../../Classes/Swift/MarqueeLabel.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + EA167CFF1CA8B43700DBF930 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAE4AC7B1CA8DE70006C1ECC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + EA167CF91CA8B43700DBF930 = { + isa = PBXGroup; + children = ( + EA167D041CA8B43700DBF930 /* MarqueeLabelSwift Demo */, + EAE4AC801CA8DE70006C1ECC /* MarqueeLabelSwift Framework */, + EA167D031CA8B43700DBF930 /* Products */, + ); + sourceTree = ""; + }; + EA167D031CA8B43700DBF930 /* Products */ = { + isa = PBXGroup; + children = ( + EA167D021CA8B43700DBF930 /* MarqueeLabelSwiftDemo.app */, + EAE4AC7F1CA8DE70006C1ECC /* MarqueeLabelSwift.framework */, + ); + name = Products; + sourceTree = ""; + }; + EA167D041CA8B43700DBF930 /* MarqueeLabelSwift Demo */ = { + isa = PBXGroup; + children = ( + EAE4AC551CA8DAA1006C1ECC /* Classes */, + EAE4AC561CA8DAA4006C1ECC /* Support */, + EAE4AC571CA8DAAB006C1ECC /* Interface */, + EAE4AC641CA8DB84006C1ECC /* Supporting Files */, + ); + name = "MarqueeLabelSwift Demo"; + path = MarqueeLabelSwift; + sourceTree = ""; + }; + EAE4AC551CA8DAA1006C1ECC /* Classes */ = { + isa = PBXGroup; + children = ( + EAE4ACCE1CAA2495006C1ECC /* MarqueeLabel.swift */, + ); + name = Classes; + sourceTree = ""; + }; + EAE4AC561CA8DAA4006C1ECC /* Support */ = { + isa = PBXGroup; + children = ( + EAE4AC5D1CA8DAFB006C1ECC /* MarqueeLabelDemoViewController.swift */, + EAE4AC5C1CA8DAFB006C1ECC /* MarqueeLabelDemoPushController.swift */, + EAE4AC5E1CA8DAFB006C1ECC /* MarqueeLabelTableViewController.swift */, + ); + name = Support; + sourceTree = ""; + }; + EAE4AC571CA8DAAB006C1ECC /* Interface */ = { + isa = PBXGroup; + children = ( + EAE4AC671CA8DBDC006C1ECC /* LaunchScreen.storyboard */, + EAE4AC5A1CA8DAC8006C1ECC /* MarqueeLabel.storyboard */, + EAE4AC581CA8DAC0006C1ECC /* MLHeader.xib */, + ); + name = Interface; + sourceTree = ""; + }; + EAE4AC641CA8DB84006C1ECC /* Supporting Files */ = { + isa = PBXGroup; + children = ( + EAE4AC6A1CA8DC10006C1ECC /* Assets.xcassets */, + EA167D111CA8B43700DBF930 /* Info.plist */, + EAE4AC651CA8DBBA006C1ECC /* AppDelegate.swift */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + EAE4AC801CA8DE70006C1ECC /* MarqueeLabelSwift Framework */ = { + isa = PBXGroup; + children = ( + EAE4AC831CA8DE70006C1ECC /* Info.plist */, + ); + name = "MarqueeLabelSwift Framework"; + path = MarqueeLabelSwift; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + EAE4AC7C1CA8DE70006C1ECC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + EA167D011CA8B43700DBF930 /* MarqueeLabelSwiftDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = EA167D141CA8B43700DBF930 /* Build configuration list for PBXNativeTarget "MarqueeLabelSwiftDemo" */; + buildPhases = ( + EA167CFE1CA8B43700DBF930 /* Sources */, + EA167CFF1CA8B43700DBF930 /* Frameworks */, + EA167D001CA8B43700DBF930 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MarqueeLabelSwiftDemo; + productName = MarqueeLabelSwift; + productReference = EA167D021CA8B43700DBF930 /* MarqueeLabelSwiftDemo.app */; + productType = "com.apple.product-type.application"; + }; + EAE4AC7E1CA8DE70006C1ECC /* MarqueeLabelSwift */ = { + isa = PBXNativeTarget; + buildConfigurationList = EAE4AC841CA8DE70006C1ECC /* Build configuration list for PBXNativeTarget "MarqueeLabelSwift" */; + buildPhases = ( + EAE4AC7A1CA8DE70006C1ECC /* Sources */, + EAE4AC7B1CA8DE70006C1ECC /* Frameworks */, + EAE4AC7C1CA8DE70006C1ECC /* Headers */, + EAE4AC7D1CA8DE70006C1ECC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MarqueeLabelSwift; + productName = MarqueeLabelSwift; + productReference = EAE4AC7F1CA8DE70006C1ECC /* MarqueeLabelSwift.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + EA167CFA1CA8B43700DBF930 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0730; + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = "Charles Powell"; + TargetAttributes = { + EA167D011CA8B43700DBF930 = { + CreatedOnToolsVersion = 7.3; + }; + EAE4AC7E1CA8DE70006C1ECC = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = EA167CFD1CA8B43700DBF930 /* Build configuration list for PBXProject "MarqueeLabelSwift" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = EA167CF91CA8B43700DBF930; + productRefGroup = EA167D031CA8B43700DBF930 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + EA167D011CA8B43700DBF930 /* MarqueeLabelSwiftDemo */, + EAE4AC7E1CA8DE70006C1ECC /* MarqueeLabelSwift */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + EA167D001CA8B43700DBF930 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EAE4AC591CA8DAC0006C1ECC /* MLHeader.xib in Resources */, + EAE4AC691CA8DBDC006C1ECC /* LaunchScreen.storyboard in Resources */, + EAE4AC6B1CA8DC10006C1ECC /* Assets.xcassets in Resources */, + EAE4AC5B1CA8DAC8006C1ECC /* MarqueeLabel.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAE4AC7D1CA8DE70006C1ECC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + EA167CFE1CA8B43700DBF930 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EAE4AC5F1CA8DAFB006C1ECC /* MarqueeLabelDemoPushController.swift in Sources */, + EAE4AC601CA8DAFB006C1ECC /* MarqueeLabelDemoViewController.swift in Sources */, + EAE4ACCF1CAA2495006C1ECC /* MarqueeLabel.swift in Sources */, + EAE4AC661CA8DBBA006C1ECC /* AppDelegate.swift in Sources */, + EAE4AC611CA8DAFB006C1ECC /* MarqueeLabelTableViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAE4AC7A1CA8DE70006C1ECC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EAE4ACD01CAA2495006C1ECC /* MarqueeLabel.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + EAE4AC671CA8DBDC006C1ECC /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + EAE4AC681CA8DBDC006C1ECC /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + EA167D121CA8B43700DBF930 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + EA167D131CA8B43700DBF930 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + EA167D151CA8B43700DBF930 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelSwiftDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + EA167D161CA8B43700DBF930 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelSwiftDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + EAE4AC851CA8DE70006C1ECC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = MarqueeLabelSwift/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = ""; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelSwift; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + EAE4AC861CA8DE70006C1ECC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = MarqueeLabelSwift/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = ""; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelSwift; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + EA167CFD1CA8B43700DBF930 /* Build configuration list for PBXProject "MarqueeLabelSwift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EA167D121CA8B43700DBF930 /* Debug */, + EA167D131CA8B43700DBF930 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EA167D141CA8B43700DBF930 /* Build configuration list for PBXNativeTarget "MarqueeLabelSwiftDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EA167D151CA8B43700DBF930 /* Debug */, + EA167D161CA8B43700DBF930 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EAE4AC841CA8DE70006C1ECC /* Build configuration list for PBXNativeTarget "MarqueeLabelSwift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EAE4AC851CA8DE70006C1ECC /* Debug */, + EAE4AC861CA8DE70006C1ECC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = EA167CFA1CA8B43700DBF930 /* Project object */; +} diff --git a/MarqueeLabelSwift/MarqueeLabelSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MarqueeLabelSwift/MarqueeLabelSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..8feb9e1f --- /dev/null +++ b/MarqueeLabelSwift/MarqueeLabelSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/xcshareddata/xcschemes/MarqueeLabelDemo.xcscheme b/MarqueeLabelSwift/MarqueeLabelSwift.xcodeproj/xcshareddata/xcschemes/MarqueeLabelSwift.xcscheme similarity index 52% rename from MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/xcshareddata/xcschemes/MarqueeLabelDemo.xcscheme rename to MarqueeLabelSwift/MarqueeLabelSwift.xcodeproj/xcshareddata/xcschemes/MarqueeLabelSwift.xcscheme index 886bcc31..12bd78d5 100644 --- a/MarqueeLabelDemo/MarqueeLabelDemo.xcodeproj/xcshareddata/xcschemes/MarqueeLabelDemo.xcscheme +++ b/MarqueeLabelSwift/MarqueeLabelSwift.xcodeproj/xcshareddata/xcschemes/MarqueeLabelSwift.xcscheme @@ -1,7 +1,7 @@ + LastUpgradeVersion = "0730" + version = "1.3"> @@ -14,10 +14,10 @@ buildForAnalyzing = "YES"> + BlueprintIdentifier = "EAE4AC7E1CA8DE70006C1ECC" + BuildableName = "MarqueeLabelSwift.framework" + BlueprintName = "MarqueeLabelSwift" + ReferencedContainer = "container:MarqueeLabelSwift.xcodeproj"> @@ -25,29 +25,10 @@ - - - - - - - - @@ -55,45 +36,39 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - displayScaleIsEnabled = "NO" - displayScale = "1.00" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> - + + BlueprintIdentifier = "EAE4AC7E1CA8DE70006C1ECC" + BuildableName = "MarqueeLabelSwift.framework" + BlueprintName = "MarqueeLabelSwift" + ReferencedContainer = "container:MarqueeLabelSwift.xcodeproj"> - + - + + BlueprintIdentifier = "EAE4AC7E1CA8DE70006C1ECC" + BuildableName = "MarqueeLabelSwift.framework" + BlueprintName = "MarqueeLabelSwift" + ReferencedContainer = "container:MarqueeLabelSwift.xcodeproj"> - + diff --git a/MarqueeLabelDemo/MarqueeLabelDemoNibs-Info.plist b/MarqueeLabelSwift/MarqueeLabelSwift/Info.plist similarity index 58% rename from MarqueeLabelDemo/MarqueeLabelDemoNibs-Info.plist rename to MarqueeLabelSwift/MarqueeLabelSwift/Info.plist index 32894445..d3de8eef 100644 --- a/MarqueeLabelDemo/MarqueeLabelDemoNibs-Info.plist +++ b/MarqueeLabelSwift/MarqueeLabelSwift/Info.plist @@ -3,28 +3,24 @@ CFBundleDevelopmentRegion - English - CFBundleDisplayName - ${PRODUCT_NAME} + en CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIconFile - + $(EXECUTABLE_NAME) CFBundleIdentifier - com.yourcompany.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName - ${PRODUCT_NAME} + $(PRODUCT_NAME) CFBundlePackageType - APPL + FMWK + CFBundleShortVersionString + 1.0 CFBundleSignature ???? CFBundleVersion - 1.0 - LSRequiresIPhoneOS - - NSMainNibFile - MainWindow + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + diff --git a/MarqueeLabelSwift/MarqueeLabelTableViewController.swift b/MarqueeLabelSwift/MarqueeLabelTableViewController.swift new file mode 100644 index 00000000..bd8a749f --- /dev/null +++ b/MarqueeLabelSwift/MarqueeLabelTableViewController.swift @@ -0,0 +1,94 @@ +// +// MarqueeLabelTableViewController.swift +// MarqueeLabelDemo +// +// Created by Charles Powell on 3/26/16. +// +// + +import UIKit + +class MarqueeLabelTableViewController: UITableViewController { + let strings = ["When shall we three meet again in thunder, lightning, or in rain? When the hurlyburly's done, When the battle 's lost and won.", + "I have no spur to prick the sides of my intent, but only vaulting ambition, which o'erleaps itself, and falls on the other.", + "Double, double toil and trouble; Fire burn, and cauldron bubble.", + "By the pricking of my thumbs, Something wicked this way comes.", + "My favorite things in life don't cost any money. It's really clear that the most precious resource we all have is time.", + "Be a yardstick of quality. Some people aren't used to an environment where excellence is expected."] + + override func viewDidLoad() { + if let tabBar = tabBarController?.tabBar { + var tabBarInsets = UIEdgeInsetsMake(0.0, 0.0, CGRectGetHeight(tabBar.bounds), 0.0) + tableView.contentInset = tabBarInsets + tabBarInsets.top = 84 + tableView.scrollIndicatorInsets = tabBarInsets + } + + let headerNib = UINib(nibName: "MLHeader", bundle:nil) + tableView.registerNib(headerNib, forHeaderFooterViewReuseIdentifier: "MLHeader") + } + + override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return 1 + } + + override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 30 + } + + override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + return tableView.dequeueReusableHeaderFooterViewWithIdentifier("MLHeader") + } + + override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 84.0 + } + + override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCellWithIdentifier("MLCell", forIndexPath: indexPath) as! MLCell + + cell.label.text = strings[Int(arc4random_uniform(UInt32(strings.count)))] + cell.label.type = .Continuous + cell.label.speed = .Duration(15) + cell.label.animationCurve = .EaseInOut + cell.label.fadeLength = 10.0 + cell.label.leadingBuffer = 14.0 + + // Labelize normally, to improve scroll performance + cell.label.labelize = true + + // Set background, to improve scroll performance + cell.backgroundColor = UIColor.whiteColor() + + return cell + } + + override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + tableView.deselectRowAtIndexPath(indexPath, animated: true) + let cell = tableView.cellForRowAtIndexPath(indexPath) as! MLCell + + // De-labelize on selection + cell.label.labelize = false + } + + override func scrollViewDidScroll(scrollView: UIScrollView) { + // Re-labelize all scrolling labels on tableview scroll + for cell in tableView.visibleCells as! [MLCell] { + cell.label.labelize = true + } + + // Animate border + let header = tableView.headerViewForSection(0) as! MLHeader + UIView.animateWithDuration(0.2) { + header.border.alpha = (scrollView.contentOffset.y > 1.0 ? 1.0 : 0.0) + } + } +} + +class MLCell: UITableViewCell { + @IBOutlet weak var label: MarqueeLabel! +} + +class MLHeader: UITableViewHeaderFooterView { + @IBOutlet weak var border: UIView! +} diff --git a/MarqueeLabelTV/AppDelegate.swift b/MarqueeLabelTV/AppDelegate.swift new file mode 100644 index 00000000..43e26329 --- /dev/null +++ b/MarqueeLabelTV/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// MarqueeLabelTV +// +// Created by Charles Powell on 3/28/16. +// Copyright © 2016 Charles Powell. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(application: UIApplication) { + // 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. + // 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. + } + + func applicationDidEnterBackground(application: UIApplication) { + // 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. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(application: UIApplication) { + // 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. + } + + func applicationDidBecomeActive(application: UIApplication) { + // 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. + } + + func applicationWillTerminate(application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json new file mode 100644 index 00000000..8bf75d9f --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json new file mode 100644 index 00000000..8bf75d9f --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json new file mode 100644 index 00000000..6a3dcfa5 --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json @@ -0,0 +1,26 @@ +{ + "assets" : [ + { + "size" : "1280x768", + "idiom" : "tv", + "filename" : "App Icon - Large.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "400x240", + "idiom" : "tv", + "filename" : "App Icon - Small.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "1920x720", + "idiom" : "tv", + "filename" : "Top Shelf Image.imageset", + "role" : "top-shelf-image" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/Contents.json b/MarqueeLabelTV/Assets.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Assets.xcassets/LaunchImage.launchimage/Contents.json b/MarqueeLabelTV/Assets.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 00000000..29d94c78 --- /dev/null +++ b/MarqueeLabelTV/Assets.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "orientation" : "landscape", + "idiom" : "tv", + "extent" : "full-screen", + "minimum-system-version" : "9.0", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/Base.lproj/Main.storyboard b/MarqueeLabelTV/Base.lproj/Main.storyboard new file mode 100644 index 00000000..5eddf2f2 --- /dev/null +++ b/MarqueeLabelTV/Base.lproj/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MarqueeLabelDemo/MarqueeLabelDemo-Info.plist b/MarqueeLabelTV/Info.plist similarity index 67% rename from MarqueeLabelDemo/MarqueeLabelDemo-Info.plist rename to MarqueeLabelTV/Info.plist index b1c047e2..20412a39 100644 --- a/MarqueeLabelDemo/MarqueeLabelDemo-Info.plist +++ b/MarqueeLabelTV/Info.plist @@ -3,32 +3,30 @@ CFBundleDevelopmentRegion - English - CFBundleDisplayName - ${PRODUCT_NAME} + en CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIconFile - + $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName - ${PRODUCT_NAME} + $(PRODUCT_NAME) CFBundlePackageType APPL + CFBundleShortVersionString + 1.0 CFBundleSignature ???? CFBundleVersion - 1.0 + 1 LSRequiresIPhoneOS - UILaunchStoryboardName - MarqueeLabel UIMainStoryboardFile MarqueeLabel - UISupportedInterfaceOrientations - + UIRequiredDeviceCapabilities + + arm64 + diff --git a/MarqueeLabelTV/MarqueeLabel.storyboard b/MarqueeLabelTV/MarqueeLabel.storyboard new file mode 100644 index 00000000..c7f1a192 --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabel.storyboard @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MarqueeLabelTV/MarqueeLabelTV.xcodeproj/project.pbxproj b/MarqueeLabelTV/MarqueeLabelTV.xcodeproj/project.pbxproj new file mode 100644 index 00000000..2fb0a7d1 --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV.xcodeproj/project.pbxproj @@ -0,0 +1,433 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + EA59ABFD1CAA274A0052AD98 /* MarqueeLabel.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EA59ABFC1CAA274A0052AD98 /* MarqueeLabel.storyboard */; }; + EA59ABFF1CAA278D0052AD98 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA59ABFE1CAA278D0052AD98 /* ViewController.swift */; }; + EA59AC011CAA28410052AD98 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA59AC001CAA28410052AD98 /* AppDelegate.swift */; }; + EA59AC0F1CAA28FF0052AD98 /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4ACD61CAA2520006C1ECC /* MarqueeLabel.swift */; }; + EAAEFA021CAA2C1A00F8D857 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAAEFA011CAA2C1A00F8D857 /* Assets.xcassets */; }; + EAE4ACD71CAA2520006C1ECC /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE4ACD61CAA2520006C1ECC /* MarqueeLabel.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + EA59ABFC1CAA274A0052AD98 /* MarqueeLabel.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MarqueeLabel.storyboard; sourceTree = SOURCE_ROOT; }; + EA59ABFE1CAA278D0052AD98 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = SOURCE_ROOT; }; + EA59AC001CAA28410052AD98 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = SOURCE_ROOT; }; + EA59AC071CAA28D80052AD98 /* MarqueeLabelTV.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MarqueeLabelTV.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EA59AC0B1CAA28D80052AD98 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EAAEFA011CAA2C1A00F8D857 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + EAE4ACB61CAA23FD006C1ECC /* MarqueeLabelTVDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MarqueeLabelTVDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + EAE4ACC21CAA23FD006C1ECC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + EAE4ACD61CAA2520006C1ECC /* MarqueeLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MarqueeLabel.swift; path = ../../Classes/Swift/MarqueeLabel.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + EA59AC031CAA28D80052AD98 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAE4ACB31CAA23FD006C1ECC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + EA59AC081CAA28D80052AD98 /* MarqueeLabelTV Framework */ = { + isa = PBXGroup; + children = ( + EA59AC0B1CAA28D80052AD98 /* Info.plist */, + ); + name = "MarqueeLabelTV Framework"; + path = MarqueeLabelTV; + sourceTree = ""; + }; + EAE4ACAD1CAA23FD006C1ECC = { + isa = PBXGroup; + children = ( + EAE4ACB81CAA23FD006C1ECC /* MarqueeLabelTV Demo */, + EA59AC081CAA28D80052AD98 /* MarqueeLabelTV Framework */, + EAE4ACB71CAA23FD006C1ECC /* Products */, + ); + sourceTree = ""; + }; + EAE4ACB71CAA23FD006C1ECC /* Products */ = { + isa = PBXGroup; + children = ( + EAE4ACB61CAA23FD006C1ECC /* MarqueeLabelTVDemo.app */, + EA59AC071CAA28D80052AD98 /* MarqueeLabelTV.framework */, + ); + name = Products; + sourceTree = ""; + }; + EAE4ACB81CAA23FD006C1ECC /* MarqueeLabelTV Demo */ = { + isa = PBXGroup; + children = ( + EAE4ACC81CAA244F006C1ECC /* Classes */, + EAE4ACC91CAA2455006C1ECC /* Support */, + EAE4ACCA1CAA245B006C1ECC /* Interface */, + EAE4ACCB1CAA2462006C1ECC /* Supporting Files */, + ); + name = "MarqueeLabelTV Demo"; + path = MarqueeLabelTV; + sourceTree = ""; + }; + EAE4ACC81CAA244F006C1ECC /* Classes */ = { + isa = PBXGroup; + children = ( + EAE4ACD61CAA2520006C1ECC /* MarqueeLabel.swift */, + ); + name = Classes; + sourceTree = ""; + }; + EAE4ACC91CAA2455006C1ECC /* Support */ = { + isa = PBXGroup; + children = ( + EA59ABFE1CAA278D0052AD98 /* ViewController.swift */, + ); + name = Support; + sourceTree = ""; + }; + EAE4ACCA1CAA245B006C1ECC /* Interface */ = { + isa = PBXGroup; + children = ( + EA59ABFC1CAA274A0052AD98 /* MarqueeLabel.storyboard */, + ); + name = Interface; + sourceTree = ""; + }; + EAE4ACCB1CAA2462006C1ECC /* Supporting Files */ = { + isa = PBXGroup; + children = ( + EA59AC001CAA28410052AD98 /* AppDelegate.swift */, + EAE4ACC21CAA23FD006C1ECC /* Info.plist */, + EAAEFA011CAA2C1A00F8D857 /* Assets.xcassets */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + EA59AC041CAA28D80052AD98 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + EA59AC061CAA28D80052AD98 /* MarqueeLabelTV */ = { + isa = PBXNativeTarget; + buildConfigurationList = EA59AC0C1CAA28D80052AD98 /* Build configuration list for PBXNativeTarget "MarqueeLabelTV" */; + buildPhases = ( + EA59AC021CAA28D80052AD98 /* Sources */, + EA59AC031CAA28D80052AD98 /* Frameworks */, + EA59AC041CAA28D80052AD98 /* Headers */, + EA59AC051CAA28D80052AD98 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MarqueeLabelTV; + productName = MarqueeLabelTV; + productReference = EA59AC071CAA28D80052AD98 /* MarqueeLabelTV.framework */; + productType = "com.apple.product-type.framework"; + }; + EAE4ACB51CAA23FD006C1ECC /* MarqueeLabelTVDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = EAE4ACC51CAA23FD006C1ECC /* Build configuration list for PBXNativeTarget "MarqueeLabelTVDemo" */; + buildPhases = ( + EAE4ACB21CAA23FD006C1ECC /* Sources */, + EAE4ACB31CAA23FD006C1ECC /* Frameworks */, + EAE4ACB41CAA23FD006C1ECC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MarqueeLabelTVDemo; + productName = MarqueeLabelTV; + productReference = EAE4ACB61CAA23FD006C1ECC /* MarqueeLabelTVDemo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + EAE4ACAE1CAA23FD006C1ECC /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0730; + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = "Charles Powell"; + TargetAttributes = { + EA59AC061CAA28D80052AD98 = { + CreatedOnToolsVersion = 7.3; + }; + EAE4ACB51CAA23FD006C1ECC = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = EAE4ACB11CAA23FD006C1ECC /* Build configuration list for PBXProject "MarqueeLabelTV" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = EAE4ACAD1CAA23FD006C1ECC; + productRefGroup = EAE4ACB71CAA23FD006C1ECC /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + EAE4ACB51CAA23FD006C1ECC /* MarqueeLabelTVDemo */, + EA59AC061CAA28D80052AD98 /* MarqueeLabelTV */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + EA59AC051CAA28D80052AD98 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAE4ACB41CAA23FD006C1ECC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EAAEFA021CAA2C1A00F8D857 /* Assets.xcassets in Resources */, + EA59ABFD1CAA274A0052AD98 /* MarqueeLabel.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + EA59AC021CAA28D80052AD98 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EA59AC0F1CAA28FF0052AD98 /* MarqueeLabel.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAE4ACB21CAA23FD006C1ECC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EA59AC011CAA28410052AD98 /* AppDelegate.swift in Sources */, + EA59ABFF1CAA278D0052AD98 /* ViewController.swift in Sources */, + EAE4ACD71CAA2520006C1ECC /* MarqueeLabel.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + EA59AC0D1CAA28D80052AD98 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = MarqueeLabelTV/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelTV; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "appletvsimulator appletvos"; + TARGETED_DEVICE_FAMILY = 3; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + EA59AC0E1CAA28D80052AD98 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = MarqueeLabelTV/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelTV; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "appletvsimulator appletvos"; + TARGETED_DEVICE_FAMILY = 3; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + EAE4ACC31CAA23FD006C1ECC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = appletvos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.2; + }; + name = Debug; + }; + EAE4ACC41CAA23FD006C1ECC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = appletvos; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.2; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + EAE4ACC61CAA23FD006C1ECC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelTV; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + EAE4ACC71CAA23FD006C1ECC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.charlespowell.MarqueeLabelTV; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + EA59AC0C1CAA28D80052AD98 /* Build configuration list for PBXNativeTarget "MarqueeLabelTV" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EA59AC0D1CAA28D80052AD98 /* Debug */, + EA59AC0E1CAA28D80052AD98 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EAE4ACB11CAA23FD006C1ECC /* Build configuration list for PBXProject "MarqueeLabelTV" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EAE4ACC31CAA23FD006C1ECC /* Debug */, + EAE4ACC41CAA23FD006C1ECC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EAE4ACC51CAA23FD006C1ECC /* Build configuration list for PBXNativeTarget "MarqueeLabelTVDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EAE4ACC61CAA23FD006C1ECC /* Debug */, + EAE4ACC71CAA23FD006C1ECC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = EAE4ACAE1CAA23FD006C1ECC /* Project object */; +} diff --git a/MarqueeLabelTV/MarqueeLabelTV.xcodeproj/xcshareddata/xcschemes/MarqueeLabelTV.xcscheme b/MarqueeLabelTV/MarqueeLabelTV.xcodeproj/xcshareddata/xcschemes/MarqueeLabelTV.xcscheme new file mode 100644 index 00000000..c685b1db --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV.xcodeproj/xcshareddata/xcschemes/MarqueeLabelTV.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json new file mode 100644 index 00000000..8bf75d9f --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json new file mode 100644 index 00000000..8bf75d9f --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json new file mode 100644 index 00000000..6a3dcfa5 --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json @@ -0,0 +1,26 @@ +{ + "assets" : [ + { + "size" : "1280x768", + "idiom" : "tv", + "filename" : "App Icon - Large.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "400x240", + "idiom" : "tv", + "filename" : "App Icon - Small.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "1920x720", + "idiom" : "tv", + "filename" : "Top Shelf Image.imageset", + "role" : "top-shelf-image" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/LaunchImage.launchimage/Contents.json b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 00000000..29d94c78 --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Assets.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "orientation" : "landscape", + "idiom" : "tv", + "extent" : "full-screen", + "minimum-system-version" : "9.0", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MarqueeLabelTV/MarqueeLabelTV/Info.plist b/MarqueeLabelTV/MarqueeLabelTV/Info.plist new file mode 100644 index 00000000..d3de8eef --- /dev/null +++ b/MarqueeLabelTV/MarqueeLabelTV/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/MarqueeLabelTV/ViewController.swift b/MarqueeLabelTV/ViewController.swift new file mode 100644 index 00000000..0be1991e --- /dev/null +++ b/MarqueeLabelTV/ViewController.swift @@ -0,0 +1,95 @@ +// +// ViewController.swift +// Demo-tvOS +// +// Created by toshi0383 on 1/9/16. +// Copyright © 2016 Charles Powell. All rights reserved. +// + +import UIKit + +let labels = [ + "Lorem ipsum dolor sit amet.", + "Lorem ipsum dolor sit amet, consectetur.", + "Lorem ipsum dolor sit amet, consectetur adipiscing.", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed id.", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed id ultricies justo.", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed id ultricies justo. Praesent eleifend."] + +let defaultScrollDuration: CGFloat = 20.0 + +class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { + + @IBOutlet var marqueeTableView: UITableView! + @IBOutlet var labelTableView: UITableView! + + override func viewDidLoad() { + super.viewDidLoad() + // MarqueeLabel Tableview + marqueeTableView.dataSource = self + marqueeTableView.delegate = self + + // Basic UILabel Tableview + labelTableView.dataSource = self + } + + func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return labels.count * 10 + } + + func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) + cell.cellText = labels[indexPath.row % labels.count] + return cell + } + + func tableView(tableView: UITableView, didUpdateFocusInContext context: UITableViewFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) { + if tableView == marqueeTableView { + if let previouslyFocusedIndexPath = context.previouslyFocusedIndexPath { + let previous = tableView.cellForRowAtIndexPath(previouslyFocusedIndexPath) as? MarqueeCell + previous?.marquee.labelize = true + } + if let nextFocusedIndexPath = context.nextFocusedIndexPath { + let next = tableView.cellForRowAtIndexPath(nextFocusedIndexPath) as? MarqueeCell + next?.marquee.labelize = false + } + } + } +} + +protocol TextCell { + var cellText: String? { get set } +} + +class MarqueeCell: UITableViewCell { + @IBOutlet var marquee: MarqueeLabel! + + override func awakeFromNib() { + // Perform initial setup + marquee.labelize = true + marquee.fadeLength = 7.0 + marquee.speed = .Duration(defaultScrollDuration) + marquee.lineBreakMode = .ByTruncatingTail + } + + override var cellText: String? { + get { + return marquee.text + } + set { + marquee.text = newValue + } + } +} + +extension UITableViewCell: TextCell { + var cellText: String? { + get { + return textLabel?.text + } + set { + textLabel?.text = newValue + } + } +} diff --git a/README.mdown b/README.mdown index f06ad29c..c9597468 100644 --- a/README.mdown +++ b/README.mdown @@ -1,11 +1,9 @@ Overview ============ -MarqueeLabel is a UILabel subclass adds a scrolling marquee effect when the text of the label outgrows the available width. The label scrolling direction and speed/rate can be specified as well. All standard UILabel properties (where it makes sense) are available in MarqueeLabel and it behaves just like a UILabel. +MarqueeLabel is a UILabel subclass adds a scrolling marquee effect when the text of the label outgrows the available width. The label scrolling direction and speed/rate can be specified as well. All standard UILabel properties (where it makes sense) are available in MarqueeLabel, with the intent of MarqueeLabel behaving just like a UILabel. -## MarqueeLabel in Swift! - -If you're implementing a project in Swift, be sure to check out the [Swift version of MarqueeLabel](https://github.com/cbpowell/MarqueeLabel-Swift)! +MarqueeLabel is compatible with both iOS and tvOS! ## Check it out! ![GIF of MarqueeLabelDemo in action](https://raw.githubusercontent.com/cbpowell/MarqueeLabel/master/MarqueeLabelDemo.gif) @@ -21,10 +19,16 @@ If you're implementing a project in Swift, be sure to check out the [Swift versi ### Installation #### [CocoaPods](http://cocoapods.org) -Add the following to your project's Podfile: +MarqueeLabel has [subspecs](https://guides.cocoapods.org/syntax/podspec.html#subspec) for both Objective-C and Swift! Currently, Objective-C is the default subspec. + +That means to use MarqueeLabel in an Objective-C project, add the following to your project's Podfile: ```ruby pod 'MarqueeLabel' ``` +But if you're using Swift, add the following instead to specify the Swift subspec: +```ruby +pod 'MarqueeLabel/Swift' +``` #### Carthage @@ -35,34 +39,47 @@ github "cbpowell/MarqueeLabel" #### Manual Installation -1. Add MarqueeLabel.h and MarqueeLabel.m to your project. +1. Add MarqueeLabel.h and MarqueeLabel.m, or MarqueeLabel.swift, to your project. 2. Add **QuartzCore.framework** to your project frameworks. -3. Import MarqueeLabel.h and replace your UILabels with MarqueeLabels as needed. - -**Note: MarqueeLabel uses ARC.** +3. Import MarqueeLabel and replace your UILabels with MarqueeLabels as needed. ## Usage -MarqueeLabel supports scrolling the label, at either a defined rate (points per second) or over a duration (seconds), whenever the length of the label's text exceeds the space available given the label's frame. There are several options for the marquee type, and the default is `MLContinuous` (which looks just like what Apple typically uses). The animation curve of this scroll can be defined, and defaults to `UIViewAnimationOptionCurveLinear`. MarqueeLabel also features an optional fade at the left and right edges of the view, in order to fade the label text into the background rather than simply being clipped off. +MarqueeLabel automatically scrolls its text, at either a defined rate (points per second) or over a duration (seconds), whenever the length of the label's text exceeds the space available given the label's frame. + +There are several options for the Marquee type, and the default is `Continuous` (which looks just like what Apple typically uses). The animation curve of this scroll can be defined, and defaults to `UIViewAnimationOptionCurveLinear`. + +There are also several optional features to help with your integration of the scrolling nature of MarqueeLabel: +- An optional edge fade at the left and right edges of the view, in order to fade the label text into the background rather than simply being clipped off +- Leading and trailing buffers to offset the label text inside it's frame, giving you better control over alignment +- "Labelization" to make your MarqueeLabel _exactly_ like a UILabel. +- Scroll animation "holding" and pausing + +See the included demo project for several use case examples! -#### Code +### Code +These lines of code create a MarqueeLabel that will scroll across its content in 8.0 seconds, and adds 10.0 point long fade at the left and right boundaries. -To use MarqueeLabel, replace: +#### Objective-C +Replace: - UILabel *lengthyLabel = [[UILabel alloc] initWithFrame:labelCGRectFrame]; + UILabel *lengthyLabel = [[UILabel alloc] initWithFrame:aFrame]; With: - MarqueeLabel *scrollyLabel = [[MarqueeLabel alloc] initWithFrame:labelCGRectFrame duration:8.0 andFadeLength:10.0f]; + MarqueeLabel *lengthyLabel = [[MarqueeLabel alloc] initWithFrame:aFrame duration:8.0 andFadeLength:10.0f]; -This creates a MarqueeLabel that will scroll across its content in 8.0 seconds, and adds 10.0 point long fade at the left and right boundaries. +#### Swift +Replace: -If you'd rather have a label that scrolls at a specific rate (points per second), instead of completing the scroll in a specific time frame, you can use this instead: + var lengthyLabel = UILabel.init(frame:aFrame) - MarqueeLabel *scrollyLabel = [[MarqueeLabel alloc] initWithFrame:labelCGRectFrame rate:50.0 andFadeLength:10.0f]; +With: + + var lengthyLabel = MarqueeLabel.initWithFrame(frame:aFrame duration:8.0 andFadeLength:10.0) -#### Storyboards -If you're using Storyboards/Interface Builder you can create a MarqueeLabel instance by adding a normal UILabel view to your Storyboard, and then manually changing the view's class to `MarqueeLabel` in the "Custom Class" field of the Identity Inspector tab of Xcode's Utilities panel (the right-side panel). +### Storyboards +If you're using Storyboards/Interface Builder you can create a MarqueeLabel instance by adding a normal UILabel view to your Storyboard, and then manually changing the view's class to `MarqueeLabel` in the "Custom Class" field of the Identity Inspector tab on the Utilities panel (the right-side panel). _Note:_ If you forget to change the Custom Class field to `MarqueeLabel` and then try to access/set MarqueeLabel-specific properties in your code, you will get crashes! You can then configure the normal UILabel properties, as well as most of the MarqueeLabel configuration properties, via the Attributes tab of the Utility panel! @@ -72,9 +89,6 @@ You can then configure the normal UILabel properties, as well as most of the Mar Check out the [MarqueeLabel documentation](http://cocoadocs.org/docsets/MarqueeLabel/) for more about all the features, including: - Bulk-manipulation class methods to conveniently restart, pause, and unpause all labels in a view controller - Scrolling direction: left->right, right->left, and continuous looping (both left and right) -- Label edge fades -- Pausing/unpausing mid-animation scrolling of the label -- Tap to scroll ### Special Notes @@ -83,36 +97,26 @@ Check out the [MarqueeLabel documentation](http://cocoadocs.org/docsets/MarqueeL MarqueeLabel tries its best to automatically begin scrolling when appropriate, but sometimes the way your view/view controller appears onscreen can trip it up. To combat this, you can try: -- Using the `restartLabel` instance method to "manually" start scrolling on a MarqueeLabel -- Try using the bulk manipulation class methods - but note that these don't currently play well with UIViewController containment. You'll need to pass them the lowest UIViewController in your heirarchy. +- Using the `restartLabel` instance method to manually start scrolling on a MarqueeLabel +- Try using the bulk manipulation class methods - but note that these don't currently play well with UIViewController containment. You'll need to pass them the lowest UIViewController in your hierarchy. #### Use in UITableView and UICollectionView -As noted above, MarqueeLabel can sometimes have trouble detecting when the scroll animation should start. This is particularly true when you've placed it in UITableViews/UICollectionViews, although Release v2.0 has improved this somewhat. +As noted above, MarqueeLabel can sometimes have trouble detecting when the scroll animation should start when used in UITableViews and UICollectionViews - although recent reviews have improved this. Usually you'll configure the MarqueeLabel instance when building the cell in `tableView:cellForRowAtIndexPath:` (or similar for UICollectionView), but at this point the cell is not onscreen so MarqueeLabel will not begin the scrolling animation. Even when the cell is eventually placed onscreen as the user scrolls, due to timing it's possible that the animation will not fire. To make sure the scrolling animation _does_ begin as the cell scrolls onscreen, you can use the the `restartLabel` method on your MarqueeLabels inside the `tableView:willDisplayCell:forRowAtIndexPath:` delegate method (or similar for UICollectionView). -**That said** - the UITableView/UICollectionView best practice is to minimize things like excessive animation, subviews, and custom drawing in your cells, in order to get glassy smooth scrolling. The ever-increasing speed of iOS devices is making smooth scrolling easier and easier to achieve, but in general I would recommend against allowing your labels to automatically animate during user scrolling of the UITableView/UICollectionView. I suggest [holding scrolling](http://cocoadocs.org/docsets/MarqueeLabel/2.0.7/Classes/MarqueeLabel.html#//api/name/holdScrolling) or [labelizing](http://cocoadocs.org/docsets/MarqueeLabel/2.0.7/Classes/MarqueeLabel.html#//api/name/labelize) the labels while the user scrolls. - - -#### Labelize - -Using the labelize feature will cause a MarqueeLabel to act like a normal UILabel - including the line break mode you've set. This could cause the ellipsis (...) to appear if you leave the `lineBreakMode` property as the default `NSLineBreakByTruncatingTail`. - -If you simply wish to pause scrolling with the label at the "home" location, set the `holdScrolling` property to `YES` instead. The automatic scroll animation won't restart until you set `holdScrolling` back to `NO`. - -#### Modal View Controllers +**That said** - the UITableView/UICollectionView best practice is to minimize things like excessive animation, subviews, and custom drawing in your cells, in order to get glassy smooth scrolling. In general I would recommend against allowing your labels to automatically animate during user scrolling of the UITableView/UICollectionView. I suggest [holding scrolling](http://cocoadocs.org/docsets/MarqueeLabel/2.0.7/Classes/MarqueeLabel.html#//api/name/holdScrolling) or [labelizing](http://cocoadocs.org/docsets/MarqueeLabel/2.0.7/Classes/MarqueeLabel.html#//api/name/labelize) the labels while the user scrolls. See the table view example in the demo! -Sometimes MarqueeLabel will fail to auto-restart upon the dismissal of a modal view controller or other view controller which blocks the view of your view controller. It's not always necessary, as sometimes the scroll animations will continue happily in the background. However, see the [Important Animation Note](#important-animation-note) section below. -### Important Animation Note +#### Important Animation Note MarqueeLabel is based on Core Animation, which does cause some problems when views appear and disappear and the repeating animation is stopped by iOS and does not automatically restart. -To combat this, MarqueeLabel provides a few class methods that allow easy "restarting" of all MarqueeLabels associated with a UIViewController. Specifically, the class method `restartLabelsOfController:` should be called by your view controller (which passes in `self` for the `controller` parameter`) when it is revealed or about to be revealed. Keep in mind that presenting a modal view controller can pause repeating UIView animations in the controller that is being covered! +To address this, MarqueeLabel provides a few class methods that allow easy "restarting" of all MarqueeLabels associated with a UIViewController. Specifically, the class method `restartLabelsOfController:` should be called by your view controller (which passes in `self` for the `controller` parameter`) when it is revealed or about to be revealed. Keep in mind that presenting a modal view controller can pause repeating UIView animations in the controller that is being covered! -`controllerLabelsShouldLabelize:` and `controllerLabelsShouldAnimate:` are for convienience, allowing labelizing and re-animating all labels of a UIViewController. Labelizing can be useful for performance, such as labelizing all MarqueeLabels when a UITableView/UIScrollView starts scrolling. +`controllerLabelsShouldLabelize:` and `controllerLabelsShouldAnimate:` are for convenience, allowing labelizing and re-animating all labels of a UIViewController. Labelizing can be useful for performance, such as labelizing all MarqueeLabels when a UITableView/UIScrollView starts scrolling. ## Todo - Ideas?