mrv*_*rvn 41 ios uicollectionview
默认情况下,Collection View在插入单元格时保持内容偏移.另一方面,我想在当前显示的单元格上方插入单元格,以便它们显示在屏幕顶部边缘上方,就像Messages.app在加载早期消息时一样.有谁知道实现它的方法?
小智 57
这是我使用的技术.我发现其他人会引起奇怪的副作用,例如屏幕闪烁:
CGFloat bottomOffset = self.collectionView.contentSize.height - self.collectionView.contentOffset.y;
[CATransaction begin];
[CATransaction setDisableActions:YES];
[self.collectionView performBatchUpdates:^{
[self.collectionView insertItemsAtIndexPaths:indexPaths];
} completion:^(BOOL finished) {
self.collectionView.contentOffset = CGPointMake(0, self.collectionView.contentSize.height - bottomOffset);
}];
[CATransaction commit];
Run Code Online (Sandbox Code Playgroud)
Seb*_*ian 23
let amount = 5 // change this to the amount of items to add
let section = 0 // change this to your needs, too
let contentHeight = self.collectionView!.contentSize.height
let offsetY = self.collectionView!.contentOffset.y
let bottomOffset = contentHeight - offsetY
CATransaction.begin()
CATransaction.setDisableActions(true)
self.collectionView!.performBatchUpdates({
var indexPaths = [NSIndexPath]()
for i in 0..<amount {
let index = 0 + i
indexPaths.append(NSIndexPath(forItem: index, inSection: section))
}
if indexPaths.count > 0 {
self.collectionView!.insertItemsAtIndexPaths(indexPaths)
}
}, completion: {
finished in
print("completed loading of new stuff, animating")
self.collectionView!.contentOffset = CGPointMake(0, self.collectionView!.contentSize.height - bottomOffset)
CATransaction.commit()
})
Run Code Online (Sandbox Code Playgroud)
Pet*_*ger 23
我的方法利用了子类流布局.这意味着您不必在视图控制器中破解滚动/布局代码.想法是,只要你知道你在顶部插入单元格就设置了自定义属性,你就会标记下一个布局更新会将单元格插入到顶部,并且在更新之前你会记住内容大小.然后覆盖prepareLayout()并在那里设置所需的内容偏移量.它看起来像这样:
定义变量
private var isInsertingCellsToTop: Bool = false
private var contentSizeWhenInsertingToTop: CGSize?
Run Code Online (Sandbox Code Playgroud)
覆盖 prepareLayout()
并在调用super之后
if isInsertingCellsToTop == true {
if let collectionView = collectionView, oldContentSize = contentSizeWhenInsertingToTop {
let newContentSize = collectionViewContentSize()
let contentOffsetY = collectionView.contentOffset.y + (newContentSize.height - oldContentSize.height)
let newOffset = CGPointMake(collectionView.contentOffset.x, contentOffsetY)
collectionView.setContentOffset(newOffset, animated: false)
}
contentSizeWhenInsertingToTop = nil
isInsertingMessagesToTop = false
}
Run Code Online (Sandbox Code Playgroud)
Fog*_*ter 12
我用两行代码做了这个(尽管它是在UITableView上),但我认为你能够以同样的方式做到这一点.
我将桌面视图旋转了180度.
然后我也将每个tableview单元旋转了180度.
这意味着我可以将它视为标准的从上到下的桌子,但底部被视为顶部.
Swift 3 版本代码:基于 James Martin 的回答
let amount = 1 // change this to the amount of items to add
let section = 0 // change this to your needs, too
let contentHeight = self.collectionView.contentSize.height
let offsetY = self.collectionView.contentOffset.y
let bottomOffset = contentHeight - offsetY
CATransaction.begin()
CATransaction.setDisableActions(true)
self.collectionView.performBatchUpdates({
var indexPaths = [NSIndexPath]()
for index in 0..<amount {
indexPaths.append(NSIndexPath(item: index, section: section))
}
if indexPaths.count > 0 {
self.collectionView.insertItems(at: indexPaths as [IndexPath])
}
}, completion: {
finished in
print("completed loading of new stuff, animating")
self.collectionView.contentOffset = CGPoint(x: 0, y: self.collectionView.contentSize.height - bottomOffset)
CATransaction.commit()
})
Run Code Online (Sandbox Code Playgroud)
添加到Fogmeister的答案(使用代码),最干净的方法是反转(颠倒),UICollectionView
以便您有一个粘贴到底部而不是顶部的滚动视图.UITableView
正如Fogmeister指出的那样,这也适用.
- (void)viewDidLoad
{
[super viewDidLoad];
self.collectionView.transform = CGAffineTransformMake(1, 0, 0, -1, 0, 0);
}
Run Code Online (Sandbox Code Playgroud)
在Swift中:
override func viewDidLoad() {
super.viewDidLoad()
collectionView.transform = CGAffineTransformMake(1, 0, 0, -1, 0, 0)
}
Run Code Online (Sandbox Code Playgroud)
这有副作用,也可以倒置显示你的细胞,所以你也必须翻转它们.所以我们cell.transform = collectionView.transform
像这样传输trasform():
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
cell.transform = collectionView.transform;
return cell;
}
Run Code Online (Sandbox Code Playgroud)
在Swift中:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! UICollectionViewCell
cell.transform = collectionView.transform
return cell
}
Run Code Online (Sandbox Code Playgroud)
最后,在这种设计下开发时要记住的主要事情是代理中的NSIndexPath
参数是相反的.那条indexPath.row == 0
行collectionView
通常位于顶部的底部.
在许多开源项目中使用此技术来产生所描述的行为,包括由Slack维护的流行的SlackTextViewController(https://github.com/slackhq/SlackTextViewController)
以为我会为Fogmeister的奇妙答案添加一些代码上下文!
这是Peter解决方案的稍作调整的版本(将流布局分类为子类,没有上下颠倒的轻量级方法)。是Swift 3。请注意UIView.animate
,持续时间为零-这是为了使单元的偶数/奇数(连续行)动画进行动画处理,但会停止视口偏移动画的更改(这看起来很糟糕)
用法:
let layout = self.collectionview.collectionViewLayout as! ContentSizePreservingFlowLayout
layout.isInsertingCellsToTop = true
self.collectionview.performBatchUpdates({
if let deletionIndexPaths = deletionIndexPaths, deletionIndexPaths.count > 0 {
self.collectionview.deleteItems(at: deletionIndexPaths.map { return IndexPath.init(item: $0.item+twitterItems, section: 0) })
}
if let insertionIndexPaths = insertionIndexPaths, insertionIndexPaths.count > 0 {
self.collectionview.insertItems(at: insertionIndexPaths.map { return IndexPath.init(item: $0.item+twitterItems, section: 0) })
}
}) { (finished) in
completionBlock?()
}
Run Code Online (Sandbox Code Playgroud)
下面是ContentSizePreservingFlowLayout
其全部:
class ContentSizePreservingFlowLayout: UICollectionViewFlowLayout {
var isInsertingCellsToTop: Bool = false {
didSet {
if isInsertingCellsToTop {
contentSizeBeforeInsertingToTop = collectionViewContentSize
}
}
}
private var contentSizeBeforeInsertingToTop: CGSize?
override func prepare() {
super.prepare()
if isInsertingCellsToTop == true {
if let collectionView = collectionView, let oldContentSize = contentSizeBeforeInsertingToTop {
UIView.animate(withDuration: 0, animations: {
let newContentSize = self.collectionViewContentSize
let contentOffsetY = collectionView.contentOffset.y + (newContentSize.height - oldContentSize.height)
let newOffset = CGPoint(x: collectionView.contentOffset.x, y: contentOffsetY)
collectionView.contentOffset = newOffset
})
}
contentSizeBeforeInsertingToTop = nil
isInsertingCellsToTop = false
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
22947 次 |
最近记录: |