iOS:一用就上癮的跑馬燈檢視

金字塔程式設計師發表於2018-05-02

簡介

在產品開發過程中,有可能會遇到這樣一個情況:一個UILabel設計為僅能顯示一行,但是在小屏手機中,因為寬度不夠,最終會顯示省略號...。 但是這些資訊又比較重要、不能省略,卻沒有充足的空間換行顯示。 那麼問題來了,該怎麼辦呢?這個時候,聰明的產品經理摸了摸下巴,突然雙眼放光“用跑馬燈啊”

image

好吧,既然產品都給出了精妙絕倫的方案,程式設計師的使命就是義無反顧地實現它!

Github地址

喜歡就給顆小星星喲❤️ JXMarqueeView地址️

動圖預覽

  • JXMarqueeType.left:往左滾動

    left.gif

  • JXMarqueeType.right:往右滾動

    right.gif

  • JXMarqueeType.reverse:迴圈反轉

    reverse.gif

  • 圖片滾動

    picture.gif

  • 自定義View

    poetry.gif

原理

  • 使用CADisplayLink,每次螢幕重新整理的時候,調整檢視的位置就行。為了達到迴圈顯示,需要新增兩個一樣的檢視。
  • 為了擴大跑馬燈的使用範圍,我進行了抽象化處理,並沒有寫死用UILabel來實現,而是暴露了一個屬性contentView: UIView。只要是UIView及其子類,都可以用來進行跑馬燈顯示。對於複雜的檢視,需要自己重寫contentView的sizeThatFits方法,返回正確的size即可。

這裡分享兩個騷操作:

  1. 如何實現UIView的拷貝?
//騷操作:UIView是沒有遵從拷貝協議的。可以通過UIView支援NSCoding協議,間接來複制一個檢視
let otherContentViewData = NSKeyedArchiver.archivedData(withRootObject: validContentView)
let otherContentView = NSKeyedUnarchiver.unarchiveObject(with: otherContentViewData) as! UIView
otherContentView.frame = CGRect(x: validContentView.bounds.size.width + contentMargin, y: 0, width: validContentView.bounds.size.width, height: self.bounds.size.height)
containerView.addSubview(otherContentView)
複製程式碼
  1. 如何斷開CADisplayLink的迴圈引用? 大家知道CADisplayLink和NSTimer都會對Target強持有,Target一般也會強持有它們。如果使用閉包回撥的API,可以解決這個問題,但是這些API要求iOS的系統都比較高。所以,還是需要直面這個問題。
override func willMove(toSuperview newSuperview: UIView?) {
        //騷操作:當檢視將被移除父檢視的時候,newSuperview就為nil。在這個時候,停止掉CADisplayLink,斷開迴圈引用,檢視就可以被正確釋放掉了。
        if newSuperview == nil {
            self.stopMarquee()
        }
    }
複製程式碼

使用

  • UILabel使用示例
let label = UILabel()
label.textColor = UIColor.red
label.font = UIFont.systemFont(ofSize: 30, weight: .medium)
label.text = "abcdefghijklmnopqrstuvwxyz"

marqueeView.contentView = label
marqueeView.contentMargin = 50
marqueeView.marqueeType = .left
self.view.addSubview(marqueeView)
複製程式碼
  • UIImageView使用示例
let imageView = UIImageView(image: UIImage(named: "haizeiwang.jpeg"))
imageView.contentMode = .scaleAspectFill

marqueeView.contentView = imageView
marqueeView.marqueeType = .reverse
self.view.addSubview(marqueeView)
複製程式碼
  • 拷貝自定義View

如果contentView帶有圓角、陰影等,通過NSCoding協議拷貝的View會丟失掉這些資訊。這種特殊情況需要自己重新建立一個同樣的自定義View。 重寫JXMarqueeViewCopyable協議的func copyMarqueeView() -> UIView方法即可。具體可以參考demo裡面的原始碼。

Github地址

喜歡就給顆小星星喲❤️ JXMarqueeView地址️

相關文章