Swift -Swift Toast 源码分析

1,085 阅读3分钟

这是我参与更文挑战的第6天,活动详情查看: 更文挑战

image.png

Toast是平常开发中比较常用的提示组件和加载组件;Swift Toast 代码量不是很多,但是应用到了swift基数语法绝大多数的功能;对于巩固前面学习 struct,class,闭包, func ,变量的定义,extension 语法有非常大的帮助,在实战中应用,对理解语法上有了更深一层次; 同时对于新手来说难度也不是很大,不会感觉很吃力,对于老手就可以忽略不用看了,但可以学习下他的组件设计思想,整体比较简洁通用,高内聚低耦合可扩展;他不仅简单支持自己的toast展示,还支持用户自定义toast,对于位置也是支持自定义;除了常规的上,中,下还可以指定point..等等

短短783行代码就完成了日常中Toast90%以上的功能;基本做到了高内聚低耦合可扩展 ;是一个非常值得学习模仿的UI组件库

Toast的整体构建思路:

  1. 创建UIView分类, 这样所有的继承UIView类都具有toast展示的能力

    public extension UIView {
    
  2. 创建一个具有可展示ToastView

    // 创建 & 展示
    func makeToast(_ message: String?, duration: TimeInterval = ToastManager.shared.duration, position: ToastPosition = ToastManager.shared.position, title: String? = nil, image: UIImage? = nil, style: ToastStyle = ToastManager.shared.style, completion: ((_ didTap: Bool) -> Void)? = nil) {
            do {
              // toastViewForMessage 真实创建View的方法
                let toast = try toastViewForMessage(message, title: title, image: image, style: style)
              // 展示方法
                showToast(toast, duration: duration, position: position, completion: completion)
            } catch ToastError.missingParameters {
                print("Error: message, title, and image are all nil")
            } catch {}
        }
    
  3. 通用的展示showToast;不仅是自己创建Toast ,支持用户自定义View展示

    func showToast(_ toast: UIView, duration: TimeInterval = ToastManager.shared.duration, position: ToastPosition = ToastManager.shared.position, completion: ((_ didTap: Bool) -> Void)? = nil) {
            let point = position.centerPoint(forToast: toast, inSuperview: self)
            showToast(toast, duration: duration, point: point, completion: completion)
        }
    
  4. 支持创建模态的 ToastActivityView

    func makeToastActivity(_ position: ToastPosition) {
            // sanity
            guard objc_getAssociatedObject(self, &ToastKeys.activityView) as? UIView == nil else { return }
            // 创建通用的加载指示器视图
            let toast = createToastActivityView()
            let point = position.centerPoint(forToast: toast, inSuperview: self)
            makeToastActivity(toast, point: point)
        }
    

主要逻辑梳理

  1. 创建UIView的分类,这行就能支持所有的view类型 能进行toast提示; 这样代码比较简洁

    public extension UIView {
    
    self.view.makeToast("这是一个 toast")
    
    self.view.makeToast("这是一个自定义:指定动画时间和位置的Toast", duration: 3.0, position: .top)
    
    
  2. 创建默认toast

  3. 展示toast

    1. 展示默认toast

      1. self.view.makeToast("这是一个 toast")
        
    2. 也支持展示用户自定义的Toast

      1. self.view.showToast(myView)
        
  4. 支持创建模态Loading 指示器

    self.view.makeToastActivity(.center)
    
  5. 通过定义ToastStyle 对toast 的样式进行自定义

    1. public struct ToastStyle {
      
          public init() {}
        	// 默认背景颜色
          public var backgroundColor: UIColor = UIColor.black.withAlphaComponent(0.8)
          // 标题颜色
          public var titleColor: UIColor = T.color
      		// 内容颜色
          public var messageColor: UIColor = T.color
          /// 最大宽度百分比
          public var maxWidthPercentage: CGFloat = 0.8 {
              didSet {
                  maxWidthPercentage = max(min(maxWidthPercentage, 1.0), 0.0)
              }
          }
          public var maxHeightPercentage: CGFloat = 0.8 {
              didSet {
                  maxHeightPercentage = max(min(maxHeightPercentage, 1.0), 0.0)
              }
          }
      
          public var horizontalPadding: CGFloat = 10.0
          public var verticalPadding: CGFloat = 10.0
        
        	... 更多
      }
      
    2. // 创建一个新的 Style
      var style = ToastStyle()
      
      // 修改messageLabel的颜色
      style.messageColor = .blue
      
      // 展示一个toast,通过指定style
      self.view.makeToast("这是一个 toast", duration: 3.0, position: .bottom, style: style)
      
      // 也可以对全局toast进行样式设置
      ToastManager.shared.style = style
      
  6. 通过定义ToastPosition ,自定义toast展示位置:上,中,下 (默认)

    public enum ToastPosition {
        case top
        case center
        case bottom
    }
    
  7. 通过ToastManager 配置默认Toast的 style,position,动画时间长短,是否支持点击消失toast

    public class ToastManager {
        
        // 单例 
        public static let shared = ToastManager()
        
        // 默认样式
        public var style = ToastStyle()
        
        // 是否支持点击消失隐藏toast,默认是true
        public var isTapToDismissEnabled = true
        
        // 是否按照点击先后展示,还是立即展示出来
        public var isQueueEnabled = false
        
        // showToast 展示时间
        public var duration: TimeInterval = 3.0
        
        // 展示位置 :默认是底部
        public var position: ToastPosition = .bottom
        
    }