- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
在过去的几周里,我一直在为这个问题伤脑筋,我已经没有想法了..
我使用自定义 UICollectionViewFlowLayout
构建了自己的 UICollectionView
框架,用于垂直卡片分页和创建卡片堆叠效果。
这是它的样子的 gif:
我正在尝试实现一项允许用户滚动到特定索引处的特定卡片的功能(使用scrollToItem
例如函数)。
现在的问题是,由于某种原因,在尝试滚动回上一张卡片时无法正常工作。
下面是发生了什么的记录,我在上面附加了一个 tapGestureRecognizer,当我点击聚焦(当前居中)的卡片时,它应该滚动到该索引 - 1(所以之前的卡)。
出于某种原因,它只会在底部卡片的 frame.origin.y
高于聚焦(当前居中卡片)的 frame.origin.maxY
时执行此操作)。
请注意,我在卡片上轻敲两次以使其工作,因为底部卡片的 frame.origin.y
值需要低于 frame .origin.maxY
出于某种原因使它起作用。
collectionView.scrollToItem(at: convertIndexToIndexPath(for: index), at: .top, animated: animated)
和
if let frame = collectionView.layoutAttributesForItem(at: convertIndexToIndexPath(for: index))?.frame {
collectionView.scrollRectToVisible(frame, animated: true)
}
我已经找出是哪一行导致了这个问题,在 UICollectionViewFlowLayout
的子类(称为 VerticalCardSwiperFlowLayout
)中,有一个函数叫做 updateCellAttributes
,它修改了框架的某些属性以实现此效果。问题出现在以下行:
let finalY = max(cvMinY, cardMinY)
这是有问题的函数,包括在代码注释顶部对其工作原理的非常详尽的解释:
/**
Updates the attributes.
Here manipulate the zIndex of the cards here, calculate the positions and do the animations.
Below we'll briefly explain how the effect of scrolling a card to the background instead of the top is achieved.
Keep in mind that (x,y) coords in views start from the top left (x: 0,y: 0) and increase as you go down/to the right,
so as you go down, the y-value increases, and as you go right, the x value increases.
The two most important variables we use to achieve this effect are cvMinY and cardMinY.
* cvMinY (A): The top position of the collectionView + inset. On the drawings below it's marked as "A".
This position never changes (the value of the variable does, but the position is always at the top where "A" is marked).
* cardMinY (B): The top position of each card. On the drawings below it's marked as "B". As the user scrolls a card,
this position changes with the card position (as it's the top of the card).
When the card is moving down, this will go up, when the card is moving up, this will go down.
We then take the max(cvMinY, cardMinY) to get the highest value of those two and set that as the origin.y of the card.
By doing this, we ensure that the origin.y of a card never goes below cvMinY, thus preventing cards from scrolling upwards.
```
+---------+ +---------+
| | | |
| +-A=B-+ | | +-A-+ | ---> The top line here is the previous card
| | | | | +--B--+ | that's visible when the user starts scrolling.
| | | | | | | |
| | | | | | | | | As the card moves down,
| | | | | | | | v cardMinY ("B") goes up.
| +-----+ | | | | |
| | | +-----+ |
| +--B--+ | | +--B--+ |
| | | | | | | |
+-+-----+-+ +-+-----+-+
```
- parameter attributes: The attributes we're updating.
*/
fileprivate func updateCellAttributes(_ attributes: UICollectionViewLayoutAttributes) {
guard let collectionView = collectionView else { return }
var cvMinY = collectionView.bounds.minY + collectionView.contentInset.top
let cardMinY = attributes.frame.minY
var origin = attributes.frame.origin
let cardHeight = attributes.frame.height
if cvMinY > cardMinY + cardHeight + minimumLineSpacing + collectionView.contentInset.top {
cvMinY = 0
}
let finalY = max(cvMinY, cardMinY)
let deltaY = (finalY - cardMinY) / cardHeight
transformAttributes(attributes: attributes, deltaY: deltaY)
// Set the attributes frame position to the values we calculated
origin.x = collectionView.frame.width/2 - attributes.frame.width/2 - collectionView.contentInset.left
origin.y = finalY
attributes.frame = CGRect(origin: origin, size: attributes.frame.size)
attributes.zIndex = attributes.indexPath.row
}
// Creates and applies a CGAffineTransform to the attributes to recreate the effect of the card going to the background.
fileprivate func transformAttributes(attributes: UICollectionViewLayoutAttributes, deltaY: CGFloat) {
let translationScale = CGFloat((attributes.zIndex + 1) * 10)
if let itemTransform = firstItemTransform {
let scale = 1 - deltaY * itemTransform
var t = CGAffineTransform.identity
t = t.scaledBy(x: scale, y: 1)
if isPreviousCardVisible {
t = t.translatedBy(x: 0, y: (deltaY * translationScale))
}
attributes.transform = t
}
}
下面是调用该特定代码的函数:
internal override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let items = NSArray(array: super.layoutAttributesForElements(in: rect)!, copyItems: true)
for object in items {
if let attributes = object as? UICollectionViewLayoutAttributes {
self.updateCellAttributes(attributes)
}
}
return items as? [UICollectionViewLayoutAttributes]
}
如果您想亲自看看,可以在这里下载完整的项目: https://github.com/JoniVR/VerticalCardSwiper/archive/master.zip
(如果你通过github结账,一定要下载开发分支)
特定的 Github 问题可以找到一些讨论和可能的额外信息 here .
感谢您抽出宝贵时间,我们将不胜感激有关此问题的任何帮助或信息!另外,如果您有任何其他问题或缺少任何重要信息,请告诉我
编辑 1:注意:奇怪的效果只发生在滚动到 currentIndex - 1
时,currentIndex + 1
没有给出任何问题,我认为这在一定程度上解释了为什么它发生在 let finalY = max(cvMinY, cardMinY)
,但我还没有找到合适的解决方案。
最佳答案
我设法让它以另一种方式工作,方法是使用 setContentOffset
并手动计算偏移量。
guard index >= 0 && index < verticalCardSwiperView.numberOfItems(inSection: 0) else { return }
let y = CGFloat(index) * (flowLayout.cellHeight + flowLayout.minimumLineSpacing) - topInset
let point = CGPoint(x: verticalCardSwiperView.contentOffset.x, y: y)
verticalCardSwiperView.setContentOffset(point, animated: animated)
verticalCardSwiperView 基本上只是 UICollectionView
的子类,我这样做是因为我想缩小用户可以访问的范围,因为这是一个特定的库,允许完整的 collectionView 访问会让事情变得困惑。
如果您碰巧知道究竟是什么导致了这个问题,或者我该如何更好地解决它,我仍然很乐意找出答案:)
关于ios - UICollectionView scrollToItem() 滚动到上一个单元格无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54045707/
我有一个按钮的水平 Collection View 。单击其中一个 View Controller 时,用户将被带到另一个 View Controller 。通常,并非所有按钮都是可见的,因此我希望所
我有 UICollectionView 和两个 UIButton:WeekButton 和 MonthButton。当我触摸 WeekButton 或 MonthButton 时,我希望 UIColl
我有一个水平滚动的uicollectionview,其中带有我通过uicollectionviewdelegateflowlayout方法insetForSectionAt设置的插图。 在尝试使用方法
将 collectionView.scrollToItem 与 IndexPath 一起使用时。是否可以设置自定义滚动速度? 最佳答案 是的,这是可能的。试试这个: UIView.animate(wi
在过去的几周里,我一直在为这个问题伤脑筋,我已经没有想法了.. 短背景 我使用自定义 UICollectionViewFlowLayout 构建了自己的 UICollectionView 框架,用于垂
当我在模拟器上运行时它工作正常。但是当我在物理设备上运行时,我遇到了一个错误——index out of range。 代码: func collectionView(_ collectionView
我在 ViewController 中有两个 Collection View 。一个 Collection View 代表顶部的标签栏,另一个代表屏幕下半部分的页面。我在自定义 UIView(从另一个
为什么 scrollToItem 在我的 CollectionView 中不起作用?我想在 EnabledID 上使用 scrollToItem。那么问题是什么以及如何解决? 代码: var data
我有一个实现分页的 Collection View ,这就是为什么我在自定义 UICollectionViewFlowLayout 中覆盖 targetContentOffset 来处理它。当通过用户
我设法让我的 UICollectionView 使用 设置到所需的位置 override func viewDidLayoutSubviews() { collectionView.scrol
我有时会像这样滚动到单元格的左侧: collectionView.scrollToItem( at: IndexPath(row: 5, section: 0), at: .left,
我正在使用 React Native FlatList成分。单击列表项时,它会向列表中添加更多项并使用函数 ScrollToItem 滚动到其中之一。 . 有时在滚动时,我会在 android 上收到
我只是想在以编程方式滚动到项目时制作自定义动画。因此,当我不编写动画并按单元格使用默认值时,不会消失,但是当我将 scrolltoItem func 放入 UIView.animate func 时,
大家下午好 我遇到了一个关于我一直关注的聊天应用程序教程的令人沮丧的错误,我想补救(教程没有解决这个问题,因为我已经转换到 Swift 3/Xcode8)。让我尝试描述问题: 两个用户之间的聊天记录使
我使用的是 Collection View UICollectionView,它的效果非常好……除了我无法滚动到任何特定项目。它似乎总是滚动到“中间”是我最好的猜测。无论如何,我发送给 scrollT
我有一个带有内容偏移量的水平 UICollectionView,这样每个元素(包括最左边的项目)都可以滚动到中心: let cvOffset = (UIScreen.main.bounds.width
使用以下配置: let layout = UICollectionViewFlowLayout() layout.sectionHeadersPinToVisibleBounds = true let
我有一个 collectionView 的自定义布局。此自定义布局增加了中心单元格的宽度。这是执行此操作的自定义布局类。查看 shiftedAttributes 函数,看看它是如何完成的 class
以下函数加载一个 Messages 数组,重新加载 collectionView 并(应该)滚动到最后一项。 问题是最后一个项目向上滚动太远超出 View ,因此不可见。 注意:我使用了 3 种不同的
我是一名优秀的程序员,十分优秀!