import UIKit

open class PagingIndicatorLayoutAttributes: UICollectionViewLayoutAttributes {

  open var backgroundColor: UIColor?
  
  override open func copy(with zone: NSZone? = nil) -> Any {
    let copy = super.copy(with: zone) as! PagingIndicatorLayoutAttributes
    copy.backgroundColor = backgroundColor
    return copy
  }
  
  override open func isEqual(_ object: Any?) -> Bool {
    if let rhs = object as? PagingIndicatorLayoutAttributes {
      if backgroundColor != rhs.backgroundColor {
        return false
      }
      return super.isEqual(object)
    } else {
      return false
    }
  }
  
  func configure(_ options: PagingOptions) {
    if case let .visible(height, index, _, _) = options.indicatorOptions {
      backgroundColor = options.indicatorColor
      frame.size.height = height
      frame.origin.y = options.menuHeight - height
      zIndex = index
    }
  }
  
  func update(from: PagingIndicatorMetric, to: PagingIndicatorMetric, progress: CGFloat) {
    frame.origin.x = tween(from: from.x, to: to.x, progress: progress)
    frame.size.width = tween(from: from.width, to: to.width, progress: progress)
  }
  
  func update(to metric: PagingIndicatorMetric) {
    frame.origin.x = metric.x
    frame.size.width = metric.width
  }
  
}

import UIKit

open class PagingIndicatorLayoutAttributes: UICollectionViewLayoutAttributes {

  open var backgroundColor: UIColor?
  
  override open func copy(with zone: NSZone? = nil) -> Any {
    let copy = super.copy(with: zone) as! PagingIndicatorLayoutAttributes
    copy.backgroundColor = backgroundColor
    return copy
  }
  
  override open func isEqual(_ object: Any?) -> Bool {
    if let rhs = object as? PagingIndicatorLayoutAttributes {
      if backgroundColor != rhs.backgroundColor {
        return false
      }
      return super.isEqual(object)
    } else {
      return false
    }
  }
  
  func configure(_ options: PagingOptions) {
    if case let .visible(height, index, _, insets) = options.indicatorOptions {
      backgroundColor = options.indicatorColor
      frame.size.height = height
      frame.origin.y = options.menuHeight - height - insets.bottom + insets.top
      zIndex = index
    }
  }
  
  func update(from: PagingIndicatorMetric, to: PagingIndicatorMetric, progress: CGFloat) {
    frame.origin.x = tween(from: from.x, to: to.x, progress: progress)
    frame.size.width = tween(from: from.width, to: to.width, progress: progress)
  }
  
  func update(to metric: PagingIndicatorMetric) {
    frame.origin.x = metric.x
    frame.size.width = metric.width
  }
  
}

Include vertical insets for indicator view
Include vertical insets for indicator view

Account for the top and bottom insets when setting the frame for the
indicator view. This allows you to offset the indicator view from the
bottom of the menu.
