iOS: An addictive marquee view as soon as you use it

Introduction

Github address, like to remember to give a little star ❤️ I believe that everyone will encounter such a situation at work. A UILabel only displays one line, and the display is incomplete in small-screen mobile phones... But these information are more important and cannot be omitted and there is not enough space to wrap the display. So here comes the question? How to do this? At this time, the smart product manager touched his chin, and suddenly his eyes lit up, "Use a marquee!"

image

Well, since the product has given a wonderful solution, the programmer's mission is to complete it without hesitation.

principle

  • The principle is very simple, just use CADisplayLink to continuously adjust the position of the view according to the refresh frequency. In order to achieve circular display, you need to add two identical views.
  • In order to expand the scope of use of the marquee, I abstracted it, and did not write a UILabel to implement it, but exposed a property contentView: UIView. As long as it is UIView and its subclasses, it can be used for marquee display. For complex views, you need to rewrite the sizeThatFits method of contentView yourself to return the correct size.
  • For specific details, please refer to the source code to understand, and here are two show operations:
  1. How to realize the copy of 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. How to break circular reference of CADisplayLink? We all know that both CADisplayLink and NSTimer will strongly hold Target, and Target will generally hold them too. If you use the API of the closure callback, you can solve this problem, but these APIs require the iOS system to be relatively high. So, this issue still needs to be faced.
override func willMove(toSuperview newSuperview: UIView?) {
        //骚操作:当视图将被移除父视图的时候,newSuperview就为nil。在这个时候,停止掉CADisplayLink,断开循环引用,视图就可以被正确释放掉了。
        if newSuperview == nil {
            self.stopMarquee()
        }
    }

use

//文字
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)

//图片
let imageView = UIImageView(image: UIImage(named: "haizeiwang.jpeg"))
        imageView.contentMode = .scaleAspectFill

marqueeView.contentView = imageView
marqueeView.marqueeType = .reverse
self.view.addSubview(marqueeView)

preview

JXMarqueeType.left: scroll left

left.gif

JXMarqueeType.right: scroll right

right.gif

JXMarqueeType.reverse: Cycle inversion

reverse.gif

picture

picture.gif

customize

poetry.gif

Github address, remember to give a little star if you like it ❤️

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325340262&siteId=291194637