├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── TXScrollLabelView.podspec ├── TXScrollLabelView ├── TXScrollLabelView.h ├── TXScrollLabelView.m ├── UIView+TXFrame.h └── UIView+TXFrame.m └── TXScrollLabelViewDemo ├── TXScrollLabelViewDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── TXScrollLabelViewDemo.xcscheme ├── TXScrollLabelViewDemo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist ├── Main.storyboard ├── NSString+AttributedString.h ├── NSString+AttributedString.m ├── ViewController.h ├── ViewController.m └── main.m ├── TXScrollLabelViewDemoTests ├── Info.plist └── TXScrollLabelViewDemoTests.m └── TXScrollLabelViewDemoUITests ├── Info.plist └── TXScrollLabelViewDemoUITests.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | os: osx 3 | osx_image: xcode8.3 4 | 5 | env: 6 | global: 7 | - XCODE_PROJ=TXScrollLabelViewDemo/TXScrollLabelViewDemo.xcodeproj 8 | matrix: 9 | - SCHEME="TXScrollLabelViewDemo" 10 | 11 | before_install: 12 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet 13 | 14 | script: 15 | - set -o pipefail 16 | - xcodebuild -project "$XCODE_PROJ" -scheme "$SCHEME" -configuration Debug clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty -c 17 | - xcodebuild -project "$XCODE_PROJ" -scheme "$SCHEME" -configuration Release clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty -c 18 | 19 | after_success: 20 | - bash <(curl -s https://codecov.io/bash) 21 | - sleep 10 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 tingxins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 |

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

18 | 19 | `TXScrollLabelView` is an iOS lightweight library that can displays adverts or boardcast e.g. with an custom view. 20 | 21 | > [中文介绍](http://www.jianshu.com/p/8f1f1b1ee814) 22 | 23 | ![x-scroll-label-view](https://tingxins.com/assets/histories/TXScrollLabelView/master/x-scroll-label-view.gif) 24 | 25 | ## Support what kinds of scrollType 26 | 27 | - **TXScrollLabelViewTypeLeftRight** : scrolling from right to left, and cycle all contents(`scrollTitle`) in a single line. 28 | 29 | 30 | - **TXScrollLabelViewTypeUpDown**: scrolling from bottom to top, and cycle all contents. 31 | 32 | 33 | - **TXScrollLabelViewTypeFlipRepeat**: scrolling from bottom to top, and cycle the first line of your contents. 34 | 35 | 36 | - **TXScrollLabelViewTypeFlipNoRepeat**: scrolling from bottom to top, and cycle all contents with a line once times. 37 | 38 | And `scrollVelocity` property now supports all above enum of `TXScrollLabelViewType`, just enjoy it! 39 | 40 | ## Installation 41 | 42 | There are three ways to use TXScrollLabelView in your project: 43 | 44 | * Using CocoaPods 45 | 46 | * Manual 47 | 48 | * Using Carthage 49 | 50 | ### CocoaPods 51 | 52 | CocoaPods is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries in your projects. 53 | 54 | **Podfile** 55 | 56 | platform :ios, '7.0' 57 | pod 'TXScrollLabelView' 58 | 59 | ### Manual 60 | 61 | Download repo's zip, and just drag **ALL** files in the TXScrollLabelView folder to your projects. Import header file when you are using: 62 | 63 | #import "TXScrollLabelView.h" 64 | 65 | ### Carthage 66 | 67 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. 68 | 69 | You can install Carthage with [Homebrew](http://brew.sh/) using the following command: 70 | 71 | $ brew update 72 | $ brew install carthage 73 | 74 | To integrate **TXScrollLableView** into your Xcode project using Carthage, specify it in your Cartfile: 75 | 76 | github "tingxins/TXScrollLableView" 77 | 78 | Run carthage to build the frameworks and drag the framework into your Xcode project. 79 | 80 | ## Usage 81 | 82 | Now, TXScrollLabelView supports both **array & string**. just enjoy it. 👀 83 | 84 | ### Example 85 | 86 | **Objective-C :** 87 | 88 | /** Step1: 滚动文字 */ 89 | NSString *scrollTitle = @"xxxxxx"; 90 | 91 | /** Step2: 创建 ScrollLabelView */ 92 | TXScrollLabelView *scrollLabelView = [TXScrollLabelView scrollWithTitle:scrollTitle type:TXScrollLabelViewTypeFlipNoRepeat velocity:velocity options:UIViewAnimationOptionCurveEaseInOut]; 93 | 94 | /** Step3: 设置代理进行回调(Optional) */ 95 | scrollLabelView.scrollLabelViewDelegate = self; 96 | 97 | /** Step4: 布局(Required) */ 98 | scrollLabelView.frame = CGRectMake(50, 100, 300, 30); 99 | [self.view addSubview:scrollLabelView]; 100 | 101 | /** Step5: 开始滚动(Start scrolling!) */ 102 | [scrollLabelView beginScrolling]; 103 | 104 | 105 | You can running **TXScrollLabelViewDemo** for more details. 106 | 107 | **Swift :** Producting.([**Swift-version**](https://github.com/tingxins/ScrollLabelView)) 108 | 109 | ### Delegate Method 110 | 111 | Tap Gesture callback. 112 | 113 | ``` 114 | 115 | - (void)scrollLabelView:(TXScrollLabelView *)scrollLabelView didClickWithText:(NSString *)text atIndex:(NSInteger)index; 116 | 117 | ``` 118 | 119 | ## Communication 120 | 121 | Absolutely,you can contribute to this project all the time if you want to. 122 | 123 | - If you **need help or ask general question**, just [**@tingxins**](http://weibo.com/tingxins) in `Weibo` or `Twitter`, ofcourse, you can access to my [**blog**](https://tingxins.com). 124 | 125 | - If you **found a bug**, just open an issue. 126 | 127 | - If you **have a feature request**, just open an issue. 128 | 129 | - If you **want to contribute**, fork this repository, and then submit a pull request. 130 | 131 | ## License 132 | 133 | `TXScrollLabelView` is available under the MIT license. See the LICENSE file for more info. 134 | 135 | ## Ad 136 | 137 | Welcome to my Official Account of WeChat. 138 | 139 | ![wechat-qrcode](https://tingxins.github.io/assets/histories/adv/wechat-qrcode.jpg) 140 | 141 | -------------------------------------------------------------------------------- /TXScrollLabelView.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | s.name = "TXScrollLabelView" 4 | s.version = "1.3.2" 5 | s.summary = "TXScrollLabelView (Objective-C), the best way to show & display informations such as Adverts / Boardcast / OnSale e.g. with a customView." 6 | s.homepage = "https://github.com/tingxins/TXScrollLabelView" 7 | s.license = { :type => "MIT", :file => "LICENSE" } 8 | s.author = { "tingxins" => "tingxins@sina.com" } 9 | s.platform = :ios, "7.0" 10 | s.source = { :git => "https://github.com/tingxins/TXScrollLabelView.git", :tag => 'v1.3.2' } 11 | s.source_files = 'TXScrollLabelView/**/*.{h,m}' 12 | s.requires_arc = true 13 | end 14 | -------------------------------------------------------------------------------- /TXScrollLabelView/TXScrollLabelView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TXScrollLabelView.h 3 | // 4 | // Created by tingxins on 2/23/16. 5 | // Copyright © 2016 tingxins. All rights reserved. 6 | // 如果在使用 TXScrollLabelView 的过程中出现bug,请及时联系,我会尽快进行修复。如果有更好的点子,直接 Open an issue 或者 submit a pr。 7 | /** 8 | Blog : https://tingxins.com 9 | 简书 :http://www.jianshu.com/u/5141561e4d59 10 | GitHub : https://github.com/tingxins 11 | Weibo : http://weibo.com/tingxins 12 | Twitter : http://twitter.com/tingxins 13 | */ 14 | 15 | #define TX_DEPRECATED_METHODS(explain) __attribute__((deprecated(explain))) 16 | #define TX_DEPRECATED_MESSAGES(explain) __deprecated_msg(explain) 17 | 18 | #import 19 | #import "UIView+TXFrame.h" 20 | 21 | @class TXScrollLabelView; 22 | 23 | @protocol TXScrollLabelViewDelegate 24 | @optional 25 | - (void)scrollLabelView:(TXScrollLabelView *)scrollLabelView didClickWithText:(NSString *)text atIndex:(NSInteger)index; 26 | 27 | @end 28 | 29 | @interface TXScrollLabelView : UIScrollView 30 | 31 | typedef NS_ENUM(NSInteger, TXScrollLabelViewType) { 32 | TXScrollLabelViewTypeLeftRight = 0, //not supports scrollInset.top\bottom\right 33 | TXScrollLabelViewTypeUpDown, //not supports scrollInset.top\bottom 34 | TXScrollLabelViewTypeFlipRepeat, //not supports scrollInset.top\bottom 35 | TXScrollLabelViewTypeFlipNoRepeat //not supports scrollInset.top\bottom 36 | }; 37 | 38 | /*************WILL BE REMOVED IN FUTURE.********************/ 39 | #pragma mark - Deprecated property 40 | /** Deprecated, please Use `scrollTitle` */ 41 | @property (copy, nonatomic) NSString *tx_scrollTitle TX_DEPRECATED_METHODS("Deprecated, please Use `scrollTitle`"); 42 | /** Deprecated, please Use `scrollType` */ 43 | @property (assign, nonatomic) TXScrollLabelViewType tx_scrollType TX_DEPRECATED_METHODS("Deprecated, please Use `scrollType`"); 44 | /** Deprecated, please Use `scrollVelocity` */ 45 | @property (assign, nonatomic) NSTimeInterval tx_scrollVelocity TX_DEPRECATED_METHODS("Deprecated, please Use `scrollVelocity`"); 46 | /** Deprecated, please Use `frame` */ 47 | @property (assign, nonatomic) CGRect tx_scrollContentSize TX_DEPRECATED_METHODS("Deprecated, please Use `frame`"); 48 | /** Deprecated, please Use `scrollTitleColor` */ 49 | @property (strong, nonatomic) UIColor *tx_scrollTitleColor TX_DEPRECATED_METHODS("Deprecated, please Use `scrollTitleColor`"); 50 | /*************ALL ABOVE.***********************************/ 51 | 52 | #pragma mark - On Used Property 53 | @property (weak, nonatomic) id scrollLabelViewDelegate; 54 | /** 滚动文字 */ 55 | @property (copy, nonatomic) NSString *scrollTitle; 56 | /** 滚动类型 */ 57 | @property (assign, nonatomic) TXScrollLabelViewType scrollType; 58 | /** 滚动速率([0, 10]),单位秒s,建议在初始化方法中设置该属性*/ 59 | @property (assign, nonatomic) NSTimeInterval scrollVelocity; 60 | /** 文本颜色 */ 61 | @property (strong, nonatomic) UIColor *scrollTitleColor; 62 | /** 滚动内部inset */ 63 | @property (assign, nonatomic) UIEdgeInsets scrollInset; 64 | /** 每次循环滚动的间距 */ 65 | @property (assign, nonatomic) CGFloat scrollSpace; 66 | /** 文字排版 */ 67 | @property (assign, nonatomic) NSTextAlignment textAlignment; 68 | /** 字体大小 */ 69 | @property (strong, nonatomic) UIFont *font; 70 | //根据内容自适应宽度 Pending!! 71 | @property (assign, nonatomic) BOOL autoWidth; 72 | 73 | #pragma mark - setupAttributeTitle 74 | 75 | - (void)setupAttributeTitle:(NSAttributedString *)attributeTitle; 76 | 77 | #pragma mark - Instance Methods 78 | 79 | - (instancetype)initWithTitle:(NSString *)scrollTitle 80 | type:(TXScrollLabelViewType)scrollType 81 | velocity:(NSTimeInterval)scrollVelocity 82 | options:(UIViewAnimationOptions)options 83 | inset:(UIEdgeInsets)inset; 84 | 85 | #pragma mark - Factory Methods 86 | 87 | + (instancetype)scrollWithTitle:(NSString *)scrollTitle; 88 | 89 | + (instancetype)scrollWithTitle:(NSString *)scrollTitle 90 | type:(TXScrollLabelViewType)scrollType; 91 | 92 | + (instancetype)scrollWithTitle:(NSString *)scrollTitle 93 | type:(TXScrollLabelViewType)scrollType 94 | velocity:(NSTimeInterval)scrollVelocity; 95 | 96 | + (instancetype)scrollWithTitle:(NSString *)scrollTitle 97 | type:(TXScrollLabelViewType)scrollType 98 | velocity:(NSTimeInterval)scrollVelocity 99 | options:(UIViewAnimationOptions)options; 100 | 101 | /** 102 | 类初始化方法 103 | @param scrollTitle 滚动文本 104 | @param scrollType 滚动类型 105 | @param scrollVelocity 滚动速率 106 | @param options Now, supports the types of TXScrollLabelViewTypeFlipRepeat\NoRepeat only. 107 | @param inset just edgeInset. 108 | */ 109 | + (instancetype)scrollWithTitle:(NSString *)scrollTitle 110 | type:(TXScrollLabelViewType)scrollType 111 | velocity:(NSTimeInterval)scrollVelocity 112 | options:(UIViewAnimationOptions)options 113 | inset:(UIEdgeInsets)inset; 114 | 115 | #pragma mark - Operation Methods 116 | /** 117 | * 开始滚动 118 | */ 119 | - (void) beginScrolling; 120 | /** 121 | * 停止滚动 122 | */ 123 | - (void) endScrolling; 124 | 125 | /** 126 | * 暂停滚动(暂不支持恢复) 127 | */ 128 | - (void) pauseScrolling; 129 | 130 | @end 131 | 132 | @interface TXScrollLabelView (TXArray) 133 | 134 | /** 135 | 类初始化方法 136 | @param scrollTexts 滚动文本数组 137 | */ 138 | - (instancetype)initWithTextArray:(NSArray *)scrollTexts 139 | type:(TXScrollLabelViewType)scrollType 140 | velocity:(NSTimeInterval)scrollVelocity 141 | options:(UIViewAnimationOptions)options 142 | inset:(UIEdgeInsets)inset; 143 | 144 | + (instancetype)scrollWithTextArray:(NSArray *)scrollTexts 145 | type:(TXScrollLabelViewType)scrollType 146 | velocity:(NSTimeInterval)scrollVelocity 147 | options:(UIViewAnimationOptions)options 148 | inset:(UIEdgeInsets)inset; 149 | 150 | @end 151 | 152 | @interface TXScrollLabelView (TXScrollLabelViewDeprecated) 153 | 154 | + (instancetype)tx_setScrollTitle:(NSString *)scrollTitle TX_DEPRECATED_MESSAGES("Method deprecated. Use `+ scrollWithTitle:`"); 155 | 156 | + (instancetype)tx_setScrollTitle:(NSString *)scrollTitle 157 | scrollType:(TXScrollLabelViewType)scrollType TX_DEPRECATED_MESSAGES("Method deprecated. Use `+ scrollWithTitle:type:`"); 158 | 159 | + (instancetype)tx_setScrollTitle:(NSString *)scrollTitle 160 | scrollType:(TXScrollLabelViewType)scrollType 161 | scrollVelocity:(NSTimeInterval)scrollVelocity TX_DEPRECATED_MESSAGES("Method deprecated. Use `+ scrollWithTitle:type:velocity:`"); 162 | 163 | + (instancetype)tx_setScrollTitle:(NSString *)scrollTitle 164 | scrollType:(TXScrollLabelViewType)scrollType 165 | scrollVelocity:(NSTimeInterval)scrollVelocity 166 | options:(UIViewAnimationOptions)options TX_DEPRECATED_MESSAGES("Method deprecated. Use `+ scrollWithTitle:type:velocity:options:`"); 167 | 168 | + (instancetype)tx_setScrollTitle:(NSString *)scrollTitle 169 | scrollType:(TXScrollLabelViewType)scrollType 170 | scrollVelocity:(NSTimeInterval)scrollVelocity 171 | options:(UIViewAnimationOptions)options 172 | inset:(UIEdgeInsets)inset TX_DEPRECATED_MESSAGES("Method deprecated. Use `+ scrollWithTitle:type:velocity:options:inset:`"); 173 | @end 174 | 175 | @interface UIView (TXAdditions) 176 | 177 | - (void)addTapGesture:(id)target sel:(SEL)selector; 178 | 179 | @end 180 | 181 | -------------------------------------------------------------------------------- /TXScrollLabelView/TXScrollLabelView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TXScrollLabelView.m 3 | // 4 | // Created by tingxins on 2/23/16. 5 | // Copyright © 2016 tingxins. All rights reserved. 6 | // 如果在使用 TXScrollLabelView 的过程中出现bug,请及时联系,我会尽快进行修复。如果有更好的点子,直接 Open an issue 或者 submit a pr。 7 | /** 8 | Blog : https://tingxins.com 9 | 简书 :http://www.jianshu.com/u/5141561e4d59 10 | GitHub : https://github.com/tingxins 11 | Weibo : http://weibo.com/tingxins 12 | Twitter : http://twitter.com/tingxins 13 | */ 14 | 15 | #define TXScrollLabelFont [UIFont systemFontOfSize:14] 16 | #import "TXScrollLabelView.h" 17 | #import 18 | 19 | static const NSInteger TXScrollDefaultTimeInterval = 2.0;//滚动默认时间 20 | 21 | typedef NS_ENUM(NSInteger, TXScrollLabelType) { 22 | TXScrollLabelTypeUp = 0, 23 | TXScrollLabelTypeDown 24 | }; 25 | 26 | #pragma mark - NSTimer+TXTimerTarget 27 | 28 | @interface NSTimer (TXTimerTarget) 29 | 30 | + (NSTimer *)tx_scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeat:(BOOL)yesOrNo block:(void(^)(NSTimer *timer))block; 31 | 32 | @end 33 | 34 | 35 | @implementation NSTimer (TXTimerTarget) 36 | 37 | + (NSTimer *)tx_scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeat:(BOOL)yesOrNo block:(void (^)(NSTimer *))block{ 38 | return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(startTimer:) userInfo:[block copy] repeats:yesOrNo]; 39 | } 40 | 41 | + (void)startTimer:(NSTimer *)timer { 42 | void (^block)(NSTimer *timer) = timer.userInfo; 43 | if (block) { 44 | block(timer); 45 | } 46 | } 47 | 48 | @end 49 | 50 | #pragma mark - UILabel+TXLabel 51 | 52 | 53 | @interface TXScrollLabel : UILabel 54 | 55 | @property (assign, nonatomic) UIEdgeInsets contentInset; 56 | 57 | @end 58 | 59 | @implementation TXScrollLabel 60 | 61 | - (instancetype)init { 62 | if (self = [super init]) { 63 | _contentInset = UIEdgeInsetsZero; 64 | } 65 | return self; 66 | } 67 | 68 | - (instancetype)initWithFrame:(CGRect)frame { 69 | if (self = [super initWithFrame:frame]) { 70 | _contentInset = UIEdgeInsetsZero; 71 | } 72 | return self; 73 | } 74 | 75 | - (void)drawTextInRect:(CGRect)rect { 76 | [super drawTextInRect:UIEdgeInsetsInsetRect(rect, _contentInset)]; 77 | } 78 | 79 | @end 80 | 81 | @interface TXScrollLabel (TXLabel) 82 | 83 | + (instancetype)tx_label; 84 | 85 | @end 86 | 87 | @implementation TXScrollLabel (TXLabel) 88 | 89 | + (instancetype)tx_label { 90 | TXScrollLabel *label = [[TXScrollLabel alloc]init]; 91 | label.numberOfLines = 0; 92 | label.font = TXScrollLabelFont; 93 | label.textColor = [UIColor whiteColor]; 94 | label.lineBreakMode = NSLineBreakByWordWrapping; 95 | label.textAlignment = NSTextAlignmentCenter; 96 | return label; 97 | } 98 | 99 | @end 100 | 101 | #pragma mark - TXScrollLabelView 102 | 103 | @interface TXScrollLabelView () 104 | 105 | @property (assign, nonatomic) UIViewAnimationOptions options; 106 | 107 | @property (weak, nonatomic) TXScrollLabel *upLabel; 108 | 109 | @property (weak, nonatomic) TXScrollLabel *downLabel; 110 | //定时器 111 | @property (strong, nonatomic) NSTimer *scrollTimer; 112 | //文本行分割数组 113 | @property (strong, nonatomic) NSArray *scrollArray; 114 | 115 | @property (strong, nonatomic) NSArray *scrollTexts; 116 | //当前滚动行 117 | @property (assign, nonatomic) NSInteger currentSentence; 118 | //是否第一次开始计时 119 | @property (assign, nonatomic, getter=isFirstTime) BOOL firstTime; 120 | //传入参数是否为数组 121 | @property (assign, nonatomic) BOOL isArray; 122 | 123 | @end 124 | 125 | @implementation TXScrollLabelView 126 | 127 | @synthesize scrollSpace = _scrollSpace; 128 | 129 | @synthesize font = _font; 130 | 131 | #pragma mark - Preference Methods 132 | 133 | - (void)setSomePreference { 134 | /** Default preference. */ 135 | self.backgroundColor = [UIColor blackColor]; 136 | self.scrollEnabled = NO; 137 | } 138 | 139 | - (void)setSomeSubviews { 140 | TXScrollLabel *upLabel = [TXScrollLabel tx_label]; 141 | self.upLabel = upLabel; 142 | [self addSubview:upLabel]; 143 | 144 | TXScrollLabel *downLabel = [TXScrollLabel tx_label]; 145 | self.downLabel = downLabel; 146 | [self addSubview:downLabel]; 147 | 148 | [upLabel addTapGesture:self sel:@selector(didTap:)]; 149 | [downLabel addTapGesture:self sel:@selector(didTap:)]; 150 | } 151 | 152 | #pragma mark - UITapGestureRecognizer Methods 153 | 154 | - (void)didTap:(UITapGestureRecognizer *)tapGesture { 155 | UILabel *label = (UILabel *)tapGesture.view; 156 | 157 | if (!label || ![label isKindOfClass:[UILabel class]]) return; 158 | 159 | NSInteger index = 0; 160 | if (self.scrollArray.count) index = [self.scrollArray indexOfObject:label.text]; 161 | 162 | if ([self.scrollLabelViewDelegate respondsToSelector:@selector(scrollLabelView:didClickWithText:atIndex:)]) { 163 | [self.scrollLabelViewDelegate scrollLabelView:self didClickWithText:label.text atIndex:index]; 164 | } 165 | } 166 | 167 | #pragma mark - Instance Methods 168 | /** Terminating app due to uncaught exception 'Warning TXScrollLabelView -[TXScrollLabelView init] unimplemented!', reason: 'unimplemented, use - scrollWithTitle:scrollType:scrollVelocity:options:'*/ 169 | - (instancetype)init { 170 | @throw [NSException exceptionWithName:[NSString stringWithFormat:@"Warning %@ %s unimplemented!", self.class, __func__] reason:@"unimplemented, please use - scrollWithTitle:scrollType:scrollVelocity:options:" userInfo:nil]; 171 | } 172 | 173 | - (instancetype)initWithFrame:(CGRect)frame { 174 | if (self = [super initWithFrame:frame]) { 175 | 176 | [self setSomePreference]; 177 | 178 | [self setSomeSubviews]; 179 | } 180 | return self; 181 | } 182 | 183 | - (instancetype)initWithTitle:(NSString *)scrollTitle 184 | type:(TXScrollLabelViewType)scrollType 185 | velocity:(NSTimeInterval)scrollVelocity 186 | options:(UIViewAnimationOptions)options 187 | inset:(UIEdgeInsets)inset { 188 | if (self = [super init]) { 189 | _scrollTitle = scrollTitle; 190 | _scrollType = scrollType; 191 | self.scrollVelocity = scrollVelocity; 192 | _options = options; 193 | _scrollInset = inset; 194 | } 195 | return self; 196 | } 197 | 198 | #pragma mark - Factory Methods 199 | 200 | + (instancetype)scrollWithTitle:(NSString *)scrollTitle { 201 | 202 | return [self scrollWithTitle:scrollTitle 203 | type:TXScrollLabelViewTypeLeftRight]; 204 | } 205 | 206 | + (instancetype)scrollWithTitle:(NSString *)scrollTitle 207 | type:(TXScrollLabelViewType)scrollType { 208 | 209 | return [self scrollWithTitle:scrollTitle 210 | type:scrollType 211 | velocity:TXScrollDefaultTimeInterval]; 212 | } 213 | 214 | + (instancetype)scrollWithTitle:(NSString *)scrollTitle 215 | type:(TXScrollLabelViewType)scrollType 216 | velocity:(NSTimeInterval)scrollVelocity { 217 | 218 | return [self scrollWithTitle:scrollTitle 219 | type:scrollType 220 | velocity:scrollVelocity 221 | options:UIViewAnimationOptionCurveEaseInOut]; 222 | } 223 | 224 | + (instancetype)scrollWithTitle:(NSString *)scrollTitle 225 | type:(TXScrollLabelViewType)scrollType 226 | velocity:(NSTimeInterval)scrollVelocity 227 | options:(UIViewAnimationOptions)options { 228 | 229 | return [self scrollWithTitle:scrollTitle 230 | type:scrollType 231 | velocity:scrollVelocity 232 | options:options 233 | inset:UIEdgeInsetsMake(0, 5, 0, 5)]; 234 | } 235 | 236 | + (instancetype)scrollWithTitle:(NSString *)scrollTitle 237 | type:(TXScrollLabelViewType)scrollType 238 | velocity:(NSTimeInterval)scrollVelocity 239 | options:(UIViewAnimationOptions)options 240 | inset:(UIEdgeInsets)inset { 241 | 242 | return [[self alloc] initWithTitle:scrollTitle 243 | type:scrollType 244 | velocity:scrollVelocity 245 | options:options 246 | inset:inset]; 247 | } 248 | 249 | #pragma mark - Deprecated Getter & Setter Methods 250 | /*************WILL BE REMOVED IN THE FUTURE.****************************/ 251 | 252 | - (void)setTx_scrollTitle:(NSString *)tx_scrollTitle { 253 | self.scrollTitle = tx_scrollTitle; 254 | } 255 | 256 | - (void)setTx_scrollType:(TXScrollLabelViewType)tx_scrollType { 257 | self.scrollType = tx_scrollType; 258 | } 259 | 260 | - (void)setTx_scrollVelocity:(NSTimeInterval)tx_scrollVelocity { 261 | self.scrollVelocity = tx_scrollVelocity; 262 | } 263 | 264 | - (void)setTx_scrollContentSize:(CGRect)tx_scrollContentSize{ 265 | _tx_scrollContentSize = tx_scrollContentSize; 266 | self.frame = _tx_scrollContentSize; 267 | } 268 | 269 | - (void)setTx_scrollTitleColor:(UIColor *)tx_scrollTitleColor { 270 | self.scrollTitleColor = tx_scrollTitleColor; 271 | } 272 | /*************ALL ABOVE.*******************************************/ 273 | 274 | 275 | #pragma mark - Getter & Setter Methods 276 | 277 | - (void)setScrollTitle:(NSString *)scrollTitle { 278 | _scrollTitle = scrollTitle; 279 | // self.scrollArray = nil; 280 | [self resetScrollLabelView]; 281 | } 282 | 283 | - (void)setScrollType:(TXScrollLabelViewType)scrollType { 284 | if (_scrollType == scrollType) return; 285 | 286 | _scrollType = scrollType; 287 | self.scrollVelocity = _scrollVelocity; 288 | [self resetScrollLabelView]; 289 | } 290 | 291 | - (void)setScrollVelocity:(NSTimeInterval)scrollVelocity { 292 | CGFloat velocity = scrollVelocity; 293 | if (scrollVelocity < 0.1) { 294 | velocity = 0.1; 295 | }else if (scrollVelocity > 10) { 296 | velocity = 10; 297 | } 298 | 299 | if (_scrollType == TXScrollLabelViewTypeLeftRight || _scrollType == TXScrollLabelViewTypeUpDown) { 300 | _scrollVelocity = velocity / 30.0; 301 | }else { 302 | _scrollVelocity = velocity; 303 | } 304 | } 305 | 306 | - (UIViewAnimationOptions)options { 307 | if (_options) return _options; 308 | return _options = UIViewAnimationOptionCurveEaseInOut; 309 | } 310 | 311 | - (void)setScrollTitleColor:(UIColor *)scrollTitleColor { 312 | _scrollTitleColor = scrollTitleColor; 313 | [self setupTextColor:scrollTitleColor]; 314 | } 315 | 316 | - (void)setScrollInset:(UIEdgeInsets)scrollInset { 317 | _scrollInset = scrollInset; 318 | [self setupSubviewsLayout]; 319 | } 320 | 321 | - (void)setScrollSpace:(CGFloat)scrollSpace { 322 | _scrollSpace = scrollSpace; 323 | [self setupSubviewsLayout]; 324 | } 325 | 326 | - (CGFloat)scrollSpace { 327 | if (_scrollSpace) return _scrollSpace; 328 | return 0.f; 329 | } 330 | 331 | - (NSArray *)scrollArray { 332 | if (_scrollArray) return _scrollArray; 333 | if (_scrollTexts.count) { 334 | return _scrollArray = _scrollTexts; 335 | } 336 | return _scrollArray = [self getSeparatedLinesFromLabel]; 337 | } 338 | 339 | - (void)setFrame:(CGRect)frame { 340 | [super setFrame:frame]; 341 | [self setupSubviewsLayout]; 342 | } 343 | 344 | - (void)setTextAlignment:(NSTextAlignment)textAlignment { 345 | _textAlignment = textAlignment; 346 | self.upLabel.textAlignment = textAlignment; 347 | self.downLabel.textAlignment = textAlignment; 348 | } 349 | 350 | - (void)setFont:(UIFont *)font { 351 | _font = font; 352 | self.upLabel.font = font; 353 | self.downLabel.font = font; 354 | [self setupSubviewsLayout]; 355 | } 356 | 357 | - (UIFont *)font { 358 | if (_font) return _font; 359 | return TXScrollLabelFont; 360 | } 361 | 362 | #pragma mark - Custom Methods 363 | 364 | // Component initial 365 | - (void)setupInitial { 366 | switch (_scrollType) { 367 | case TXScrollLabelViewTypeLeftRight: 368 | [self updateTextForScrollViewWithSEL:@selector(updateLeftRightScrollLabelLayoutWithText:labelType:)]; 369 | break; 370 | 371 | case TXScrollLabelViewTypeUpDown: 372 | [self updateTextForScrollViewWithSEL:@selector(updateUpDownScrollLabelLayoutWithText:labelType:)]; 373 | break; 374 | case TXScrollLabelViewTypeFlipRepeat: 375 | case TXScrollLabelViewTypeFlipNoRepeat: 376 | // TODO 377 | break; 378 | 379 | default: 380 | @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"TXScrollLabelViewType unrecognized in -[TXScrollLabelView setupInitial]" userInfo:nil]; 381 | break; 382 | } 383 | } 384 | 385 | /** 重置滚动视图 */ 386 | - (void)resetScrollLabelView { 387 | [self endup];//停止滚动 388 | [self setupSubviewsLayout];//重新布局 389 | [self startup];//开始滚动 390 | } 391 | 392 | - (void)setupTextColor:(UIColor *)color { 393 | self.upLabel.textColor = color; 394 | self.downLabel.textColor = color; 395 | } 396 | 397 | - (void)setupTitle:(NSString *)title { 398 | self.upLabel.text = title; 399 | self.downLabel.text = title; 400 | } 401 | 402 | - (void)setupAttributeTitle:(NSAttributedString *)attributeTitle { 403 | _scrollTitle = attributeTitle.string; 404 | [self setupSubviewsLayout]; 405 | self.upLabel.attributedText = attributeTitle; 406 | self.downLabel.attributedText = attributeTitle; 407 | } 408 | 409 | #pragma mark - SubviewsLayout Methods 410 | 411 | - (void)setupSubviewsLayout { 412 | switch (_scrollType) { 413 | case TXScrollLabelViewTypeLeftRight: 414 | if (self.isArray) { 415 | [self setupInitial]; 416 | }else { 417 | [self setupSubviewsLayout_LeftRight]; 418 | } 419 | break; 420 | case TXScrollLabelViewTypeUpDown: 421 | if (self.isArray) { 422 | [self setupInitial]; 423 | }else { 424 | [self setupSubviewsLayout_UpDown]; 425 | } 426 | break; 427 | case TXScrollLabelViewTypeFlipRepeat: { 428 | [self setupSubviewsLayout_Flip]; 429 | [self setupTitle:_scrollTitle]; 430 | } 431 | break; 432 | case TXScrollLabelViewTypeFlipNoRepeat: 433 | [self setupSubviewsLayout_Flip]; 434 | break; 435 | 436 | default: 437 | break; 438 | } 439 | } 440 | 441 | - (void)setupSubviewsLayout_LeftRight { 442 | 443 | CGFloat labelMaxH = self.tx_height;//最大高度 444 | CGFloat labelMaxW = 0;//无限宽 445 | CGFloat labelH = labelMaxH;//label实际高度 446 | __block CGFloat labelW = 0;//label宽度,有待计算 447 | self.contentOffset = CGPointZero; 448 | [self setupLRUDTypeLayoutWithMaxSize:CGSizeMake(labelMaxW, labelMaxH) width:labelW height:labelH completedHandler:^(CGSize size) { 449 | labelW = MAX(size.width, self.tx_width); 450 | //开始布局 451 | self.upLabel.frame = CGRectMake(_scrollInset.left, 0, labelW, labelH); 452 | //由于 TXScrollLabelViewTypeLeftRight\UpDown 类型 X\Y 值均不一样,此处不再block中处理! 453 | self.downLabel.frame = CGRectMake(CGRectGetMaxX(self.upLabel.frame) + self.scrollSpace, 0, labelW, labelH); 454 | }]; 455 | } 456 | 457 | - (void)setupSubviewsLayout_UpDown { 458 | CGFloat labelMaxH = 0; 459 | CGFloat labelMaxW = self.tx_width - _scrollInset.left - _scrollInset.right; 460 | CGFloat labelW = labelMaxW; 461 | __block CGFloat labelH = 0; 462 | 463 | [self setupLRUDTypeLayoutWithMaxSize:CGSizeMake(labelMaxW, labelMaxH) width:labelW height:labelH completedHandler:^(CGSize size) { 464 | labelH = MAX(size.height, self.tx_height); 465 | self.upLabel.frame = CGRectMake(_scrollInset.left, 0, labelW, labelH); 466 | self.downLabel.frame = CGRectMake(_scrollInset.left, CGRectGetMaxY(self.upLabel.frame) + self.scrollSpace, labelW, labelH); 467 | }]; 468 | } 469 | 470 | - (void)setupSubviewsLayout_Flip { 471 | CGFloat labelW = self.tx_width - _scrollInset.left - _scrollInset.right; 472 | CGFloat labelX = _scrollInset.left; 473 | self.upLabel.frame = CGRectMake(labelX, 0, labelW, self.tx_height); 474 | self.downLabel.frame = CGRectMake(labelX, CGRectGetMaxY(self.upLabel.frame), labelW, self.tx_height); 475 | } 476 | 477 | - (void)setupLRUDTypeLayoutWithMaxSize:(CGSize)size 478 | width:(CGFloat)width 479 | height:(CGFloat)height 480 | completedHandler:(void(^)(CGSize size))completedHandler { 481 | CGSize scrollLabelS = [_scrollTitle boundingRectWithSize:size 482 | options:NSStringDrawingUsesLineFragmentOrigin 483 | attributes:@{NSFontAttributeName: self.font} context:nil].size; 484 | //回调获取布局数据 485 | completedHandler(scrollLabelS); 486 | if (!self.isArray) { 487 | [self setupTitle:_scrollTitle]; 488 | } 489 | } 490 | 491 | - (void)setupLRUDTypeLayoutWithTitle:(NSString *)title 492 | maxSize:(CGSize)size 493 | width:(CGFloat)width 494 | height:(CGFloat)height 495 | completedHandler:(void(^)(CGSize size))completedHandler { 496 | CGSize scrollLabelS = [title boundingRectWithSize:size 497 | options:NSStringDrawingUsesLineFragmentOrigin 498 | attributes:@{NSFontAttributeName: self.font} context:nil].size; 499 | //回调获取布局数据 500 | completedHandler(scrollLabelS); 501 | } 502 | 503 | /** 504 | update the frame of scrollLabel. Just layout 505 | 506 | @param text scrollText 507 | @param type scrollLabel type 508 | */ 509 | - (void)updateLeftRightScrollLabelLayoutWithText:(NSString *)text labelType:(TXScrollLabelType)type { 510 | CGFloat labelMaxH = self.tx_height;//最大高度 511 | CGFloat labelMaxW = 0;//无限宽 512 | CGFloat labelH = labelMaxH;//label实际高度 513 | __block CGFloat labelW = 0;//label宽度,有待计算 514 | 515 | [self setupLRUDTypeLayoutWithTitle:text maxSize:CGSizeMake(labelMaxW, labelMaxH) width:labelW height:labelH completedHandler:^(CGSize size) { 516 | labelW = MAX(size.width, self.tx_width); 517 | //开始布局 518 | if (type == TXScrollLabelTypeUp) { 519 | self.upLabel.frame = CGRectMake(_scrollInset.left, 0, labelW, labelH); 520 | }else if (type == TXScrollLabelTypeDown) { 521 | self.downLabel.frame = CGRectMake(CGRectGetMaxX(self.upLabel.frame) + self.scrollSpace, 0, labelW, labelH); 522 | } 523 | }]; 524 | } 525 | 526 | /** 527 | The same as "-updateLeftRightScrollLabelLayoutWithText:labelType:" 528 | */ 529 | - (void)updateUpDownScrollLabelLayoutWithText:(NSString *)text labelType:(TXScrollLabelType)type { 530 | CGFloat labelMaxH = 0; 531 | CGFloat labelMaxW = self.tx_width - _scrollInset.left - _scrollInset.right; 532 | CGFloat labelW = labelMaxW; 533 | __block CGFloat labelH = 0; 534 | 535 | [self setupLRUDTypeLayoutWithTitle:text maxSize:CGSizeMake(labelMaxW, labelMaxH) width:labelW height:labelH completedHandler:^(CGSize size) { 536 | labelH = MAX(size.height, self.tx_height); 537 | if (type == TXScrollLabelTypeUp) { 538 | self.upLabel.frame = CGRectMake(_scrollInset.left, 0, labelW, labelH); 539 | }else if (type == TXScrollLabelTypeDown) { 540 | self.downLabel.frame = CGRectMake(_scrollInset.left, CGRectGetMaxY(self.upLabel.frame) + self.scrollSpace, labelW, labelH); 541 | } 542 | }]; 543 | } 544 | 545 | #pragma mark - Scrolling Operation Methods -- Public 546 | 547 | - (void)beginScrolling { 548 | self.currentSentence = 0; 549 | if (self.isArray) { 550 | [self setupInitial]; 551 | } 552 | [self startup]; 553 | } 554 | 555 | - (void)endScrolling { 556 | [self endup]; 557 | } 558 | 559 | - (void)pauseScrolling { 560 | [self endup]; 561 | } 562 | 563 | #pragma mark - Scrolling Operation Methods -- Private 564 | 565 | - (void)endup { 566 | [self.scrollTimer invalidate]; 567 | self.scrollTimer = nil; 568 | self.scrollArray = nil; 569 | } 570 | 571 | - (void)startup { 572 | if (!self.scrollTitle.length && !self.scrollArray.count) return; 573 | 574 | [self endup]; 575 | 576 | if (_scrollType == TXScrollLabelViewTypeFlipRepeat || _scrollType == TXScrollLabelViewTypeFlipNoRepeat) { 577 | _firstTime = YES; 578 | if (_scrollType == TXScrollLabelViewTypeFlipNoRepeat) { 579 | [self setupTitle:[self.scrollArray firstObject]];//初次显示 580 | } 581 | [self startWithVelocity:1]; 582 | }else { 583 | [self startWithVelocity:self.scrollVelocity]; 584 | } 585 | } 586 | 587 | //开始计时 588 | - (void)startWithVelocity:(NSTimeInterval)velocity { 589 | // if (!self.scrollTitle.length) return; 590 | 591 | if (!self.scrollTitle.length && self.scrollArray.count) return; 592 | 593 | __weak typeof(self) weakSelf = self; 594 | self.scrollTimer = [NSTimer tx_scheduledTimerWithTimeInterval:velocity repeat:YES block:^(NSTimer *timer) { 595 | TXScrollLabelView *strongSelf = weakSelf; 596 | if (strongSelf) { 597 | [strongSelf updateScrolling]; 598 | } 599 | }]; 600 | [[NSRunLoop mainRunLoop] addTimer:self.scrollTimer forMode:NSRunLoopCommonModes]; 601 | } 602 | 603 | #pragma mark - Scrolling Animation Methods 604 | 605 | - (void)updateScrolling { 606 | switch (self.scrollType) { 607 | case TXScrollLabelViewTypeLeftRight: 608 | [self updateScrollingType_LeftRight]; 609 | break; 610 | case TXScrollLabelViewTypeUpDown: 611 | [self updateScrollingType_UpDown]; 612 | break; 613 | case TXScrollLabelViewTypeFlipRepeat: 614 | [self updateScrollingType_FlipRepeat]; 615 | break; 616 | case TXScrollLabelViewTypeFlipNoRepeat: 617 | [self updateScrollingType_FlipNoRepeat]; 618 | break; 619 | default: 620 | break; 621 | } 622 | } 623 | 624 | #pragma mark - ScrollLabelView + Methods 625 | 626 | - (void)updateScrollingType_LeftRight { 627 | 628 | if (self.contentOffset.x >= (_scrollInset.left + self.upLabel.tx_width + self.scrollSpace)) { 629 | /** 更新 Label.text */ 630 | if ((self.contentOffset.x > (_scrollInset.left + self.upLabel.tx_width) - self.tx_width) && 631 | self.isArray) { 632 | [self updateTextForScrollViewWithSEL:@selector(updateLeftRightScrollLabelLayoutWithText:labelType:)]; 633 | } 634 | [self endup]; 635 | self.contentOffset = CGPointMake(_scrollInset.left + 1, 0);//x增加偏移量,防止卡顿 636 | [self startup]; 637 | }else { 638 | self.contentOffset = CGPointMake(self.contentOffset.x + 1, self.contentOffset.y); 639 | } 640 | 641 | } 642 | 643 | - (void)updateScrollingType_UpDown { 644 | if (self.contentOffset.y >= (self.upLabel.tx_height + self.scrollSpace)) { 645 | /** 更新 Label.text */ 646 | if ((self.contentOffset.y >= (self.upLabel.tx_height)) && 647 | self.isArray) { 648 | [self updateTextForScrollViewWithSEL:@selector(updateUpDownScrollLabelLayoutWithText:labelType:)]; 649 | } 650 | [self endup]; 651 | self.contentOffset = CGPointMake(0, 2);//y增加偏移量,防止卡顿 652 | [self startup]; 653 | }else { 654 | self.contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y + 1); 655 | } 656 | } 657 | 658 | - (void)updateScrollingType_FlipRepeat { 659 | [self updateRepeatTypeWithOperation:^(NSTimeInterval velocity) { 660 | [self flipAnimationWithDelay:velocity]; 661 | }]; 662 | } 663 | 664 | - (void)updateScrollingType_FlipNoRepeat { 665 | [self updateRepeatTypeWithOperation:^(NSTimeInterval velocity) { 666 | [self flipNoCleAnimationWithDelay:velocity]; 667 | }]; 668 | } 669 | 670 | - (void)updateRepeatTypeWithOperation:(void(^)(NSTimeInterval))operation { 671 | NSTimeInterval velocity = self.scrollVelocity; 672 | if (self.isFirstTime) { 673 | _firstTime = NO; 674 | [self endup]; 675 | [self startWithVelocity:velocity]; 676 | } 677 | operation(velocity); 678 | } 679 | 680 | - (void)flipAnimationWithDelay:(NSTimeInterval)delay { 681 | [UIView transitionWithView:self.upLabel duration:delay * 0.5 options:self.options animations:^{ 682 | self.upLabel.tx_bottom = 0; 683 | [UIView transitionWithView:self.upLabel duration:delay * 0.5 options:self.options animations:^{ 684 | self.downLabel.tx_y = 0; 685 | } completion:^(BOOL finished) { 686 | self.upLabel.tx_y = self.tx_height; 687 | TXScrollLabel *tempLabel = self.upLabel; 688 | self.upLabel = self.downLabel; 689 | self.downLabel = tempLabel; 690 | }]; 691 | } completion:nil]; 692 | } 693 | 694 | 695 | /** 696 | Execute flip animation. 697 | 698 | @param delay animation duration. 699 | */ 700 | - (void)flipNoCleAnimationWithDelay:(NSTimeInterval)delay { 701 | if (!self.scrollArray.count) return; 702 | /** 更新文本 */ 703 | [self updateScrollText]; 704 | /** 执行翻滚动画 */ 705 | [self flipAnimationWithDelay:delay]; 706 | } 707 | 708 | #pragma mark - Params For Array 709 | 710 | void (*setter)(id, SEL, NSString *, TXScrollLabelType); 711 | 712 | - (void)updateTextForScrollViewWithSEL:(SEL)sel { 713 | 714 | if (!self.scrollArray.count) return; 715 | 716 | /** 更新文本 */ 717 | [self updateScrollText]; 718 | /** 执行 SEL */ 719 | setter = (void (*)(id, SEL, NSString *, TXScrollLabelType))[self methodForSelector:sel]; 720 | setter(self, sel, self.upLabel.text, TXScrollLabelTypeUp); 721 | setter(self, sel, self.downLabel.text, TXScrollLabelTypeDown); 722 | } 723 | 724 | - (void)updateScrollText { 725 | NSInteger currentSentence = self.currentSentence; 726 | if (currentSentence >= self.scrollArray.count) currentSentence = 0; 727 | self.upLabel.text = self.scrollArray[currentSentence]; 728 | currentSentence ++; 729 | if (currentSentence >= self.scrollArray.count) currentSentence = 0; 730 | self.downLabel.text = self.scrollArray[currentSentence]; 731 | 732 | self.currentSentence = currentSentence; 733 | } 734 | 735 | #pragma mark - Text-Separator 736 | 737 | -(NSArray *)getSeparatedLinesFromLabel { 738 | if (!_scrollTitle.length) return nil; 739 | 740 | NSString *text = _scrollTitle; 741 | UIFont *font = self.font; 742 | CTFontRef myFont = CTFontCreateWithName((__bridge CFStringRef)([font fontName]), [font pointSize], NULL); 743 | NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text]; 744 | [attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)]; 745 | 746 | CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attStr); 747 | CGMutablePathRef path = CGPathCreateMutable(); 748 | CGPathAddRect(path, NULL, CGRectMake(0,0,self.upLabel.tx_width,100000)); 749 | CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL); 750 | 751 | NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame); 752 | 753 | NSMutableArray *linesArray = [[NSMutableArray alloc]init]; 754 | for (id line in lines) { 755 | CTLineRef lineRef = (__bridge CTLineRef )line; 756 | CFRange lineRange = CTLineGetStringRange(lineRef); 757 | NSRange range = NSMakeRange(lineRange.location, lineRange.length); 758 | NSString *lineString = [text substringWithRange:range]; 759 | [linesArray addObject:lineString]; 760 | } 761 | 762 | return (NSArray *)linesArray; 763 | } 764 | 765 | - (void)dealloc { 766 | [self endup]; 767 | } 768 | 769 | @end 770 | 771 | @implementation TXScrollLabelView (TXArray) 772 | 773 | #pragma mark - Array Methods 774 | 775 | - (instancetype)initWithTextArray:(NSArray *)scrollTexts 776 | type:(TXScrollLabelViewType)scrollType 777 | velocity:(NSTimeInterval)scrollVelocity 778 | options:(UIViewAnimationOptions)options 779 | inset:(UIEdgeInsets)inset { 780 | if (self = [super init]) { 781 | self.isArray = YES; 782 | _scrollTexts = [scrollTexts copy]; 783 | _scrollTitle = [_scrollTexts firstObject]; 784 | _scrollType = scrollType; 785 | self.scrollVelocity = scrollVelocity; 786 | _options = options; 787 | _scrollInset = inset; 788 | } 789 | return self; 790 | } 791 | 792 | + (instancetype)scrollWithTextArray:(NSArray *)scrollTexts 793 | type:(TXScrollLabelViewType)scrollType 794 | velocity:(NSTimeInterval)scrollVelocity 795 | options:(UIViewAnimationOptions)options 796 | inset:(UIEdgeInsets)inset { 797 | return [[self alloc] initWithTextArray:scrollTexts 798 | type:scrollType 799 | velocity:scrollVelocity 800 | options:options 801 | inset:inset]; 802 | } 803 | 804 | @end 805 | 806 | @implementation TXScrollLabelView (TXScrollLabelViewDeprecated) 807 | 808 | + (instancetype)tx_setScrollTitle:(NSString *)scrollTitle { 809 | 810 | return [self scrollWithTitle:scrollTitle]; 811 | } 812 | 813 | + (instancetype)tx_setScrollTitle:(NSString *)scrollTitle 814 | scrollType:(TXScrollLabelViewType)scrollType { 815 | 816 | return [self scrollWithTitle:scrollTitle 817 | type:scrollType]; 818 | } 819 | 820 | + (instancetype)tx_setScrollTitle:(NSString *)scrollTitle 821 | scrollType:(TXScrollLabelViewType)scrollType 822 | scrollVelocity:(NSTimeInterval)scrollVelocity { 823 | 824 | return [self scrollWithTitle:scrollTitle 825 | type:scrollType 826 | velocity:scrollVelocity]; 827 | } 828 | 829 | + (instancetype)tx_setScrollTitle:(NSString *)scrollTitle 830 | scrollType:(TXScrollLabelViewType)scrollType 831 | scrollVelocity:(NSTimeInterval)scrollVelocity 832 | options:(UIViewAnimationOptions)options { 833 | 834 | return [self scrollWithTitle:scrollTitle 835 | type:scrollType 836 | velocity:scrollVelocity 837 | options:options]; 838 | } 839 | 840 | + (instancetype)tx_setScrollTitle:(NSString *)scrollTitle 841 | scrollType:(TXScrollLabelViewType)scrollType 842 | scrollVelocity:(NSTimeInterval)scrollVelocity 843 | options:(UIViewAnimationOptions)options 844 | inset:(UIEdgeInsets)inset { 845 | 846 | return [self scrollWithTitle:scrollTitle 847 | type:scrollType 848 | velocity:scrollVelocity 849 | options:options 850 | inset:inset]; 851 | } 852 | 853 | @end 854 | 855 | 856 | @implementation UIView (TXAdditions) 857 | 858 | - (void)addTapGesture:(id)target sel:(SEL)selector { 859 | self.userInteractionEnabled = YES; 860 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:target action:selector]; 861 | [self addGestureRecognizer:tap]; 862 | } 863 | 864 | @end 865 | -------------------------------------------------------------------------------- /TXScrollLabelView/UIView+TXFrame.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+TXFrame.h 3 | // TXSwipeTableViewTest 4 | // 5 | // Created by tingxins on 9/1/16. 6 | // Copyright © 2016 tingxins. All rights reserved. 7 | // Welcome to my blog: https://tingxins.com 8 | // 9 | 10 | #import 11 | 12 | @interface UIView (TXFrame) 13 | /** 设置x值 */ 14 | @property (assign, nonatomic) CGFloat tx_x; 15 | /** 设置y值 */ 16 | @property (assign, nonatomic) CGFloat tx_y; 17 | /** 设置width */ 18 | @property (assign, nonatomic) CGFloat tx_width; 19 | /** 设置height */ 20 | @property (assign, nonatomic) CGFloat tx_height; 21 | /** 设置size */ 22 | @property (assign, nonatomic) CGSize tx_size; 23 | /** 设置origin */ 24 | @property (assign, nonatomic) CGPoint tx_origin; 25 | /** 设置center */ 26 | @property (assign, nonatomic) CGPoint tx_center; 27 | /** 设置center.x */ 28 | @property (assign, nonatomic) CGFloat tx_centerX; 29 | /** 设置center.y */ 30 | @property (assign, nonatomic) CGFloat tx_centerY; 31 | /** 设置bottom */ 32 | @property (assign, nonatomic) CGFloat tx_bottom; 33 | @end 34 | -------------------------------------------------------------------------------- /TXScrollLabelView/UIView+TXFrame.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+TXFrame.m 3 | // TXSwipeTableViewTest 4 | // 5 | // Created by tingxins on 9/1/16. 6 | // Copyright © 2016 tingxins. All rights reserved. 7 | // 8 | 9 | #import "UIView+TXFrame.h" 10 | 11 | @implementation UIView (TXFrame) 12 | 13 | - (CGFloat)tx_x { 14 | return self.frame.origin.x; 15 | } 16 | 17 | - (void)setTx_x:(CGFloat)tx_x { 18 | CGRect frame = self.frame; 19 | frame.origin.x = tx_x; 20 | self.frame = frame; 21 | } 22 | 23 | - (CGFloat)tx_y { 24 | return self.frame.origin.y; 25 | } 26 | 27 | - (void)setTx_y:(CGFloat)tx_y { 28 | CGRect frame = self.frame; 29 | frame.origin.y = tx_y; 30 | self.frame = frame; 31 | } 32 | 33 | - (CGFloat)tx_width { 34 | return self.frame.size.width; 35 | } 36 | 37 | - (void)setTx_width:(CGFloat)tx_width { 38 | CGRect frame = self.frame; 39 | frame.size.width = tx_width; 40 | self.frame = frame; 41 | } 42 | 43 | - (CGFloat)tx_height { 44 | return self.frame.size.height; 45 | } 46 | 47 | - (void)setTx_height:(CGFloat)tx_height { 48 | CGRect frame = self.frame; 49 | frame.size.height = tx_height; 50 | self.frame = frame; 51 | } 52 | 53 | - (CGSize)tx_size { 54 | return self.frame.size; 55 | } 56 | 57 | - (void)setTx_size:(CGSize)tx_size { 58 | CGRect frame = self.frame; 59 | frame.size = tx_size; 60 | self.frame = frame; 61 | } 62 | 63 | - (CGPoint)tx_origin { 64 | return self.frame.origin; 65 | } 66 | 67 | - (void)setTx_origin:(CGPoint)tx_origin { 68 | CGRect frame = self.frame; 69 | frame.origin = tx_origin; 70 | self.frame = frame; 71 | } 72 | 73 | - (CGPoint)tx_center { 74 | return self.center; 75 | } 76 | 77 | - (void)setTx_center:(CGPoint)tx_center { 78 | self.center = tx_center; 79 | } 80 | 81 | - (CGFloat)tx_centerX { 82 | return self.center.x; 83 | } 84 | 85 | - (void)setTx_centerX:(CGFloat)tx_centerX { 86 | CGPoint center = self.center; 87 | center.x = tx_centerX; 88 | self.center = center; 89 | } 90 | 91 | - (CGFloat)tx_centerY { 92 | return self.center.y; 93 | } 94 | 95 | - (void)setTx_centerY:(CGFloat)tx_centerY { 96 | CGPoint center = self.center; 97 | center.y = tx_centerY; 98 | self.center = center; 99 | } 100 | 101 | - (CGFloat)tx_bottom { 102 | return CGRectGetMaxY(self.frame); 103 | } 104 | 105 | - (void)setTx_bottom:(CGFloat)tx_bottom { 106 | CGRect frame = self.frame; 107 | frame.origin.y = tx_bottom - frame.size.height; 108 | self.frame = frame; 109 | } 110 | 111 | @end 112 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 972620CA1DDE2F0600009F23 /* TXScrollLabelView.m in Sources */ = {isa = PBXBuildFile; fileRef = 972620C61DDE2F0600009F23 /* TXScrollLabelView.m */; }; 11 | 972620CB1DDE2F0600009F23 /* UIView+TXFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 972620C91DDE2F0600009F23 /* UIView+TXFrame.m */; }; 12 | 97883B5E1EBD7A6800552DFE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97883B5D1EBD7A6800552DFE /* Main.storyboard */; }; 13 | 97886D991DB8E0AF00A0B326 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97886D981DB8E0AF00A0B326 /* main.m */; }; 14 | 97886D9C1DB8E0AF00A0B326 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 97886D9B1DB8E0AF00A0B326 /* AppDelegate.m */; }; 15 | 97886D9F1DB8E0AF00A0B326 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 97886D9E1DB8E0AF00A0B326 /* ViewController.m */; }; 16 | 97886DA41DB8E0AF00A0B326 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97886DA31DB8E0AF00A0B326 /* Assets.xcassets */; }; 17 | 97886DA71DB8E0AF00A0B326 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97886DA51DB8E0AF00A0B326 /* LaunchScreen.storyboard */; }; 18 | 97886DB21DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 97886DB11DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests.m */; }; 19 | 97886DBD1DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 97886DBC1DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests.m */; }; 20 | AF1B25351DF5803200AB8923 /* NSString+AttributedString.m in Sources */ = {isa = PBXBuildFile; fileRef = AF1B25341DF5803200AB8923 /* NSString+AttributedString.m */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 97886DAE1DB8E0AF00A0B326 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 97886D8C1DB8E0AF00A0B326 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 97886D931DB8E0AF00A0B326; 29 | remoteInfo = TXScrollLabelViewDemo; 30 | }; 31 | 97886DB91DB8E0AF00A0B326 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = 97886D8C1DB8E0AF00A0B326 /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = 97886D931DB8E0AF00A0B326; 36 | remoteInfo = TXScrollLabelViewDemo; 37 | }; 38 | /* End PBXContainerItemProxy section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 972620C61DDE2F0600009F23 /* TXScrollLabelView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TXScrollLabelView.m; sourceTree = ""; }; 42 | 972620C71DDE2F0600009F23 /* TXScrollLabelView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TXScrollLabelView.h; sourceTree = ""; }; 43 | 972620C81DDE2F0600009F23 /* UIView+TXFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+TXFrame.h"; sourceTree = ""; }; 44 | 972620C91DDE2F0600009F23 /* UIView+TXFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+TXFrame.m"; sourceTree = ""; }; 45 | 97883B5D1EBD7A6800552DFE /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 46 | 97886D941DB8E0AF00A0B326 /* TXScrollLabelViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TXScrollLabelViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 97886D981DB8E0AF00A0B326 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 48 | 97886D9A1DB8E0AF00A0B326 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 49 | 97886D9B1DB8E0AF00A0B326 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 50 | 97886D9D1DB8E0AF00A0B326 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 51 | 97886D9E1DB8E0AF00A0B326 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 52 | 97886DA31DB8E0AF00A0B326 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 53 | 97886DA61DB8E0AF00A0B326 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 54 | 97886DA81DB8E0AF00A0B326 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | 97886DAD1DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TXScrollLabelViewDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 97886DB11DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TXScrollLabelViewDemoTests.m; sourceTree = ""; }; 57 | 97886DB31DB8E0AF00A0B326 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 97886DB81DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TXScrollLabelViewDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 97886DBC1DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TXScrollLabelViewDemoUITests.m; sourceTree = ""; }; 60 | 97886DBE1DB8E0AF00A0B326 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | AF1B25331DF5803200AB8923 /* NSString+AttributedString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+AttributedString.h"; sourceTree = ""; }; 62 | AF1B25341DF5803200AB8923 /* NSString+AttributedString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+AttributedString.m"; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 97886D911DB8E0AF00A0B326 /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | 97886DAA1DB8E0AF00A0B326 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | 97886DB51DB8E0AF00A0B326 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXFrameworksBuildPhase section */ 88 | 89 | /* Begin PBXGroup section */ 90 | 972620C51DDE2F0600009F23 /* TXScrollLabelView */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 972620C71DDE2F0600009F23 /* TXScrollLabelView.h */, 94 | 972620C61DDE2F0600009F23 /* TXScrollLabelView.m */, 95 | 972620C81DDE2F0600009F23 /* UIView+TXFrame.h */, 96 | 972620C91DDE2F0600009F23 /* UIView+TXFrame.m */, 97 | ); 98 | name = TXScrollLabelView; 99 | path = ../../TXScrollLabelView; 100 | sourceTree = ""; 101 | }; 102 | 97886D8B1DB8E0AF00A0B326 = { 103 | isa = PBXGroup; 104 | children = ( 105 | 97886D961DB8E0AF00A0B326 /* TXScrollLabelViewDemo */, 106 | 97886DB01DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests */, 107 | 97886DBB1DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests */, 108 | 97886D951DB8E0AF00A0B326 /* Products */, 109 | ); 110 | sourceTree = ""; 111 | }; 112 | 97886D951DB8E0AF00A0B326 /* Products */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 97886D941DB8E0AF00A0B326 /* TXScrollLabelViewDemo.app */, 116 | 97886DAD1DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests.xctest */, 117 | 97886DB81DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests.xctest */, 118 | ); 119 | name = Products; 120 | sourceTree = ""; 121 | }; 122 | 97886D961DB8E0AF00A0B326 /* TXScrollLabelViewDemo */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 972620C51DDE2F0600009F23 /* TXScrollLabelView */, 126 | 97886D9A1DB8E0AF00A0B326 /* AppDelegate.h */, 127 | 97886D9B1DB8E0AF00A0B326 /* AppDelegate.m */, 128 | 97886D9D1DB8E0AF00A0B326 /* ViewController.h */, 129 | 97886D9E1DB8E0AF00A0B326 /* ViewController.m */, 130 | AF1B25331DF5803200AB8923 /* NSString+AttributedString.h */, 131 | AF1B25341DF5803200AB8923 /* NSString+AttributedString.m */, 132 | 97886DA31DB8E0AF00A0B326 /* Assets.xcassets */, 133 | 97886DA51DB8E0AF00A0B326 /* LaunchScreen.storyboard */, 134 | 97886DA81DB8E0AF00A0B326 /* Info.plist */, 135 | 97883B5D1EBD7A6800552DFE /* Main.storyboard */, 136 | 97886D971DB8E0AF00A0B326 /* Supporting Files */, 137 | ); 138 | path = TXScrollLabelViewDemo; 139 | sourceTree = ""; 140 | }; 141 | 97886D971DB8E0AF00A0B326 /* Supporting Files */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 97886D981DB8E0AF00A0B326 /* main.m */, 145 | ); 146 | name = "Supporting Files"; 147 | sourceTree = ""; 148 | }; 149 | 97886DB01DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 97886DB11DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests.m */, 153 | 97886DB31DB8E0AF00A0B326 /* Info.plist */, 154 | ); 155 | path = TXScrollLabelViewDemoTests; 156 | sourceTree = ""; 157 | }; 158 | 97886DBB1DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | 97886DBC1DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests.m */, 162 | 97886DBE1DB8E0AF00A0B326 /* Info.plist */, 163 | ); 164 | path = TXScrollLabelViewDemoUITests; 165 | sourceTree = ""; 166 | }; 167 | /* End PBXGroup section */ 168 | 169 | /* Begin PBXNativeTarget section */ 170 | 97886D931DB8E0AF00A0B326 /* TXScrollLabelViewDemo */ = { 171 | isa = PBXNativeTarget; 172 | buildConfigurationList = 97886DC11DB8E0AF00A0B326 /* Build configuration list for PBXNativeTarget "TXScrollLabelViewDemo" */; 173 | buildPhases = ( 174 | 97886D901DB8E0AF00A0B326 /* Sources */, 175 | 97886D911DB8E0AF00A0B326 /* Frameworks */, 176 | 97886D921DB8E0AF00A0B326 /* Resources */, 177 | ); 178 | buildRules = ( 179 | ); 180 | dependencies = ( 181 | ); 182 | name = TXScrollLabelViewDemo; 183 | productName = TXScrollLabelViewDemo; 184 | productReference = 97886D941DB8E0AF00A0B326 /* TXScrollLabelViewDemo.app */; 185 | productType = "com.apple.product-type.application"; 186 | }; 187 | 97886DAC1DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests */ = { 188 | isa = PBXNativeTarget; 189 | buildConfigurationList = 97886DC41DB8E0AF00A0B326 /* Build configuration list for PBXNativeTarget "TXScrollLabelViewDemoTests" */; 190 | buildPhases = ( 191 | 97886DA91DB8E0AF00A0B326 /* Sources */, 192 | 97886DAA1DB8E0AF00A0B326 /* Frameworks */, 193 | 97886DAB1DB8E0AF00A0B326 /* Resources */, 194 | ); 195 | buildRules = ( 196 | ); 197 | dependencies = ( 198 | 97886DAF1DB8E0AF00A0B326 /* PBXTargetDependency */, 199 | ); 200 | name = TXScrollLabelViewDemoTests; 201 | productName = TXScrollLabelViewDemoTests; 202 | productReference = 97886DAD1DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests.xctest */; 203 | productType = "com.apple.product-type.bundle.unit-test"; 204 | }; 205 | 97886DB71DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests */ = { 206 | isa = PBXNativeTarget; 207 | buildConfigurationList = 97886DC71DB8E0AF00A0B326 /* Build configuration list for PBXNativeTarget "TXScrollLabelViewDemoUITests" */; 208 | buildPhases = ( 209 | 97886DB41DB8E0AF00A0B326 /* Sources */, 210 | 97886DB51DB8E0AF00A0B326 /* Frameworks */, 211 | 97886DB61DB8E0AF00A0B326 /* Resources */, 212 | ); 213 | buildRules = ( 214 | ); 215 | dependencies = ( 216 | 97886DBA1DB8E0AF00A0B326 /* PBXTargetDependency */, 217 | ); 218 | name = TXScrollLabelViewDemoUITests; 219 | productName = TXScrollLabelViewDemoUITests; 220 | productReference = 97886DB81DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests.xctest */; 221 | productType = "com.apple.product-type.bundle.ui-testing"; 222 | }; 223 | /* End PBXNativeTarget section */ 224 | 225 | /* Begin PBXProject section */ 226 | 97886D8C1DB8E0AF00A0B326 /* Project object */ = { 227 | isa = PBXProject; 228 | attributes = { 229 | LastUpgradeCheck = 0810; 230 | ORGANIZATIONNAME = tingxins; 231 | TargetAttributes = { 232 | 97886D931DB8E0AF00A0B326 = { 233 | CreatedOnToolsVersion = 8.0; 234 | DevelopmentTeam = QZ2B7EZFJP; 235 | ProvisioningStyle = Automatic; 236 | }; 237 | 97886DAC1DB8E0AF00A0B326 = { 238 | CreatedOnToolsVersion = 8.0; 239 | DevelopmentTeam = X37JS8D42G; 240 | ProvisioningStyle = Automatic; 241 | TestTargetID = 97886D931DB8E0AF00A0B326; 242 | }; 243 | 97886DB71DB8E0AF00A0B326 = { 244 | CreatedOnToolsVersion = 8.0; 245 | DevelopmentTeam = X37JS8D42G; 246 | ProvisioningStyle = Automatic; 247 | TestTargetID = 97886D931DB8E0AF00A0B326; 248 | }; 249 | }; 250 | }; 251 | buildConfigurationList = 97886D8F1DB8E0AF00A0B326 /* Build configuration list for PBXProject "TXScrollLabelViewDemo" */; 252 | compatibilityVersion = "Xcode 3.2"; 253 | developmentRegion = English; 254 | hasScannedForEncodings = 0; 255 | knownRegions = ( 256 | en, 257 | Base, 258 | ); 259 | mainGroup = 97886D8B1DB8E0AF00A0B326; 260 | productRefGroup = 97886D951DB8E0AF00A0B326 /* Products */; 261 | projectDirPath = ""; 262 | projectRoot = ""; 263 | targets = ( 264 | 97886D931DB8E0AF00A0B326 /* TXScrollLabelViewDemo */, 265 | 97886DAC1DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests */, 266 | 97886DB71DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests */, 267 | ); 268 | }; 269 | /* End PBXProject section */ 270 | 271 | /* Begin PBXResourcesBuildPhase section */ 272 | 97886D921DB8E0AF00A0B326 /* Resources */ = { 273 | isa = PBXResourcesBuildPhase; 274 | buildActionMask = 2147483647; 275 | files = ( 276 | 97883B5E1EBD7A6800552DFE /* Main.storyboard in Resources */, 277 | 97886DA71DB8E0AF00A0B326 /* LaunchScreen.storyboard in Resources */, 278 | 97886DA41DB8E0AF00A0B326 /* Assets.xcassets in Resources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | 97886DAB1DB8E0AF00A0B326 /* Resources */ = { 283 | isa = PBXResourcesBuildPhase; 284 | buildActionMask = 2147483647; 285 | files = ( 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | 97886DB61DB8E0AF00A0B326 /* Resources */ = { 290 | isa = PBXResourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | /* End PBXResourcesBuildPhase section */ 297 | 298 | /* Begin PBXSourcesBuildPhase section */ 299 | 97886D901DB8E0AF00A0B326 /* Sources */ = { 300 | isa = PBXSourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | 972620CB1DDE2F0600009F23 /* UIView+TXFrame.m in Sources */, 304 | 972620CA1DDE2F0600009F23 /* TXScrollLabelView.m in Sources */, 305 | 97886D9F1DB8E0AF00A0B326 /* ViewController.m in Sources */, 306 | 97886D9C1DB8E0AF00A0B326 /* AppDelegate.m in Sources */, 307 | AF1B25351DF5803200AB8923 /* NSString+AttributedString.m in Sources */, 308 | 97886D991DB8E0AF00A0B326 /* main.m in Sources */, 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | }; 312 | 97886DA91DB8E0AF00A0B326 /* Sources */ = { 313 | isa = PBXSourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | 97886DB21DB8E0AF00A0B326 /* TXScrollLabelViewDemoTests.m in Sources */, 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | }; 320 | 97886DB41DB8E0AF00A0B326 /* Sources */ = { 321 | isa = PBXSourcesBuildPhase; 322 | buildActionMask = 2147483647; 323 | files = ( 324 | 97886DBD1DB8E0AF00A0B326 /* TXScrollLabelViewDemoUITests.m in Sources */, 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | }; 328 | /* End PBXSourcesBuildPhase section */ 329 | 330 | /* Begin PBXTargetDependency section */ 331 | 97886DAF1DB8E0AF00A0B326 /* PBXTargetDependency */ = { 332 | isa = PBXTargetDependency; 333 | target = 97886D931DB8E0AF00A0B326 /* TXScrollLabelViewDemo */; 334 | targetProxy = 97886DAE1DB8E0AF00A0B326 /* PBXContainerItemProxy */; 335 | }; 336 | 97886DBA1DB8E0AF00A0B326 /* PBXTargetDependency */ = { 337 | isa = PBXTargetDependency; 338 | target = 97886D931DB8E0AF00A0B326 /* TXScrollLabelViewDemo */; 339 | targetProxy = 97886DB91DB8E0AF00A0B326 /* PBXContainerItemProxy */; 340 | }; 341 | /* End PBXTargetDependency section */ 342 | 343 | /* Begin PBXVariantGroup section */ 344 | 97886DA51DB8E0AF00A0B326 /* LaunchScreen.storyboard */ = { 345 | isa = PBXVariantGroup; 346 | children = ( 347 | 97886DA61DB8E0AF00A0B326 /* Base */, 348 | ); 349 | name = LaunchScreen.storyboard; 350 | sourceTree = ""; 351 | }; 352 | /* End PBXVariantGroup section */ 353 | 354 | /* Begin XCBuildConfiguration section */ 355 | 97886DBF1DB8E0AF00A0B326 /* Debug */ = { 356 | isa = XCBuildConfiguration; 357 | buildSettings = { 358 | ALWAYS_SEARCH_USER_PATHS = NO; 359 | CLANG_ANALYZER_NONNULL = YES; 360 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 361 | CLANG_CXX_LIBRARY = "libc++"; 362 | CLANG_ENABLE_MODULES = YES; 363 | CLANG_ENABLE_OBJC_ARC = YES; 364 | CLANG_WARN_BOOL_CONVERSION = YES; 365 | CLANG_WARN_CONSTANT_CONVERSION = YES; 366 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 367 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 368 | CLANG_WARN_EMPTY_BODY = YES; 369 | CLANG_WARN_ENUM_CONVERSION = YES; 370 | CLANG_WARN_INFINITE_RECURSION = YES; 371 | CLANG_WARN_INT_CONVERSION = YES; 372 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 373 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 374 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 375 | CLANG_WARN_UNREACHABLE_CODE = YES; 376 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 377 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 378 | COPY_PHASE_STRIP = NO; 379 | DEBUG_INFORMATION_FORMAT = dwarf; 380 | ENABLE_STRICT_OBJC_MSGSEND = YES; 381 | ENABLE_TESTABILITY = YES; 382 | GCC_C_LANGUAGE_STANDARD = gnu99; 383 | GCC_DYNAMIC_NO_PIC = NO; 384 | GCC_NO_COMMON_BLOCKS = YES; 385 | GCC_OPTIMIZATION_LEVEL = 0; 386 | GCC_PREPROCESSOR_DEFINITIONS = ( 387 | "DEBUG=1", 388 | "$(inherited)", 389 | ); 390 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 391 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 392 | GCC_WARN_UNDECLARED_SELECTOR = YES; 393 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 394 | GCC_WARN_UNUSED_FUNCTION = YES; 395 | GCC_WARN_UNUSED_VARIABLE = YES; 396 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 397 | MTL_ENABLE_DEBUG_INFO = YES; 398 | ONLY_ACTIVE_ARCH = YES; 399 | SDKROOT = iphoneos; 400 | }; 401 | name = Debug; 402 | }; 403 | 97886DC01DB8E0AF00A0B326 /* Release */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ALWAYS_SEARCH_USER_PATHS = NO; 407 | CLANG_ANALYZER_NONNULL = YES; 408 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 409 | CLANG_CXX_LIBRARY = "libc++"; 410 | CLANG_ENABLE_MODULES = YES; 411 | CLANG_ENABLE_OBJC_ARC = YES; 412 | CLANG_WARN_BOOL_CONVERSION = YES; 413 | CLANG_WARN_CONSTANT_CONVERSION = YES; 414 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 415 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 416 | CLANG_WARN_EMPTY_BODY = YES; 417 | CLANG_WARN_ENUM_CONVERSION = YES; 418 | CLANG_WARN_INFINITE_RECURSION = YES; 419 | CLANG_WARN_INT_CONVERSION = YES; 420 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 421 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 422 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 423 | CLANG_WARN_UNREACHABLE_CODE = YES; 424 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 425 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 426 | COPY_PHASE_STRIP = NO; 427 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 428 | ENABLE_NS_ASSERTIONS = NO; 429 | ENABLE_STRICT_OBJC_MSGSEND = YES; 430 | GCC_C_LANGUAGE_STANDARD = gnu99; 431 | GCC_NO_COMMON_BLOCKS = YES; 432 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 433 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 434 | GCC_WARN_UNDECLARED_SELECTOR = YES; 435 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 436 | GCC_WARN_UNUSED_FUNCTION = YES; 437 | GCC_WARN_UNUSED_VARIABLE = YES; 438 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 439 | MTL_ENABLE_DEBUG_INFO = NO; 440 | SDKROOT = iphoneos; 441 | VALIDATE_PRODUCT = YES; 442 | }; 443 | name = Release; 444 | }; 445 | 97886DC21DB8E0AF00A0B326 /* Debug */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 449 | DEVELOPMENT_TEAM = QZ2B7EZFJP; 450 | INFOPLIST_FILE = TXScrollLabelViewDemo/Info.plist; 451 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 452 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 453 | PRODUCT_BUNDLE_IDENTIFIER = com.tingxins.demo.TXScrollLabelViewDemo; 454 | PRODUCT_NAME = "$(TARGET_NAME)"; 455 | }; 456 | name = Debug; 457 | }; 458 | 97886DC31DB8E0AF00A0B326 /* Release */ = { 459 | isa = XCBuildConfiguration; 460 | buildSettings = { 461 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 462 | DEVELOPMENT_TEAM = QZ2B7EZFJP; 463 | INFOPLIST_FILE = TXScrollLabelViewDemo/Info.plist; 464 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 465 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 466 | PRODUCT_BUNDLE_IDENTIFIER = com.tingxins.demo.TXScrollLabelViewDemo; 467 | PRODUCT_NAME = "$(TARGET_NAME)"; 468 | }; 469 | name = Release; 470 | }; 471 | 97886DC51DB8E0AF00A0B326 /* Debug */ = { 472 | isa = XCBuildConfiguration; 473 | buildSettings = { 474 | BUNDLE_LOADER = "$(TEST_HOST)"; 475 | DEVELOPMENT_TEAM = X37JS8D42G; 476 | INFOPLIST_FILE = TXScrollLabelViewDemoTests/Info.plist; 477 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 478 | PRODUCT_BUNDLE_IDENTIFIER = com.tingxins.TXScrollLabelViewDemoTests; 479 | PRODUCT_NAME = "$(TARGET_NAME)"; 480 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TXScrollLabelViewDemo.app/TXScrollLabelViewDemo"; 481 | }; 482 | name = Debug; 483 | }; 484 | 97886DC61DB8E0AF00A0B326 /* Release */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | BUNDLE_LOADER = "$(TEST_HOST)"; 488 | DEVELOPMENT_TEAM = X37JS8D42G; 489 | INFOPLIST_FILE = TXScrollLabelViewDemoTests/Info.plist; 490 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 491 | PRODUCT_BUNDLE_IDENTIFIER = com.tingxins.TXScrollLabelViewDemoTests; 492 | PRODUCT_NAME = "$(TARGET_NAME)"; 493 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TXScrollLabelViewDemo.app/TXScrollLabelViewDemo"; 494 | }; 495 | name = Release; 496 | }; 497 | 97886DC81DB8E0AF00A0B326 /* Debug */ = { 498 | isa = XCBuildConfiguration; 499 | buildSettings = { 500 | DEVELOPMENT_TEAM = X37JS8D42G; 501 | INFOPLIST_FILE = TXScrollLabelViewDemoUITests/Info.plist; 502 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 503 | PRODUCT_BUNDLE_IDENTIFIER = com.tingxins.TXScrollLabelViewDemoUITests; 504 | PRODUCT_NAME = "$(TARGET_NAME)"; 505 | TEST_TARGET_NAME = TXScrollLabelViewDemo; 506 | }; 507 | name = Debug; 508 | }; 509 | 97886DC91DB8E0AF00A0B326 /* Release */ = { 510 | isa = XCBuildConfiguration; 511 | buildSettings = { 512 | DEVELOPMENT_TEAM = X37JS8D42G; 513 | INFOPLIST_FILE = TXScrollLabelViewDemoUITests/Info.plist; 514 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 515 | PRODUCT_BUNDLE_IDENTIFIER = com.tingxins.TXScrollLabelViewDemoUITests; 516 | PRODUCT_NAME = "$(TARGET_NAME)"; 517 | TEST_TARGET_NAME = TXScrollLabelViewDemo; 518 | }; 519 | name = Release; 520 | }; 521 | /* End XCBuildConfiguration section */ 522 | 523 | /* Begin XCConfigurationList section */ 524 | 97886D8F1DB8E0AF00A0B326 /* Build configuration list for PBXProject "TXScrollLabelViewDemo" */ = { 525 | isa = XCConfigurationList; 526 | buildConfigurations = ( 527 | 97886DBF1DB8E0AF00A0B326 /* Debug */, 528 | 97886DC01DB8E0AF00A0B326 /* Release */, 529 | ); 530 | defaultConfigurationIsVisible = 0; 531 | defaultConfigurationName = Release; 532 | }; 533 | 97886DC11DB8E0AF00A0B326 /* Build configuration list for PBXNativeTarget "TXScrollLabelViewDemo" */ = { 534 | isa = XCConfigurationList; 535 | buildConfigurations = ( 536 | 97886DC21DB8E0AF00A0B326 /* Debug */, 537 | 97886DC31DB8E0AF00A0B326 /* Release */, 538 | ); 539 | defaultConfigurationIsVisible = 0; 540 | defaultConfigurationName = Release; 541 | }; 542 | 97886DC41DB8E0AF00A0B326 /* Build configuration list for PBXNativeTarget "TXScrollLabelViewDemoTests" */ = { 543 | isa = XCConfigurationList; 544 | buildConfigurations = ( 545 | 97886DC51DB8E0AF00A0B326 /* Debug */, 546 | 97886DC61DB8E0AF00A0B326 /* Release */, 547 | ); 548 | defaultConfigurationIsVisible = 0; 549 | defaultConfigurationName = Release; 550 | }; 551 | 97886DC71DB8E0AF00A0B326 /* Build configuration list for PBXNativeTarget "TXScrollLabelViewDemoUITests" */ = { 552 | isa = XCConfigurationList; 553 | buildConfigurations = ( 554 | 97886DC81DB8E0AF00A0B326 /* Debug */, 555 | 97886DC91DB8E0AF00A0B326 /* Release */, 556 | ); 557 | defaultConfigurationIsVisible = 0; 558 | defaultConfigurationName = Release; 559 | }; 560 | /* End XCConfigurationList section */ 561 | }; 562 | rootObject = 97886D8C1DB8E0AF00A0B326 /* Project object */; 563 | } 564 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo.xcodeproj/xcshareddata/xcschemes/TXScrollLabelViewDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TXScrollLabelViewDemo 4 | // 5 | // Created by tingxins on 20/10/2016. 6 | // Copyright © 2016 tingxins. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TXScrollLabelViewDemo 4 | // 5 | // Created by tingxins on 20/10/2016. 6 | // Copyright © 2016 tingxins. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | // Override point for customization after application launch. 21 | // self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 22 | // self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]]; 23 | // [self.window makeKeyAndVisible]; 24 | 25 | return YES; 26 | } 27 | 28 | 29 | - (void)applicationWillResignActive:(UIApplication *)application { 30 | // 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. 31 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 32 | } 33 | 34 | 35 | - (void)applicationDidEnterBackground:(UIApplication *)application { 36 | // 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. 37 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 38 | } 39 | 40 | 41 | - (void)applicationWillEnterForeground:(UIApplication *)application { 42 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 43 | } 44 | 45 | 46 | - (void)applicationDidBecomeActive:(UIApplication *)application { 47 | // 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. 48 | } 49 | 50 | 51 | - (void)applicationWillTerminate:(UIApplication *)application { 52 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 53 | } 54 | 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ScrollLabel 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 59 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 86 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/NSString+AttributedString.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+AttributedString.h 3 | // TXScrollLabelViewDemo 4 | // 5 | // Created by 陈应平 on 2016/12/5. 6 | // Copyright © 2016年 tingxins. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (AttributedString) 12 | 13 | // 传递一个字符串数组,可以渲染不同的颜色,后期有需要可以把 color 和 font 也以数组的形式传递,配对使用 14 | - (NSMutableAttributedString *)setAttributedWithIdentifyStringArray:(NSArray *)identifyStringArray color:(UIColor *)color font:(UIFont *)font; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/NSString+AttributedString.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+AttributedString.m 3 | // TXScrollLabelViewDemo 4 | // 5 | // Created by 陈应平 on 2016/12/5. 6 | // Copyright © 2016年 tingxins. All rights reserved. 7 | // 8 | 9 | #import "NSString+AttributedString.h" 10 | 11 | @implementation NSString (AttributedString) 12 | 13 | - (NSMutableAttributedString *)setAttributedWithIdentifyStringArray:(NSArray *)identifyStringArray color:(UIColor *)color font:(UIFont *)font 14 | { 15 | if (!self && !identifyStringArray) { 16 | return nil; 17 | } 18 | 19 | if (!identifyStringArray.count) { 20 | return nil; 21 | } 22 | 23 | NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc]initWithString:self]; 24 | for (NSString *identifyString in identifyStringArray) { 25 | NSRange range = [self rangeOfString:identifyString]; 26 | if (font) { 27 | [attributedStr addAttribute:NSFontAttributeName value:font range:range]; 28 | } 29 | if (color) { 30 | [attributedStr addAttribute:NSForegroundColorAttributeName value:color range:range]; 31 | } 32 | } 33 | 34 | return attributedStr; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // TXScrollLabelViewDemo 4 | // 5 | // Created by tingxins on 20/10/2016. 6 | // Copyright © 2016 tingxins. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | @property (assign, nonatomic) IBInspectable BOOL isArray; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // TXScrollLabelViewDemo 4 | // 5 | // Created by tingxins on 20/10/2016. 6 | // Copyright © 2016 tingxins. All rights reserved. 7 | // 如果在使用 TXScrollLabelView 的过程中出现bug,请及时联系,我会尽快进行修复。如果有更好的点子,直接 Open an issue 或者 submit a pr。 8 | /** 9 | Blog : https://tingxins.com 10 | 简书 :http://www.jianshu.com/u/5141561e4d59 11 | GitHub : https://github.com/tingxins 12 | Weibo : http://weibo.com/tingxins 13 | Twitter : http://twitter.com/tingxins 14 | */ 15 | 16 | #import "ViewController.h" 17 | #import "TXScrollLabelView.h" 18 | 19 | @interface ViewController () 20 | 21 | @property (weak, nonatomic) TXScrollLabelView *scrollLabelView; 22 | 23 | @end 24 | 25 | @implementation ViewController 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | 30 | [self setViewInfos]; 31 | 32 | [self setSubviews]; 33 | 34 | } 35 | 36 | - (void)setViewInfos { 37 | self.view.backgroundColor = [UIColor whiteColor]; 38 | self.navigationController.navigationBar.translucent = NO; 39 | self.title = @"TXScrollLabelView"; 40 | } 41 | 42 | - (void)setSubviews { 43 | 44 | [self addWith:TXScrollLabelViewTypeLeftRight velocity:1 isArray:_isArray]; 45 | 46 | [self addWith:TXScrollLabelViewTypeUpDown velocity:2 isArray:_isArray]; 47 | 48 | [self addWith:TXScrollLabelViewTypeFlipRepeat velocity:2 isArray:_isArray]; 49 | 50 | [self addWith:TXScrollLabelViewTypeFlipNoRepeat velocity:2 isArray:_isArray]; 51 | } 52 | 53 | - (void)addWith:(TXScrollLabelViewType)type velocity:(CGFloat)velocity isArray:(BOOL)isArray { 54 | /** Step1: 滚动文字 */ 55 | 56 | NSString *scrollTitle = @"如果在使用 TXScrollLabelView 的过程中出现bug,请及时联系,我会尽快进行修复。如果有更好的点子,直接 Open an issue 或者 submit a pr on GitHub。Thanks."; 57 | 58 | NSArray *scrollTexts = @[@"If you need help or ask general question,", 59 | @"just @tingxins in Weibo or Twitter, ofcourse, you can follow me. Welcome access to my blog.", 60 | @"If you found a bug, just open an issue.", 61 | @"If you have a feature request, just open an issue.", 62 | @"If you want to contribute, fork this repository, and then submit a pull request.", 63 | @"Blog : https://tingxins.com", 64 | @"简书 :http://www.jianshu.com/u/5141561e4d59", 65 | @"GitHub : https://github.com/tingxins", 66 | @"Weibo : http://weibo.com/tingxins", 67 | @"Twitter : http://twitter.com/tingxins"]; 68 | 69 | /** Step2: 创建 ScrollLabelView */ 70 | TXScrollLabelView *scrollLabelView = nil; 71 | if (isArray) { 72 | scrollLabelView = [TXScrollLabelView scrollWithTextArray:scrollTexts type:type velocity:velocity options:UIViewAnimationOptionCurveEaseInOut inset:UIEdgeInsetsZero]; 73 | }else { 74 | scrollLabelView = [TXScrollLabelView scrollWithTitle:scrollTitle type:type velocity:velocity options:UIViewAnimationOptionCurveEaseInOut]; 75 | } 76 | 77 | /** Step3: 设置代理进行回调 */ 78 | scrollLabelView.scrollLabelViewDelegate = self; 79 | 80 | /** Step4: 布局(Required) */ 81 | scrollLabelView.frame = CGRectMake(50, 100 * (type + 0.7), 300, 30); 82 | 83 | [self.view addSubview:scrollLabelView]; 84 | 85 | //偏好(Optional), Preference,if you want. 86 | scrollLabelView.tx_centerX = [UIScreen mainScreen].bounds.size.width * 0.5; 87 | scrollLabelView.scrollInset = UIEdgeInsetsMake(0, 10 , 0, 10); 88 | scrollLabelView.scrollSpace = 10; 89 | scrollLabelView.font = [UIFont systemFontOfSize:15]; 90 | scrollLabelView.textAlignment = NSTextAlignmentCenter; 91 | scrollLabelView.backgroundColor = [UIColor blackColor]; 92 | scrollLabelView.layer.cornerRadius = 5; 93 | 94 | /** Step5: 开始滚动(Start scrolling!) */ 95 | [scrollLabelView beginScrolling]; 96 | } 97 | 98 | - (void)scrollLabelView:(TXScrollLabelView *)scrollLabelView didClickWithText:(NSString *)text atIndex:(NSInteger)index{ 99 | NSLog(@"%@--%ld",text, index); 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TXScrollLabelViewDemo 4 | // 5 | // Created by tingxins on 20/10/2016. 6 | // Copyright © 2016 tingxins. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemoTests/TXScrollLabelViewDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // TXScrollLabelViewDemoTests.m 3 | // TXScrollLabelViewDemoTests 4 | // 5 | // Created by tingxins on 20/10/2016. 6 | // Copyright © 2016 tingxins. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TXScrollLabelViewDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation TXScrollLabelViewDemoTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /TXScrollLabelViewDemo/TXScrollLabelViewDemoUITests/TXScrollLabelViewDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // TXScrollLabelViewDemoUITests.m 3 | // TXScrollLabelViewDemoUITests 4 | // 5 | // Created by tingxins on 20/10/2016. 6 | // Copyright © 2016 tingxins. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TXScrollLabelViewDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation TXScrollLabelViewDemoUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | --------------------------------------------------------------------------------