iOS LED跑马灯效果实现

iOS中实现LED跑马灯效果

实现原理是使用scrollView, 将需要滚动的label添加两次到 scrollView的subView下面, 然后通过滚动scrollView来实现跑马灯效果。

具体实现代码如下:

//
//  KMScrollLabel.swift
//  StopSmokingPrograms
//
//  Created by Fran on 15/11/2.
//  Copyright © 2015年 kimree. All rights reserved.
//

import UIKit

// 文字滚动方向
enum KMScrollDirection: Int{
    case Left = 0
    case Right
    case Up
    case Down
}

class KMScrollLabel: UIScrollView {

    // label 是只读的
    // 在外部只修改label的text即可
    private var label = UILabel()
    var textLabel: UILabel{
        get{
            return label
        }
    }

    // label是否在滑动
    private var keepScroll = false

    // 动画时间
    var animationDuringTime:Double = 5

    deinit{
        KMLog("KMScrollLabel deinit")
    }

    convenience init(){
        self.init(frame: CGRectZero)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        KMLog("init frame")

        self.scrollEnabled = false
        self.showsHorizontalScrollIndicator = false
        self.showsVerticalScrollIndicator = false
        self.addSubview(label)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        KMLog("init aDecoder")

        self.scrollEnabled = false
        self.showsHorizontalScrollIndicator = false
        self.showsVerticalScrollIndicator = false
        self.addSubview(label)
    }

    // MARK: - 开始滑动
    func startScroll(direction: KMScrollDirection = .Left){
        fitFrame(direction)

        // 当label不处于滑动状态时, 才可以开始滑动, 避免动画效果叠加
        if !keepScroll{
            keepScroll = true
            self.contentOffset = CGPointZero
            beginScroll(direction)
        }
    }

    // removeAllAnimations 之后会立刻执行 animation block 的 completion 部分,
    // 目前无法确定 completion 部分的参数总会是 false, 为了避免巧合, 需要配合 keepScroll 参数一起使用
    func stopScroll(){
        keepScroll = false
        self.layer.removeAllAnimations()
    }

    // MARK: - 具体怎样滑动
    func beginScroll(direction: KMScrollDirection = .Left){
        let w = label.frame.size.width
        let h = label.frame.size.height

        switch direction{
        case .Left:
            self.contentOffset.x = 0
            UIView.animateWithDuration(animationDuringTime, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: { [weak self]() -> Void in
                self?.contentOffset.x = w
                }, completion: { [weak self](finished: Bool) -> Void in
                    if finished && (self != nil && self!.keepScroll){
                        self!.contentOffset.x = 0
                        self!.beginScroll(direction)
                    }
                })

        case .Right:
            self.contentOffset.x = w
            UIView.animateWithDuration(animationDuringTime, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: { [weak self]() -> Void in
                self?.contentOffset.x = 0
                }, completion: { [weak self](finished: Bool) -> Void in
                    if finished && (self != nil && self!.keepScroll){
                        self!.contentOffset.x = w
                        self!.beginScroll(direction)
                    }
                })

        case .Up:
            self.contentOffset.y = 0
            UIView.animateWithDuration(animationDuringTime, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: { [weak self]() -> Void in
                self?.contentOffset.y = h
                }, completion: { [weak self](finished: Bool) -> Void in
                    if finished && (self != nil && self!.keepScroll){
                        self!.contentOffset.y = 0
                        self!.beginScroll(direction)
                    }
                })

        case .Down:
            self.contentOffset.y = h
            UIView.animateWithDuration(animationDuringTime, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: { [weak self]() -> Void in
                self?.contentOffset.y = 0
                }, completion: { [weak self](finished: Bool) -> Void in
                    if finished && (self != nil && self!.keepScroll){
                        self!.contentOffset.y = h
                        self!.beginScroll(direction)
                    }
                })
        }

    }

    // MARK: - 适配frame
    private func fitFrame(direction: KMScrollDirection){
        // 按照水平方向移动的要求修改frame
        func fitFrameAtHorizontalDirection(){

            let width = self.frame.size.width
            var height = self.frame.size.height

            label.numberOfLines = 1
            label.lineBreakMode = .ByWordWrapping
            var size = label.sizeThatFits(CGSizeMake(CGFloat.max, height))

            // scroll 的 height 不能小于 label 的 height
            if height < size.height{
                self.frame.size.height = size.height
                height = size.height
            }

            // label 的 width 要加上 scroll width 的一半作为留白, 并且 label 的 width 不能小于 scroll 的 width
            size.width += width / 2.0
            if size.width < width{
                size.width = width
            }

            label.frame = CGRectMake(0, (height - size.height) / 2.0, size.width, size.height)

            let tempLabel = NSKeyedUnarchiver.unarchiveObjectWithData(NSKeyedArchiver.archivedDataWithRootObject(label)) as! UILabel
            tempLabel.frame.origin.x += size.width
            self.addSubview(tempLabel)

            self.contentSize = CGSizeMake(2 * size.width, height)
        }

        // 按照竖直方向移动的要求修改frame
        func fitFrameAtVerticalDirection(){

            var width = self.frame.size.width
            let height = self.frame.size.height

            label.numberOfLines = 0
            label.lineBreakMode = .ByWordWrapping
            let originalText = label.text

            // 获取单个文字的宽度
            label.text = "田"
            let singleSize = label.sizeThatFits(CGSizeZero)

            label.text = originalText
            var size = label.sizeThatFits(CGSizeMake(singleSize.width, CGFloat.max))

            if width < size.width{
                self.frame.size.width = size.width
                width = size.width
            }

            size.height += height / 2.0
            if size.height < height{
                size.height = height
            }

            label.frame = CGRectMake((width - size.width) / 2.0, 0, size.width, size.height)

            let tempLabel = NSKeyedUnarchiver.unarchiveObjectWithData(NSKeyedArchiver.archivedDataWithRootObject(label)) as! UILabel
            tempLabel.frame.origin.y += size.height
            self.addSubview(tempLabel)

            self.contentSize = CGSizeMake(width, 2 * size.height)
        }

        // 首先遍历 scroll 的所有 subView, 将占位的 label 移除
        for view in self.subviews{
            if view != label{
                view.removeFromSuperview()
            }
        }

        switch direction{
        case .Left, .Right:
            fitFrameAtHorizontalDirection()
        case .Up, .Down:
            fitFrameAtVerticalDirection()
        }

    }

