iOS - 支持水平/垂直顯示自動(dòng)滾動(dòng)的跑馬燈控件 --- SKAutoScrollLabel的使用和實(shí)現(xiàn)

簡(jiǎn)述

SKAutoScrollLabel是一個(gè)同時(shí)支持水平/垂直兩種類型的“跑馬燈”效果的自動(dòng)滾動(dòng)UILabel。在滾動(dòng)的邊緣使用了梯度褪色來解決滾動(dòng)邊緣生硬的效果問題沙庐,總體效果呈現(xiàn)出混然天成的感覺鲤妥,并且使用簡(jiǎn)單方便。如果你覺得還不錯(cuò)拱雏,請(qǐng)star支持一下吧~


效果圖

如何開始

1.從GitHub上Clone-->SKAutoScrollLabel棉安,然后查看Demo

2.直接將目錄下的SKAutoScrollLabel拷貝到工程中,或在podfile文件夾中添加 pod 'SKAutoScrollLabel'

使用方法

初始化

SKAutoScrollLabel * leftLabel = [[SKAutoScrollLabel alloc] initWithFrame:CGRectMake(50, 50, [UIScreen mainScreen].bounds.size.width - 100, 50)];
[self.view addSubview:leftLabel];

基本設(shè)置

leftLabel.backgroundColor = [UIColor blackColor];// 背景色
leftLabel.textColor = [UIColor whiteColor];// 字體顏色
leftLabel.font = [UIFont systemFontOfSize:16];// 字體大小
leftLabel.direction = SK_AUTOSCROLL_DIRECTION_LEFT;// 滾動(dòng)方向铸抑,這是向左滾動(dòng)
leftLabel.text = text;// 顯示內(nèi)容

實(shí)現(xiàn)

※ 這里僅列出關(guān)鍵步驟贡耽,具體方法請(qǐng)查閱源碼

  1. 我們需要?jiǎng)?chuàng)建一個(gè)數(shù)組,來存放我們滾動(dòng)時(shí)所需要展示的label鹊汛,這里我們只創(chuàng)建兩個(gè)label存放到數(shù)組中即可(滾動(dòng)只需要兩個(gè)即可達(dá)成持續(xù)跑馬燈的效果)
// 創(chuàng)建label數(shù)組
    NSMutableSet * labelSet = [[NSMutableSet alloc] init];
    for (NSInteger i = 0; i < kLabelCount; i++) {
        UILabel * label = [UILabel new];
        label.backgroundColor = [UIColor clearColor];
        label.autoresizingMask = self.autoresizingMask;
        label.frame = CGRectMake(0, 0, 50, 50);
        [self.scrollView addSubview:label];
        [labelSet addObject:label];
    }
    self.labels = [labelSet.allObjects copy];

2.區(qū)分水平和垂直的UILabel

static void each_object(NSArray *objects, void (^block)(UILabel * label)) {
    for (UILabel * label in objects) {
        block(label);
    }
}

