             .disposed(by: self.disposeBag)
     }
     
+    override func viewDidLayoutSubviews() {
+        super.viewDidLayoutSubviews()
+        
+        // Wait for UICollectionView to have populated with cells before
+        // enabling scroll position sync. Otherwise, UICollectionView
+        // will emit a new scroll position as the views are displayed.
+        if self.rows.value.count > 0 && !self.scrollSyncInitialised {
+            self.scrollSyncInitialised = true
+            
+            self.scrollTopDistance.asObservable()
+                .map({ CGPoint(x: 0, y: CGFloat($0)) })
+                .filter({ self.collectionView.contentOffset != $0 })
+                .bindTo(self.collectionView.rx.contentOffset)
+                .disposed(by: self.disposeBag)
+            
+            self.collectionView.rx.contentOffset.asObservable()
+                .map({ Float32($0.y) })
+                .filter({
+                    self.scrollTopDistance.value != $0
+                })
+                .subscribe { ev in
+                    let topDistance = ev.element ?? 0
+                    mainStore.dispatch(EventsBrowserActionUpdateScrollTopDistance(to: topDistance))
+                }
+                .disposed(by: self.disposeBag)
+        }
+    }
+    
     private func cellFactory(dataSource: CollectionViewSectionedDataSource<RowModel>,
                              collectionView: UICollectionView,
                              indexPath: IndexPath,

    fileprivate let dataSource = RxCollectionViewSectionedAnimatedDataSource<RowModel>();
    fileprivate let disposeBag = DisposeBag()
    fileprivate let rows = Variable<[Row]>([])
    
    override func viewDidLoad() {
        super.viewDidLoad()

    override func viewWillDisappear(_ animated: Bool) {
        mainStore.unsubscribe(self)
        mainStore.dispatch(EventsBrowserActionUpdateIsVisible(to: false))
        
        super.viewWillDisappear(animated)
    }
}