    /*
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func drawRect(rect: CGRect) {
    // Drawing code
    }
    */

}

  

时间: 2024-11-10 07:48:06

iOS LED跑马灯效果实现的相关文章

LED跑马灯效果

今天在百度知道上帮网友解决一些问题,看到了一个类似跑马灯的效果,这个以前也有想过要写,但是没有什么头绪和时间,现在顺便就一起解决了. 这个LED跑马灯的效果是怎么一个原理,现分析如下: 假设有一个要进行变化的对象数组,我们称之为A对象.如下: 这个等变化的数组长度为5, 有颜色数组,我们称之为B,如下: 这个长度为3. 要分析出原理,我们要根据事物的表象去分析得到事物内在的规律与原理,根据这个原理与规律我们才能得出解决办法. 我们进行一次模拟: (1)初始状态 (2)移动过程中的某一状态 我们可

iOS实现跑马灯效果

在网页开发当中跑马灯是常用到的,用来显示通知等,在游戏开发当中也如此. 下面的代码片断可实现iOS中的跑马灯效果, [labelShow sizeToFit]; CGRect frame = labelShow.frame; frame.origin.x = 320; labelShow.frame = frame; [UIView beginAnimations:@"testAnimation" context:NULL]; [UIView setAnimationDuration:

iOS中跑马灯效果小结

时光过得好快,记忆中刚刚从春节返回没有多久,清明.五一已飞逝而过,眨眼已到盛夏季节.不过还好,济南这两年不算太热,刚开始升温几天,一场及时雨总能让温度保持适宜.为了纪念一下青春的尾巴,也为了能有个健康的身体和充沛的精力,现在上下班都开始步行.人生就是一场马拉松,无论何时何地都得学会享受好生活.每天早晚4公里的步行健身,晚上适当的跑步.看书.电视剧.音乐电台,整个人也感觉充实成长了好多.心静了,自信了,才能安宁,才能做好每一件事情.年后的这段期间做了一个公司自己的社交项目,总得来说学到很多,另外两

2、按下按键S1控制LED1.LED2.LED3实现跑马灯效果(CC2540开发寄存器设置)

按下按键S1控制LED1.LED2.LED3实现跑马灯效果 1 /**************************************************************************** 2 * 文 件 名: main.c 3 * 作 者: Amo [ www.amoMcu.com 阿莫单片机] 4 * 修 订: 2014-04-08 5 * 版 本: 1.0 6 * 描 述: 按下按键S1控制LED1.LED2.LED3实现跑马灯效果 7 ***********

Vue教程02(跑马灯效果案例) &#253148;

原文: http://blog.gqylpy.com/gqy/423 置顶:来自一名75后老程序员的武林秘籍--必读(博主推荐) 来,先呈上武林秘籍链接:http://blog.gqylpy.com/gqy/401/ 你好,我是一名极客!一个 75 后的老工程师! 我将花两分钟,表述清楚我让你读这段文字的目的! 如果你看过武侠小说,你可以把这个经历理解为,你失足落入一个山洞遇到了一位垂暮的老者!而这位老者打算传你一套武功秘籍! 没错,我就是这个老者! 干研发 20 多年了!我也年轻过,奋斗过!我

练习:WinForm 跑马灯效果+Timer

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Timer { public partial class Form1 : Form { public Form1

Android TextView跑马灯效果

TextView跑马灯简单效果 <!--简单示例--> <TextView android:text="@string/longWord" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textView1" android:ellipsize="marquee&quo

android 怎么实现跑马灯效果

自定义控件 FocusedTextView, 使android系统误以为它拥有焦点 1 public class FocusedTextView extends TextView { 2 public FocusedTextView(Context context, AttributeSet attrs, int defStyle) { 3 super(context, attrs, defStyle); 4 // TODO Auto-generated constructor stub 5 }

框架,锚点,背景音乐,嵌入视频和跑马灯效果

框架,iframe有点过时,会在部分浏览器出现一些奇怪的问题:设置三个属性: 1.src,框架默认的显示路径 2.name,让超链接的target属性与name值相等,就可以将超链接网页在框架中打开 3.框架的宽度和高度 站点:实际上就是一个文件夹,单独起了一个名字.统一来管理所有页面,就是一个站点,称之为网站 锚点: 书写格式:<a href="#锚点位置对应的名称">内容</a> --#是在本页面中 <a name="锚点位置的名称"