__block float offset = 0;
     // 遍歷label數(shù)組中的元素
    each_object(self.labels, ^(UILabel *label) {
        [label sizeToFit];
        
        CGRect frame = label.frame;
        // 垂直
        if (self.direction != SK_AUTOSCROLL_DIRECTION_RIGHT && self.direction != SK_AUTOSCROLL_DIRECTION_LEFT) {
            // 動(dòng)態(tài)獲取長(zhǎng)度和高度, 以此達(dá)到將label垂直的目的
            NSDictionary * attribute = [NSDictionary dictionaryWithObjectsAndKeys:self.font,NSFontAttributeName, nil];
            CGSize sizeWord = [@"一" boundingRectWithSize:self.bounds.size options:NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin attributes:attribute context:nil].size;
            CGFloat wordWidth = sizeWord.width;
            CGSize sizeStr = [self.text boundingRectWithSize:CGSizeMake(wordWidth, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin attributes:attribute context:nil].size;
            CGFloat wordHeight = sizeStr.height;
            
            frame.origin = CGPointMake((CGRectGetWidth(self.frame) / 2) - (wordWidth / 2), offset);
            frame.size = CGSizeMake(wordWidth, wordHeight);
            label.frame = frame;
            label.numberOfLines = 0;
            offset += CGRectGetHeight(label.bounds) + self.labelSpacing;
            
        } else {// 水平
            frame.origin = CGPointMake(offset, 0);
            frame.size.height = CGRectGetHeight(self.bounds);
            label.frame = frame;
            offset += CGRectGetWidth(label.bounds) + self.labelSpacing;
            // 重新定位label在scrollview中的位置
            label.center = CGPointMake(label.center.x, roundf(self.center.y - CGRectGetMinY(self.frame)));
        }
        
    });

3.判斷滾動(dòng)條件蒲赂,是否允許滾動(dòng)

// (水平方向) 判斷當(dāng)前scrollLabel是否大于self的寬度,如果是就開始滾動(dòng)
    if (CGRectGetWidth(self.scrollLabel.bounds) > CGRectGetWidth(self.bounds)) {
        CGSize size = CGSizeMake(CGRectGetWidth(self.scrollLabel.bounds) + CGRectGetWidth(self.bounds) + self.labelSpacing,  CGRectGetHeight(self.bounds));
        self.scrollView.contentSize = size;
        
        EACH_LABEL(hidden, NO);
        
        [self applyGradientMaskForFadeLength:kDefaultFadeLength enableFade:self.scrolling];
        [self scrollLabelIfNeeded];
        
    } else if (CGRectGetHeight(self.scrollLabel.bounds) > CGRectGetHeight(self.bounds)) {// (垂直方向) 判斷當(dāng)前scrollLabel是否大于self的高度刁憋,如果是就開始滾動(dòng)
        CGSize size = CGSizeMake(CGRectGetWidth(self.bounds), CGRectGetHeight(self.scrollLabel.bounds) + self.labelSpacing);
        self.scrollView.contentSize = size;
        
        EACH_LABEL(hidden, NO);
        
        [self applyGradientMaskForFadeLength:kDefaultFadeLength enableFade:self.scrolling];
        [self scrollLabelIfNeeded];
        
    } else {
        // 隱藏其他label
        EACH_LABEL(hidden, self.scrollLabel != label);
        
        // 調(diào)整scrollView和scrollLabel
        self.scrollView.contentSize = self.bounds.size;
        self.scrollLabel.frame = self.bounds;
        self.scrollLabel.hidden = NO;
        self.scrollLabel.textAlignment = NSTextAlignmentCenter;
        
        [self.scrollView.layer removeAllAnimations];
        
        [self applyGradientMaskForFadeLength:0 enableFade:NO];
    }

4.自動(dòng)滾動(dòng)動(dòng)畫

switch (self.direction) {// 滾動(dòng)方向
        case SK_AUTOSCROLL_DIRECTION_LEFT:
            self.scrollView.contentOffset = CGPointZero;
            break;
        case SK_AUTOSCROLL_DIRECTION_RIGHT:
            self.scrollView.contentOffset = CGPointMake(width + self.labelSpacing, 0);
            break;
        case SK_AUTOSCROLL_DIRECTION_TOP:
            self.scrollView.contentOffset = CGPointZero;
            break;
        case SK_AUTOSCROLL_DIRECTION_BOTTOM:
            self.scrollView.contentOffset = CGPointMake(0, height - 10 - CGRectGetHeight(self.bounds));
            break;
    }
        
    // 滾動(dòng)動(dòng)畫, UIViewAnimationOptionRepeat一直重復(fù)動(dòng)畫
    [UIView animateWithDuration:duration delay:self.autoScrollInterval options:UIViewAnimationOptionRepeat animations:^{

        switch (self.direction) {
            case SK_AUTOSCROLL_DIRECTION_LEFT:
                self.scrollView.contentOffset = CGPointMake(width + self.labelSpacing, 0);
                break;
            case SK_AUTOSCROLL_DIRECTION_RIGHT:
                self.scrollView.contentOffset = CGPointZero;
                break;
            case SK_AUTOSCROLL_DIRECTION_TOP:
                self.scrollView.contentOffset = CGPointMake(0, CGRectGetHeight(self.scrollLabel.bounds) + self.labelSpacing);
                break;
            case SK_AUTOSCROLL_DIRECTION_BOTTOM:
                self.scrollView.contentOffset = CGPointZero;

                break;
        }

    } completion:^(BOOL finished) {
        _scrolling = NO;
        // 移除陰影
        [self applyGradientMaskForFadeLength:kDefaultFadeLength enableFade:NO];
        // 完成后循調(diào)用
        if (finished) {
            [self performSelector:@selector(scrollLabelIfNeeded)];
        }
    }];

5.使用CAGradientLayer在滾動(dòng)邊緣的制造梯度褪色效果

        // 創(chuàng)建梯度mask和消失長(zhǎng)度
        CAGradientLayer * gradientMask = [CAGradientLayer layer];
        gradientMask.bounds = self.layer.bounds;
        gradientMask.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
        
        gradientMask.shouldRasterize = YES;
        gradientMask.rasterizationScale = [UIScreen mainScreen].scale;
        
        CGFloat fadePoint = 0;
        // 垂直方向的梯度褪色
        if (self.direction != SK_AUTOSCROLL_DIRECTION_RIGHT && self.direction != SK_AUTOSCROLL_DIRECTION_LEFT) {
            gradientMask.startPoint = CGPointMake(CGRectGetMidX(self.frame), 0);
            gradientMask.endPoint = CGPointMake(CGRectGetMidX(self.frame), 1);
            fadePoint = fadeLength / CGRectGetHeight(self.bounds);
        // 水平方向的梯度褪色
        } else {
            gradientMask.startPoint = CGPointMake(0, CGRectGetMidY(self.frame));
            gradientMask.endPoint = CGPointMake(1, CGRectGetMidY(self.frame));
            fadePoint = fadeLength / CGRectGetWidth(self.bounds);
        }
        
        // 設(shè)置漸變mask顏色和位置
        id transparent = (id)[UIColor clearColor].CGColor;
        id opaque = (id)[UIColor blackColor].CGColor;
        gradientMask.colors = @[transparent, opaque, opaque, transparent];
        
        // 計(jì)算褪色
        NSNumber * leftFadePoint = @(fadePoint);
        NSNumber * rightFadePoint = @(1 - fadePoint);
        if (!fade) {
            switch (self.direction) {
                case SK_AUTOSCROLL_DIRECTION_LEFT:
                    leftFadePoint = @0;
                    break;
                case SK_AUTOSCROLL_DIRECTION_RIGHT:
                    leftFadePoint = @0;
                    rightFadePoint = @1;
                    break;
                case SK_AUTOSCROLL_DIRECTION_TOP:
                    leftFadePoint = @0;
                    break;
                case SK_AUTOSCROLL_DIRECTION_BOTTOM:
                    leftFadePoint = @0;
                    rightFadePoint = @1;
                    break;

            }
        }
        
        // 將計(jì)算結(jié)果交給mask
        gradientMask.locations = @[@0, leftFadePoint, rightFadePoint, @1];
        
        [CATransaction begin];
        [CATransaction setDisableActions:YES];
        self.layer.mask = gradientMask;
        [CATransaction commit];

感謝你花時(shí)間閱讀以上內(nèi)容, 如果這個(gè)項(xiàng)目能夠幫助到你滥嘴,記得告訴我

Email: shevakuilin@gmail.com

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市至耻,隨后出現(xiàn)的幾起案子若皱,更是在濱河造成了極大的恐慌镊叁,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件走触,死亡現(xiàn)場(chǎng)離奇詭異晦譬,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)互广,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門敛腌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人兜辞,你說我怎么就攤上這事迎瞧。” “怎么了逸吵?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)缝裁。 經(jīng)常有香客問我扫皱,道長(zhǎng),這世上最難降的妖魔是什么捷绑? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任韩脑,我火速辦了婚禮,結(jié)果婚禮上粹污,老公的妹妹穿的比我還像新娘段多。我一直安慰自己,他們只是感情好壮吩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布进苍。 她就那樣靜靜地躺著,像睡著了一般鸭叙。 火紅的嫁衣襯著肌膚如雪觉啊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天沈贝,我揣著相機(jī)與錄音杠人,去河邊找鬼。 笑死宋下,一個(gè)胖子當(dāng)著我的面吹牛嗡善,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播学歧,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼罩引,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了撩满?” 一聲冷哼從身側(cè)響起蜒程,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤绅你,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后昭躺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忌锯,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年领炫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了偶垮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡帝洪,死狀恐怖似舵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情葱峡,我是刑警寧澤砚哗,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站砰奕,受9級(jí)特大地震影響蛛芥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜军援,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一仅淑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胸哥,春花似錦涯竟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蝇庭,卻和暖如春醉鳖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哮内。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工盗棵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人北发。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓纹因,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親琳拨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瞭恰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容