Basic Concept

The SushiBelt can be used to measure exposure according to the ratio for all views on the UIScrollView.

There are many characteristics of SushiBelt.

First of all, The impression ratio can be set differently for each UIView.

In the context of online advertising, An impression is when an ad is fetched from its source, and is countable. Whether the ad is clicked is not taken into account. Each time an ad is fetched, it is counted as one impression.

In Summary, SushiBelt can measure the impression according to the objective visible ratio for each UIView.

  • Green Area means a measurable range.
  • Red line means a calculated visible ratio from SushiBelt.
  • Blue line means a objective visible ratio for impression.

Also, SushiBelt calculates visible ratio as the scroll direction changes.


  • Support a measurement of exposure ratio for each view.
  • Support a various item identifiers such as integer index, IndexPath, and user-defined identifier.
  • Visibility Debugger.

Basic usages

1. Create a SushiBeltTracker

let tracker = SushiBeltTracker()

tracker.delegate = someObject
tracker.dataSource = someObject
tracker.scrollView = someScrollView

2. Inherits a SushiBeltTrackerDataSource

extension SomeObject: SushiBeltTrackerDataSource {
  func trackingRect(_ tracker: SushiBeltTracker) -> CGRect {
    return CGRect(...) // tracking area rect
  func visibleRatioForItem(_ tracker: SushiBeltTracker, item: SushiBeltTrackerItem) -> CGFloat {
    return 0.0 // default is zero, return visible ratio for item

3. Inherits a SushiBeltTrackerDelegate

extension SomeObject: SushiBeltTrackerDelegate {
  func willBeginTracking(_ tracker: SushiBeltTracker, item: SushiBeltTrackerItem) {
    // begin tracking
  func didEndTracking(_ tracker: SushiBeltTracker, item: SushiBeltTrackerItem) {
    // did end tracking


Custom Identifier

If you cannot use identifier base on index or IndexPath, you can make a custom identifier with SushiBeltTrackerIdentifier!

struct SomeData: SushiBeltTrackerIdentifier {

  let id: Int

  var var trackingIdentifer: String { 
    return "SomeData-\(id)"


Default sushiBeltTrackerItem diff checker will update frameInWindow(CGRect) each overlaped items. also, it will decides ended items too. If you wanna to hook a diff mechanism then you can make a custom diff checker with SushiBeltTrackerItemDiffChecker interface.

final class CustomSushiBeltTrackerItemDiffChecker: SushiBeltTrackerItemDiffChecker { ... }

and you can injects a custom diff checker at making a SushiBeltTracker constructor.

let tracker = SushiBeltTracker(
 trackerItemDiffChecker: CustomSushiBeltTrackerItemDiffChecker()


Default visible ratio clculator will calculate with CGRect.intersection with scrollDirection. If you wanna make a custom visible ratio calculation logics. you can make a custom visible ratio calculator with SushiBeltTrackerItemDiffChecker interface. you just inherts it!

final class CustomVisibleRatioCalculator: VisibleRatioCalculator { ... }

and you can injects a custom visible ratio calculator at making a SushiBeltTracker constructor.

let tracker = SushiBeltTracker(
 visibleRatioCalculator: CustomVisibleRatioCalculator()


To run the example project, clone the repo, and run pod install from the Example directory first.


  • iOS 11.0



SushiBelt is available through CocoaPods. To install
it, simply add the following line to your Podfile:

pod 'SushiBelt'

Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler.
Once you have your Swift package set up, adding SushiBelt as a dependency is as easy as adding it to the dependencies value of your Package.swift.

dependencies: [
    .package(url: "", .upToNextMajor(from: "1.0.0"))



SushiBelt is available under the MIT license. See the LICENSE file for more info.


View Github