     private var fromIndexPath: IndexPath? = nil
     private var swipingIndexPathes = Set<Int>()
     private var swipingToSelect = true
+    private var swipingLastLocation = CGPoint.zero
+    private var autoScrollingRate: CGFloat = 1.0
+    private var autoScrollingDirection: UISwipeGestureRecognizer.Direction = .down
+    private lazy var autoScrollingLink: CADisplayLink = {
+        let link = CADisplayLink(target: self, selector: #selector(autoScrolling))
+        link.isPaused = true
+        link.add(to: RunLoop.main, forMode: .default)
+        link.frameInterval = 1
+        return link
+    }()
     
     // use the swiping gesture to select the currently swiping cell.
     @objc private func swiping(gesture: UIPanGestureRecognizer) {

        if let currentViewSize = self.currentViewSize, currentViewSize.equalTo(self.view.bounds.size) {
            return
        } else {
            currentViewSize = self.view.bounds.size
        }
        
        self.collectionView?.collectionViewLayout.invalidateLayout()

                self.swipingToSelect = !cell.isSelected
            }
        case .changed:
            self.onSwipingChanged(location: location)
            self.startAutoScrollingIfNeeded(location: location)
        case .ended:
            fallthrough
        case .cancelled:
            fallthrough
        case .failed:
            self.swipingIndexPathes.removeAll()
            self.fromIndexPath = nil
            self.endAutoScrolling()
        }
    }
    
    private func onSwipingChanged(location: CGPoint) {
        self.swipingLastLocation = location
        
        if let toIndexPath = self.collectionView.indexPathForItem(at: location)
            , let fromIndexPath = self.fromIndexPath {
            let begin = min(fromIndexPath.row, toIndexPath.row)
            let end = max(fromIndexPath.row, toIndexPath.row)
            
            var currentSwipingIndexPathes = Set<Int>()
            for i in begin...end {
                currentSwipingIndexPathes.insert(i)
                self.swipingIndexPathes.remove(i)
                
                if self.swipingToSelect {
                    self.selectAsset(atIndex: IndexPath(row: i, section: 0))
                } else {
                    self.deselectAsset(atIndex: IndexPath(row: i, section: 0))
                }
            }
            
            for i in self.swipingIndexPathes {
                if self.swipingToSelect {
                    self.deselectAsset(atIndex: IndexPath(row: i, section: 0))
                } else {
                    self.selectAsset(atIndex: IndexPath(row: i, section: 0))
                }
            }
            self.swipingIndexPathes = currentSwipingIndexPathes
        }
    }
    
    private func startAutoScrollingIfNeeded(location: CGPoint) {
        let minLocationY = self.collectionView.contentOffset.y
        let maxLocationY = self.collectionView.bounds.height + self.collectionView.contentOffset.y

        debugPrint("minLocationY:\(minLocationY) maxLocationY:\(maxLocationY) current:\(location.y)")
        
        let locationY = min(max(location.y, minLocationY), maxLocationY)
        
        self.autoScrollingDirection = locationY - minLocationY > (maxLocationY - minLocationY) / 2 ? .down : .up
        var diff: CGFloat = 0
        switch self.autoScrollingDirection {
        case .down:
            diff = maxLocationY - locationY
        case .up:
            diff = locationY - minLocationY
        default:
            debugPrint("Known direction.")
        }
        
        let threshold = self.thumbnailSize.height / UIScreen.main.scale
        if diff < threshold {
            self.autoScrollingRate = threshold / max(diff, threshold / 10)
            self.startAutoScrolling()
        } else {
            self.endAutoScrolling()
        }
    }
    
    private func startAutoScrolling() {
        if self.autoScrollingLink.isPaused {
            self.autoScrollingLink.isPaused = false
        }
    }
    
    private func endAutoScrolling() {
        if !self.autoScrollingLink.isPaused {
            self.autoScrollingLink.isPaused = true
        }
    }
    
    @objc private func autoScrolling() {
        let offsetY = CGFloat(self.autoScrollingDirection == .down ? self.autoScrollingRate : -self.autoScrollingRate)
        
        var targetContentOffset = self.collectionView.contentOffset
        targetContentOffset.y += offsetY
        
        targetContentOffset.y = min(max(targetContentOffset.y, self.collectionView.contentInset.top),
                                    self.collectionView.contentSize.height - self.collectionView.bounds.height)
        
        self.collectionView.contentOffset = targetContentOffset
        
        self.onSwipingChanged(location: CGPoint(x: self.swipingLastLocation.x,
                                                y: self.swipingLastLocation.y + offsetY))
    }
    
    // MARK: - UIGestureRecognizerDelegate
