Instant View: fixed scroll to anchors

This commit is contained in:
Ilya Laktyushin
2018-11-21 04:24:53 +04:00
parent a99a30ac21
commit e08f1ffaec
7 changed files with 62 additions and 21 deletions

View File

@@ -368,7 +368,14 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
}
if self.currentExpandedDetails == nil {
if var currentExpandedDetails = self.currentExpandedDetails {
for (index, expanded) in expandedDetails {
if currentExpandedDetails[index] == nil {
currentExpandedDetails[index] = expanded
}
}
self.currentExpandedDetails = currentExpandedDetails
} else {
self.currentExpandedDetails = expandedDetails
}
@@ -540,8 +547,8 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
}
}
if let currentLayout = self.currentLayout, collapseOffset > 0.0 {
if let currentLayout = self.currentLayout {
let effectiveContentHeight = currentLayout.contentSize.height - collapseOffset
if effectiveContentHeight != self.scrollNode.view.contentSize.height {
transition.animateView {
@@ -928,12 +935,17 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
private func findAnchorItem(_ anchor: String, items: [InstantPageItem]) -> (InstantPageItem, CGFloat, [InstantPageDetailsItem])? {
for item in items {
if let item = item as? InstantPageAnchorItem, item.anchor == anchor {
return (item, 0.0, [])
return (item, -10.0, [])
} else if let item = item as? InstantPageTextItem {
if let lineIndex = item.anchors[anchor] {
return (item, item.lines[lineIndex].frame.minY - 10.0, [])
}
}
else if let item = item as? InstantPageTableItem {
if let offset = item.anchors[anchor] {
return (item, offset - 10.0, [])
}
}
else if let item = item as? InstantPageDetailsItem {
if let (foundItem, offset, detailsItems) = self.findAnchorItem(anchor, items: item.items) {
var detailsItems = detailsItems
@@ -965,14 +977,13 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let webPage = self.webPage, case let .Loaded(content) = webPage.content, let page = content.instantPage, page.url == baseUrl, let anchor = anchor {
if !anchor.isEmpty {
if let (item, lineOffset, detailsItems) = findAnchorItem(String(anchor), items: items) {
var previousDetailsItem: InstantPageDetailsItem?
var previousDetailsNode: InstantPageDetailsNode?
var containerOffset: CGFloat = 0.0
for detailsItem in detailsItems {
if let previousNode = previousDetailsNode, let previousDetailsItem = previousDetailsItem {
if let previousNode = previousDetailsNode {
previousNode.contentNode.updateDetailsExpanded(detailsItem.index, true, animated: false)
let frame = previousNode.contentNode.effectiveFrameForItem(detailsItem)
containerOffset += frame.minY + previousDetailsItem.titleHeight
let frame = previousNode.effectiveFrameForItem(detailsItem)
containerOffset += frame.minY
previousDetailsNode = previousNode.contentNode.nodeForDetailsItem(detailsItem)
previousDetailsNode?.setExpanded(true, animated: false)
@@ -983,18 +994,23 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
previousDetailsNode = self.nodeForDetailsItem(detailsItem)
previousDetailsNode?.setExpanded(true, animated: false)
previousDetailsItem = detailsItem
}
}
let frame: CGRect
if let previousDetailsNode = previousDetailsNode, let previousDetailsItem = previousDetailsItem {
containerOffset += previousDetailsItem.titleHeight
frame = previousDetailsNode.contentNode.effectiveFrameForItem(item)
if let previousDetailsNode = previousDetailsNode {
frame = previousDetailsNode.effectiveFrameForItem(item)
} else {
frame = self.effectiveFrameForItem(item)
}
self.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: containerOffset + frame.minY + lineOffset - self.scrollNode.view.contentInset.top), animated: true)
var targetY = min(containerOffset + frame.minY + lineOffset, self.scrollNode.view.contentSize.height - self.scrollNode.frame.height)
if targetY < self.scrollNode.view.contentOffset.y {
targetY -= self.scrollNode.view.contentInset.top
} else {
targetY -= self.containerLayout?.statusBarHeight ?? 20.0
}
self.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: targetY), animated: true)
}
} else {
self.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: -self.scrollNode.view.contentInset.top), animated: true)

View File

@@ -361,7 +361,7 @@ final class InstantPageDetailsContentNode : ASDisplayNode {
return CGRect(origin: origin, size: tile.frame.size)
}
func effectiveFrameForItem(_ item: InstantPageItem) -> CGRect {
fileprivate func effectiveFrameForItem(_ item: InstantPageItem) -> CGRect {
let layoutOrigin = item.frame.origin
var origin = layoutOrigin
@@ -610,6 +610,10 @@ final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
var effectiveContentSize: CGSize {
return self.contentNode.effectiveContentSize
}
func effectiveFrameForItem(_ item: InstantPageItem) -> CGRect {
return self.contentNode.effectiveFrameForItem(item).offsetBy(dx: 0.0, dy: self.item.titleHeight)
}
}
private final class InstantPageDetailsArrowNodeParameters: NSObject {

View File

@@ -32,11 +32,11 @@ final class InstantPageFeedbackItem: InstantPageItem {
}
func distanceThresholdGroup() -> Int? {
return nil
return 8
}
func distanceThresholdWithGroupCount(_ count: Int) -> CGFloat {
return 0.0
return CGFloat.greatestFiniteMagnitude
}
func linkSelectionRects(at point: CGPoint) -> [CGRect] {

View File

@@ -269,7 +269,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
for subBlock in blocks {
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - indexSpacing - maxIndexWidth, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: listItems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
let spacing: CGFloat = previousBlock != nil ? spacingBetweenBlocks(upper: previousBlock, lower: subBlock) : 0.0
let spacing: CGFloat = previousBlock != nil && subLayout.contentSize.height > 0.0 ? spacingBetweenBlocks(upper: previousBlock, lower: subBlock) : 0.0
let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + indexSpacing + maxIndexWidth, y: contentSize.height + spacing))
if previousBlock == nil {
originY += spacing

View File

@@ -4,7 +4,7 @@ import TelegramCore
func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?) -> CGFloat {
if let upper = upper, let lower = lower {
switch (upper, lower) {
case (_, .cover), (_, .channelBanner), (.details, .details), (.relatedArticles, nil), (.anchor, _), (_, .anchor):
case (_, .cover), (_, .channelBanner), (.details, .details), (.relatedArticles, nil), (_, .anchor):
return 0.0
case (.divider, _), (_, .divider):
return 25.0
@@ -49,7 +49,7 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?) ->
}
} else if let lower = lower {
switch lower {
case .cover, .channelBanner, .details:
case .cover, .channelBanner, .details, .anchor:
return 0.0
default:
return 25.0

View File

@@ -108,6 +108,8 @@ final class InstantPageTableItem: InstantPageScrollableItem {
fileprivate let cells: [InstantPageTableCellItem]
private let borderWidth: CGFloat
let anchors: [String: CGFloat]
fileprivate init(frame: CGRect, totalWidth: CGFloat, horizontalInset: CGFloat, borderWidth: CGFloat, theme: InstantPageTheme, cells: [InstantPageTableCellItem], rtl: Bool) {
self.frame = frame
self.totalWidth = totalWidth
@@ -116,6 +118,20 @@ final class InstantPageTableItem: InstantPageScrollableItem {
self.theme = theme
self.cells = cells
self.isRTL = rtl
var anchors: [String: CGFloat] = [:]
for cell in cells {
if let textItem = cell.textItem {
for (anchor, lineIndex) in textItem.anchors {
if anchors[anchor] == nil {
let textItemFrame = textItem.frame.offsetBy(dx: cell.frame.minX, dy: cell.frame.minY)
let offset = textItemFrame.minY + textItem.lines[lineIndex].frame.minY
anchors[anchor] = offset
}
}
}
}
self.anchors = anchors
}
var contentSize: CGSize {

View File

@@ -552,7 +552,8 @@ func layoutTextItemWithString(_ string: NSAttributedString, boundingWidth: CGFlo
var lastIndex: CFIndex = 0
var currentLineOrigin = CGPoint()
var hasAnchors = false
var maxLineWidth: CGFloat = 0.0
var maxImageHeight: CGFloat = 0.0
var extraDescent: CGFloat = 0.0
@@ -677,6 +678,10 @@ func layoutTextItemWithString(_ string: NSAttributedString, boundingWidth: CGFlo
}
}
if !anchorItems.isEmpty {
hasAnchors = true
}
if hadExtraDescent && extraDescent > 0 {
workingLineOrigin.y += fontLineSpacing
}
@@ -706,7 +711,7 @@ func layoutTextItemWithString(_ string: NSAttributedString, boundingWidth: CGFlo
}
var height: CGFloat = 0.0
if !lines.isEmpty {
if !lines.isEmpty && !(string.length == 1 && hasAnchors) {
height = lines.last!.frame.maxY + extraDescent
}