Fix item list scrolling for touches outside section blocks

This commit is contained in:
Ilya Laktyushin 2020-07-27 18:26:36 +03:00
parent 2c52ee06de
commit 95b4d581cd
2 changed files with 67 additions and 49 deletions

View File

@ -184,6 +184,8 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
public final var keepMinimalScrollHeightWithTopInset: CGFloat?
public final var itemNodeHitTest: ((CGPoint) -> Bool)?
public final var stackFromBottom: Bool = false
public final var stackFromBottomInsetItemFactor: CGFloat = 0.0
public final var limitHitTestToNodes: Bool = false
@ -3876,67 +3878,73 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
}
self.touchesPosition = touchesPosition
self.selectionTouchLocation = touches.first!.location(in: self.view)
self.selectionTouchDelayTimer?.invalidate()
self.selectionLongTapDelayTimer?.invalidate()
self.selectionLongTapDelayTimer = nil
let timer = Timer(timeInterval: 0.08, target: ListViewTimerProxy { [weak self] in
if let strongSelf = self, strongSelf.selectionTouchLocation != nil {
strongSelf.clearHighlightAnimated(false)
if let index = strongSelf.itemIndexAtPoint(strongSelf.touchesPosition) {
var canBeSelectedOrLongTapped = false
for itemNode in strongSelf.itemNodes {
if itemNode.index == index && (strongSelf.items[index].selectable && itemNode.canBeSelected) || itemNode.canBeLongTapped {
canBeSelectedOrLongTapped = true
}
}
var processSelection = true
if let itemNodeHitTest = self.itemNodeHitTest, !itemNodeHitTest(touchesPosition) {
processSelection = false
}
if processSelection {
self.selectionTouchLocation = touches.first!.location(in: self.view)
self.selectionTouchDelayTimer?.invalidate()
self.selectionLongTapDelayTimer?.invalidate()
self.selectionLongTapDelayTimer = nil
let timer = Timer(timeInterval: 0.08, target: ListViewTimerProxy { [weak self] in
if let strongSelf = self, strongSelf.selectionTouchLocation != nil {
strongSelf.clearHighlightAnimated(false)
if canBeSelectedOrLongTapped {
strongSelf.highlightedItemIndex = index
if let index = strongSelf.itemIndexAtPoint(strongSelf.touchesPosition) {
var canBeSelectedOrLongTapped = false
for itemNode in strongSelf.itemNodes {
if itemNode.index == index && itemNode.canBeSelected {
if true {
if !itemNode.isLayerBacked {
strongSelf.reorderItemNodeToFront(itemNode)
for (_, headerNode) in strongSelf.itemHeaderNodes {
strongSelf.reorderHeaderNodeToFront(headerNode)
if itemNode.index == index && (strongSelf.items[index].selectable && itemNode.canBeSelected) || itemNode.canBeLongTapped {
canBeSelectedOrLongTapped = true
}
}
if canBeSelectedOrLongTapped {
strongSelf.highlightedItemIndex = index
for itemNode in strongSelf.itemNodes {
if itemNode.index == index && itemNode.canBeSelected {
if true {
if !itemNode.isLayerBacked {
strongSelf.reorderItemNodeToFront(itemNode)
for (_, headerNode) in strongSelf.itemHeaderNodes {
strongSelf.reorderHeaderNodeToFront(headerNode)
}
}
}
let itemNodeFrame = itemNode.frame
let itemNodeBounds = itemNode.bounds
if strongSelf.items[index].selectable {
itemNode.setHighlighted(true, at: strongSelf.touchesPosition.offsetBy(dx: -itemNodeFrame.minX + itemNodeBounds.minX, dy: -itemNodeFrame.minY + itemNodeBounds.minY), animated: false)
}
if itemNode.canBeLongTapped {
let timer = Timer(timeInterval: 0.3, target: ListViewTimerProxy {
if let strongSelf = self, strongSelf.highlightedItemIndex == index {
for itemNode in strongSelf.itemNodes {
if itemNode.index == index && itemNode.canBeLongTapped {
itemNode.longTapped()
strongSelf.clearHighlightAnimated(true)
strongSelf.selectionTouchLocation = nil
break
let itemNodeFrame = itemNode.frame
let itemNodeBounds = itemNode.bounds
if strongSelf.items[index].selectable {
itemNode.setHighlighted(true, at: strongSelf.touchesPosition.offsetBy(dx: -itemNodeFrame.minX + itemNodeBounds.minX, dy: -itemNodeFrame.minY + itemNodeBounds.minY), animated: false)
}
if itemNode.canBeLongTapped {
let timer = Timer(timeInterval: 0.3, target: ListViewTimerProxy {
if let strongSelf = self, strongSelf.highlightedItemIndex == index {
for itemNode in strongSelf.itemNodes {
if itemNode.index == index && itemNode.canBeLongTapped {
itemNode.longTapped()
strongSelf.clearHighlightAnimated(true)
strongSelf.selectionTouchLocation = nil
break
}
}
}
}
}, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false)
strongSelf.selectionLongTapDelayTimer = timer
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
}, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false)
strongSelf.selectionLongTapDelayTimer = timer
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
}
}
break
}
break
}
}
}
}
}
}, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false)
self.selectionTouchDelayTimer = timer
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
}, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false)
self.selectionTouchDelayTimer = timer
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
}
super.touchesBegan(touches, with: event)
self.updateScroller(transition: .immediate)

View File

@ -238,7 +238,9 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.listNode = ListView()
self.leftOverlayNode = ASDisplayNode()
self.leftOverlayNode.isUserInteractionEnabled = false
self.rightOverlayNode = ASDisplayNode()
self.rightOverlayNode.isUserInteractionEnabled = false
super.init()
@ -302,6 +304,14 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
let _ = strongSelf.contentScrollingEnded?(strongSelf.listNode)
}
}
self.listNode.itemNodeHitTest = { [weak self] point in
if let strongSelf = self {
return point.x > strongSelf.leftOverlayNode.frame.maxX && point.x < strongSelf.rightOverlayNode.frame.minX
} else {
return true
}
}
let previousState = Atomic<ItemListNodeState?>(value: nil)
self.transitionDisposable.set(((state