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

View File

@ -238,7 +238,9 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.listNode = ListView() self.listNode = ListView()
self.leftOverlayNode = ASDisplayNode() self.leftOverlayNode = ASDisplayNode()
self.leftOverlayNode.isUserInteractionEnabled = false
self.rightOverlayNode = ASDisplayNode() self.rightOverlayNode = ASDisplayNode()
self.rightOverlayNode.isUserInteractionEnabled = false
super.init() super.init()
@ -302,6 +304,14 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
let _ = strongSelf.contentScrollingEnded?(strongSelf.listNode) 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) let previousState = Atomic<ItemListNodeState?>(value: nil)
self.transitionDisposable.set(((state self.transitionDisposable.set(((state