@@ -620,7 +620,6 @@ final class StateController {
620
620
var allRects = [ ( frame: CGRect, indexPath: ItemPath, kind: ItemKind) ] ( )
621
621
// I dont think there can be more then a 200 elements on the screen simultaneously
622
622
allRects. reserveCapacity ( 200 )
623
- let skipIndex = 100
624
623
for sectionIndex in 0 ..< layout. sections. count {
625
624
let section = layout. sections [ sectionIndex]
626
625
let sectionPath = ItemPath ( item: 0 , section: sectionIndex)
@@ -632,22 +631,33 @@ final class StateController {
632
631
break
633
632
}
634
633
635
- var startingIndex = 0
636
- // Lets try to skip some calculations as visible rect most often is at the bottom of the layout
637
- if traverseState == . notFound {
638
- var iterationIndex = skipIndex
639
- while iterationIndex < section. items. count {
640
- let itemPath = ItemPath ( item: iterationIndex, section: sectionIndex)
641
- let itemFrame = self . itemFrame ( for: itemPath, kind: . cell, at: state, isFinal: true )
642
- if itemFrame == nil || itemFrame. map ( { $0. maxY < visibleRect. minY ? true : false } ) == true {
643
- startingIndex = iterationIndex
644
- iterationIndex += skipIndex
645
- continue
646
- } else {
647
- break
648
- }
634
+ guard let firstMatchIndex = Array ( section. items. enumerated ( ) ) . binarySearch ( predicate: { itemIndex, _ in
635
+ let itemPath = ItemPath ( item: itemIndex, section: sectionIndex)
636
+ guard let itemFrame = self . itemFrame ( for: itemPath, kind: . cell, at: state, isFinal: true ) else {
637
+ return . orderedDescending
638
+ }
639
+ if itemFrame. intersects ( visibleRect) {
640
+ return . orderedSame
641
+ }
642
+ if itemFrame. minY > visibleRect. maxY {
643
+ return . orderedDescending
644
+ }
645
+ return . orderedAscending
646
+ } ) else {
647
+ break
648
+ }
649
+ var startingIndex = firstMatchIndex
650
+ for itemIndex in ( 0 ..< firstMatchIndex) . reversed ( ) {
651
+ let itemPath = ItemPath ( item: itemIndex, section: sectionIndex)
652
+ guard let itemFrame = itemFrame ( for: itemPath, kind: . cell, at: state, isFinal: true ) else {
653
+ continue
654
+ }
655
+ guard itemFrame. maxY >= visibleRect. minY else {
656
+ break
649
657
}
658
+ startingIndex = itemIndex
650
659
}
660
+
651
661
if startingIndex < section. items. count {
652
662
for itemIndex in startingIndex..< section. items. count {
653
663
let itemPath = ItemPath ( item: itemIndex, section: sectionIndex)
@@ -813,3 +823,24 @@ final class StateController {
813
823
}
814
824
815
825
}
826
+
827
+ private extension RandomAccessCollection where Index == Int {
828
+
829
+ func binarySearch( predicate: ( Element ) -> ComparisonResult ) -> Index ? {
830
+ var lowerBound = startIndex
831
+ var upperBound = endIndex
832
+
833
+ while lowerBound < upperBound {
834
+ let midIndex = lowerBound + ( upperBound - lowerBound) / 2
835
+ if predicate ( self [ midIndex] ) == . orderedSame {
836
+ return midIndex
837
+ } else if predicate ( self [ midIndex] ) == . orderedAscending {
838
+ lowerBound = midIndex + 1
839
+ } else {
840
+ upperBound = midIndex
841
+ }
842
+ }
843
+ return nil
844
+ }
845
+
846
+ }
0 commit comments