IOS 文本跑馬燈效果(Objectc/Swift)

實現(xiàn)效果

QQ20200521-200338-HD.gif
  • 實現(xiàn)原理:動畫改變文本的y坐標(biāo)冲呢,同時使用把移出父布局的視圖立即移到父視圖的下方,使用一個臨時UIView來交替上下兩個視圖筐摘,達到利用的效果
  • 實現(xiàn)核心代碼如下:
    Object-c版本:
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

typedef void(^OnClickListener)(NSString* title);

@interface ScrollLabel : UILabel
@property(nonatomic,strong) UIView* parentView;
@property(nonatomic,strong) UIButton* upLabel;
@property(nonatomic,strong) UIButton* bottomLabel;
@property(nonatomic,copy) OnClickListener listener;

-(void) setTargetView:(UIView*) parentView withTitleArray:(NSMutableArray*)array;

-(void) setOnClickListener:(OnClickListener)listener;

-(void) start;

-(void) stop;

@end

NS_ASSUME_NONNULL_END

.m文件:

#import "ScrollLabel.h"
#import "UIView+Resize.h"

@interface  ScrollLabel()
@property(nonatomic,strong)NSMutableArray* titleArray;
@property(nonatomic,strong)NSTimer *timer;
@property(nonatomic,assign)NSInteger index;

@end

@implementation ScrollLabel

-(instancetype) init{
   if (self = [super init]) {
       
   }
   return self;
}

-(void) setTargetView:(UIView*) parentView withTitleArray:(NSMutableArray*)array{
   if (!parentView || !array || array.count == 0) {
       return;
   }
   self.titleArray = array;
   self.parentView = parentView;
   self.index = 0;
   
   self.upLabel = [[UIButton alloc] init];
   self.upLabel.backgroundColor = [UIColor greenColor];
   self.upLabel.tag = 21;
   [self.upLabel addTarget:self action:@selector(onClick:) forControlEvents:UIControlEventTouchUpInside];
   [self.upLabel setTitle:[array objectAtIndex:self.index] forState:UIControlStateNormal];
   self.upLabel.frame = CGRectMake(0, 0, parentView.frame.size.width,parentView.frame.size.height);
   self.index ++;
   
   self.bottomLabel = [[UIButton alloc] init];
   self.bottomLabel.tag = 22;
   [self.bottomLabel addTarget:self action:@selector(onClick:) forControlEvents:UIControlEventTouchUpInside];

   self.bottomLabel.frame = CGRectMake(0, self.upLabel.frame.size.height, parentView.frame.size.width,parentView.frame.size.height);
   [self.bottomLabel setTitle:[array objectAtIndex:self.index] forState:UIControlStateNormal];
   self.bottomLabel.backgroundColor = [UIColor brownColor];
   
   [self.parentView addSubview:self.upLabel];
   [self.parentView addSubview:self.bottomLabel];
   
}

-(void) onClick:(UIButton*) button{
   switch (button.tag) {
       case 21:
       case 22:
           if (self.listener) {
               self.listener(button.titleLabel.text);
           }
           break;
           
       default:
           break;
   }
}
-(void) setOnClickListener:(OnClickListener)listener{
   self.listener = listener;
}


-(void) start{
   if(self.titleArray.count == 1){
       return;
   }
   
   if (!self.timer) {
       self.timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
       [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
   }
  
}
-(void) timerAction{
   [UIView transitionWithView:self.upLabel duration:2 * 0.5 options:UIViewAnimationOptionCurveEaseInOut animations:^{
       self.upLabel.tx_bottom = 0;
       [UIView transitionWithView:self.upLabel duration:2 * 0.5 options:UIViewAnimationOptionCurveEaseInOut animations:^{
           self.bottomLabel.tx_y = 0;
       } completion:^(BOOL finished) {
           self.upLabel.tx_y = self.parentView.tx_height;
           UIButton *tempLabel = self.upLabel;
           self.upLabel = self.bottomLabel;
           self.bottomLabel = tempLabel;
           self.index ++;
           NSString* title = [self.titleArray objectAtIndex:self.index % self.titleArray.count];
           [tempLabel setTitle:title forState:UIControlStateNormal];
       }];
   } completion:^(BOOL finished){
   }];
   
}

-(void) stop{
   if(self.timer){
       [self.timer invalidate];
       self.timer = nil;
   }
}

@end

分類文件:


#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIView (Resize)

/** 設(shè)置x值 */
@property (assign, nonatomic) CGFloat tx_x;
/** 設(shè)置y值 */
@property (assign, nonatomic) CGFloat tx_y;
/** 設(shè)置width */
@property (assign, nonatomic) CGFloat tx_width;
/** 設(shè)置height */
@property (assign, nonatomic) CGFloat tx_height;
/** 設(shè)置size */
@property (assign, nonatomic) CGSize  tx_size;
/** 設(shè)置origin */
@property (assign, nonatomic) CGPoint tx_origin;
/** 設(shè)置center */
@property (assign, nonatomic) CGPoint tx_center;
/** 設(shè)置center.x */
@property (assign, nonatomic) CGFloat tx_centerX;
/** 設(shè)置center.y */
@property (assign, nonatomic) CGFloat tx_centerY;
/** 設(shè)置bottom */
@property (assign, nonatomic) CGFloat tx_bottom;

@end




#import "UIView+Resize.h"

@implementation UIView (Resize)

- (CGFloat)tx_x {
    return self.frame.origin.x;
}

- (void)setTx_x:(CGFloat)tx_x {
    CGRect frame = self.frame;
    frame.origin.x = tx_x;
    self.frame = frame;
}

- (CGFloat)tx_y {
    return self.frame.origin.y;
}

- (void)setTx_y:(CGFloat)tx_y {
    CGRect frame = self.frame;
    frame.origin.y = tx_y;
    self.frame = frame;
}

- (CGFloat)tx_width {
    return self.frame.size.width;
}

- (void)setTx_width:(CGFloat)tx_width {
    CGRect frame = self.frame;
    frame.size.width = tx_width;
    self.frame = frame;
}

- (CGFloat)tx_height {
    return self.frame.size.height;
}

- (void)setTx_height:(CGFloat)tx_height {
    CGRect frame = self.frame;
    frame.size.height = tx_height;
    self.frame = frame;
}

- (CGSize)tx_size {
    return self.frame.size;
}

- (void)setTx_size:(CGSize)tx_size {
    CGRect frame = self.frame;
    frame.size = tx_size;
    self.frame = frame;
}

- (CGPoint)tx_origin {
    return self.frame.origin;
}

- (void)setTx_origin:(CGPoint)tx_origin {
    CGRect frame = self.frame;
    frame.origin = tx_origin;
    self.frame = frame;
}

- (CGPoint)tx_center {
    return self.center;
}

- (void)setTx_center:(CGPoint)tx_center {
    self.center = tx_center;
}

- (CGFloat)tx_centerX {
    return self.center.x;
}

- (void)setTx_centerX:(CGFloat)tx_centerX {
    CGPoint center = self.center;
    center.x = tx_centerX;
    self.center = center;
}

- (CGFloat)tx_centerY {
    return self.center.y;
}

- (void)setTx_centerY:(CGFloat)tx_centerY {
    CGPoint center = self.center;
    center.y = tx_centerY;
    self.center = center;
}

- (CGFloat)tx_bottom {
    return CGRectGetMaxY(self.frame);
}

- (void)setTx_bottom:(CGFloat)tx_bottom {
    CGRect frame = self.frame;
    frame.origin.y = tx_bottom - frame.size.height;
    self.frame = frame;
}


@end

  • 測試代碼:
self.textView2 = [[UIView alloc] initWithFrame:CGRectMake(30, 160, 240, 40)];
    self.textView2.backgroundColor = [UIColor grayColor];
    self.textView2.clipsToBounds = true;
    [self.view addSubview:self.textView2];
    
    self.scrollLabel = [[ScrollLabel alloc] init];
    NSMutableArray* array = [NSMutableArray arrayWithArray:self.texts];
    [self.scrollLabel setTargetView:self.textView2 withTitleArray:array];
    [self.scrollLabel setOnClickListener:^(NSString* title){
        NSLog(@"91--------:%@",title);
    }];
  • swift 文件:
import UIKit

class ScrollLabel: UIView {

    lazy var parentView : UIView = UIView.init();
    lazy var upLabel : UIButton = UIButton.init();
    lazy var bottom : UIButton = UIButton.init();
    lazy var titleArray:NSMutableArray = NSMutableArray.init();
    var index:NSInteger = 0;
    lazy var timer:Timer? = Timer.init()
    
    override init(frame: CGRect) {
        super.init(frame:frame)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public func setTarget(_ parentView:UIView, withTitleArray array:NSMutableArray) ->Void {
        self.parentView = parentView
        self.titleArray = array
        
        self.upLabel.backgroundColor = UIColor.green;
        self.upLabel.tag = 21;
        self.upLabel.addTarget(self, action: #selector(onClickListener(btn:)), for:.touchUpInside)
        self.upLabel.setTitle(self.titleArray.object(at: self.index) as? String, for:.normal)
        self.upLabel.frame = CGRect.init(x: 0, y: 0, width: parentView.frame.size.width, height: parentView.frame.size.height)
    
        self.index += 1
       self.bottom.backgroundColor = UIColor.brown;
       self.bottom.tag = 22;
       self.bottom.addTarget(self, action: #selector(onClickListener(btn:)), for:.touchUpInside)
        self.bottom.setTitle(self.titleArray.object(at: self.index) as? String, for:.normal)
       self.bottom.frame = CGRect.init(x: 0, y: parentView.frame.size.height, width: parentView.frame.size.width, height: parentView.frame.size.height)
        
        parentView.addSubview(self.upLabel)
        parentView.addSubview(self.bottom)
    }
    
    
    @objc func onClickListener(btn : UIButton?)  {
        switch btn?.tag {
        case 21,22:
            NSLog("----")
            break;
        default:
            break;
        }
    }
    
    public func start() -> Void {
        if self.titleArray.count == 1 {
            return;
        }
        if self.timer == nil {
            
            self.timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(onFire), userInfo: nil, repeats: true);
                
            self.timer?.fire()
        }
        
        
    }
    
    @objc func onFire() -> Void {
        
        UIView.transition(with: self.upLabel, duration: 2 * 0.5, options: .curveEaseInOut, animations: {
            self.upLabel.tx_bottom = 0
            
            UIView.transition(with: self.upLabel, duration: 2 * 0.5, options: .curveEaseInOut, animations: {
                           
                           self.bottom.y = 0;
                           
                       }, completion: {_ in
                           self.upLabel.y = self.parentView.height;
                           let tempLabel = self.upLabel;
                           self.upLabel = self.bottom;
                           self.bottom = tempLabel;
                           self.index += 1;
                           let title = self.titleArray.object(at: self.index % self.titleArray.count) as? String
                           tempLabel.setTitle(title, for:.normal)
                       })
            
            
        }, completion: {_ in
        
        })
        
    }
    
    public func stop(){
        if(self.timer != nil){
            self.timer!.invalidate()
            self.timer = nil;
        }
        
    }
    
}

//UIView 的分類
extension UIView {
    // .x
    public var x: CGFloat {
        get {
            return self.frame.origin.x
        }
        set {
            var rect = self.frame
            rect.origin.x = newValue
            self.frame = rect
        }
    }
    
    // .y
    public var y: CGFloat {
        get {
            return self.frame.origin.y
        }
        set {
            var rect = self.frame
            rect.origin.y = newValue
            self.frame = rect
        }
    }
    
    // .maxX
    public var maxX: CGFloat {
        get {
            return self.frame.maxX
        }
    }
    
    // .maxY
    public var maxY: CGFloat {
        get {
            return self.frame.maxY
        }
    }
    
    // .centerX
    public var centerX: CGFloat {
        get {
            return self.center.x
        }
        set {
            self.center = CGPoint(x: newValue, y: self.center.y)
        }
    }
    
    // .centerY
    public var centerY: CGFloat {
        get {
            return self.center.y
        }
        set {
            self.center = CGPoint(x: self.center.x, y: newValue)
        }
    }
    
    // .width
    public var width: CGFloat {
        get {
            return self.frame.size.width
        }
        set {
            var rect = self.frame
            rect.size.width = newValue
            self.frame = rect
        }
    }
    
    // .height
    public var height: CGFloat {
        get {
            return self.frame.size.height
        }
        set {
            var rect = self.frame
            rect.size.height = newValue
            self.frame = rect
        }
    }
    
    public var tx_bottom:CGFloat{
        get {
            return self.frame.size.height
        }
        set {
            var rect = self.frame
            rect.origin.y = newValue - rect.size.height
            self.frame = rect
        }
    }
}

  • 測試?yán)?/li>
import UIKit


class ViewController: UIViewController {
    
    var scrollLabel:ScrollLabel?
    lazy var upLabel : UIButton = UIButton.init();

    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        self.upLabel.backgroundColor = UIColor.green;
       self.upLabel.tag = 21;
       self.upLabel.addTarget(self, action: #selector(onClickListener(btn:)), for:.touchUpInside)
       self.upLabel.setTitle("start", for:.normal)
       self.upLabel.frame = CGRect.init(x: 10, y: 50, width: 100, height: 50)
        self.view.addSubview(upLabel)
        
        let parentView : UIView = UIView.init(frame: CGRect.init(x: 50, y: 160, width: 180, height: 40))
        self.view.addSubview(parentView)
        parentView.backgroundColor = UIColor.blue
        parentView.clipsToBounds = true
        
        let array:NSMutableArray = NSMutableArray.init(objects: "香辣肉絲","聽你講個故事","聽你唱首歌",
        "高考","大學(xué)","工作","生活")
        
        scrollLabel = ScrollLabel();
        scrollLabel?.setTarget(parentView, withTitleArray: array)
        
        
    }
    
    @objc func onClickListener(btn : UIButton?)  {
           switch btn?.tag {
           case 21,22:
            scrollLabel?.start()
               break;
           default:
               break;
           }
       }


}


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末分瘦,一起剝皮案震驚了整個濱河市骄恶,隨后出現(xiàn)的幾起案子拇砰,更是在濱河造成了極大的恐慌梅忌,老刑警劉巖狰腌,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異牧氮,居然都是意外死亡琼腔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門蹋笼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來展姐,“玉大人,你說我怎么就攤上這事剖毯。” “怎么了教馆?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵逊谋,是天一觀的道長。 經(jīng)常有香客問我土铺,道長胶滋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任悲敷,我火速辦了婚禮究恤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘后德。我一直安慰自己部宿,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布瓢湃。 她就那樣靜靜地躺著理张,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绵患。 梳的紋絲不亂的頭發(fā)上雾叭,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音落蝙,去河邊找鬼织狐。 笑死,一個胖子當(dāng)著我的面吹牛筏勒,可吹牛的內(nèi)容都是我干的移迫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼奏寨,長吁一口氣:“原來是場噩夢啊……” “哼起意!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起病瞳,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤揽咕,失蹤者是張志新(化名)和其女友劉穎悲酷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亲善,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡设易,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛹头。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顿肺。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖渣蜗,靈堂內(nèi)的尸體忽然破棺而出屠尊,到底是詐尸還是另有隱情,我是刑警寧澤耕拷,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布讼昆,位于F島的核電站,受9級特大地震影響骚烧,放射性物質(zhì)發(fā)生泄漏浸赫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一赃绊、第九天 我趴在偏房一處隱蔽的房頂上張望既峡。 院中可真熱鬧,春花似錦碧查、人聲如沸运敢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽者冤。三九已至,卻和暖如春档痪,著一層夾襖步出監(jiān)牢的瞬間涉枫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工腐螟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留愿汰,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓乐纸,卻偏偏與公主長得像衬廷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子汽绢,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354