我在iOS7中忙于UICollectionView。
我正在两个不同的布局之间更改我的集合视图的布局。这是UICollectionViewFlowLayout的子类。
这是我点按按钮时更改视图的方式:
-(void)changeViewLayoutButtonPressed
{
self.changeLayout = !self.changeLayout;
if (self.changeLayout){
[self.tableViewLayout invalidateLayout];
[self.tradeFeedCollectionView setCollectionViewLayout:self.grideLayout animated:YES];
}
else {
[self.grideLayout invalidateLayout];
[self.tradeFeedCollectionView setCollectionViewLayout:self.tableViewLayout animated:YES];
}
}
此方法按预期工作,并使用漂亮的动画更改视图。但是在控制台中我收到这些消息:
快照未渲染的视图会导致空白 快照。确保您的视图至少在之前呈现过一次 屏幕更新后的快照或快照。
有关导致此问题的任何想法?
答案 0 :(得分:7)
请扩展上面的评论...
我收到警告的奇怪之处在于我的cv有三个可能的数据源。所有这些数据基本上与以下数据相同:Collection 1,Collection 2,Collection 1& 2。
当我刚看到Collection 1或Collection 2时,我没有收到任何警告。只有当我看到这两个组合时,我才收到警告。关于这一点的奇怪之处在于,没有什么可以展示一切。集合1和集合2是从"整体"中提取的。那么一个额外的步骤。不确定这意味着什么。
无论如何,我不再收到消息。
这是我原来的:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self arrangeCollectionView];
}
- (void)arrangeCollectionView
{
UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)self.cv.collectionViewLayout;
if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation))
{
flowLayout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16);
flowLayout.minimumInteritemSpacing = 16;
flowLayout.minimumLineSpacing = 16;
}
else
{
flowLayout.sectionInset = UIEdgeInsetsMake(26, 26, 26, 26);
flowLayout.minimumInteritemSpacing = 26;
flowLayout.minimumLineSpacing = 26;
}
self.cv.collectionViewLayout = flowLayout;
}
这给了我关于旋转到横向的信息,但是当旋转到肖像时没有。
这两项更改都没有消息:
<强> 1 即可。 使用
didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
拨打arrangeCollectionView
而不是
willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
解决了警告问题,但过渡时间有点粗糙。
<强> 2 即可。
摆脱对UICollectionViewFlowLayout
的明确更改并使用DelegateFlowLayout
方法并从reloadData
调用willAnimateRotation...
:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self.cv reloadData];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGSize retval = CGSizeMake(172, 256);
return retval;
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? UIEdgeInsetsMake(16 + 66, 16, 16, 16) : UIEdgeInsetsMake(26 + 66, 26, 26, 26);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? 16 : 28;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? 16 : 28;
}
这对我来说效果最好。没有更多的消息和从一个布局到另一个布局的相当平滑的过渡。
希望这可以帮助您追踪它。我想在流程布局失效期间会拍摄并呈现给用户,并且正在拍摄此快照,同时布局已经在willRotate...
中重置...也许无论如何。仍然不确定为什么我不断为2个数据子集提供零消息,并始终始终为完整集合提供消息。
答案 1 :(得分:5)
这个问题也发生在我身上。
我在UIScreen.mainScreen().snapshotViewAfterScreenUpdates(true)
方法之前调用setCollectionViewLayout
来解决此问题。
我也不知道为什么。
我希望它可以提供帮助。
答案 2 :(得分:5)
我遇到了这个问题,因为我只在横向模式下使用UICollectionView,而且第一次旋转到横向(并且只是第一次)时,我会获得许多关于快照的日志条目。我意识到日志条目的数量与单元格数量和标题视图相匹配,因此我将此代码添加到自定义单元格类和标题视图类中,并且日志条目消失了:
- (UIView*)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates
{
UIGraphicsBeginImageContext(self.bounds.size);
[self drawRect:self.bounds];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView* aView = [[UIImageView alloc] initWithFrame:self.bounds];
[aView setImage:viewImage];
return aView;
}
我需要做更多测试,看看这是否是正确的方法,但现在它正在发挥作用。
答案 3 :(得分:2)
当尚未呈现它的视图上的方法- (UIView *)snapshotViewAfterScreenUpdates:
生成此控制台警告时。
要么在某个地方调用此方法,要么更有可能setCollectionViewLayout: animated:
正在使用此方法,并且在使用它时集合视图未呈现。
我的建议是不要在集合视图上调用- (void)invalidateLayout
,看看会发生什么。
答案 4 :(得分:2)
我遇到了同样的问题。我在我的集合视图中使用UICollectionViewFlowLayout
。我想根据界面方向排列布局
像往常一样,我超越了willAnimateRotationToInterfaceOrientation:duration
。
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout;
layout.itemSize = aNewSize;
[layout invalidateLayout];
}
控制台中出现相同的消息。也许动画制作的快照失败了。我想,子视图没有足够的时间被捕获。
之后,我尝试了你的解决方案。我使用委托方法而不是直接分配项目大小。然而,模拟器仍然告诉我有警告。这里有些奇怪的东西。在调试过程中,我发现如果单元格的总数只有4,控制台就不会显示警告消息。当我将数字更改为10时,消息再次出现。不知道为什么。
让我们继续。我认为这个问题可能是因为在动画期间做布局工作。所以我将代码移到willRotateToInterfaceOrientation:duration:
。
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout;
layout.itemSize = aNewSize;
[self.collectionViewLayout invalidateLayout];
}
在第一个方法之前调用此方法。还有什么,消息不再显示。
顺便说一下,如果你动态安排单元格,你应该注意视图边界何时发生变化。在willRotateToInterfaceOrientation:duration:
中,interfaceOrientation
属性和视图边界仍然是旧值。但当事情发生willAnimateRotationToInterfaceOrientation:duration:
时,值已更新。
答案 5 :(得分:1)
虽然我尝试通过相同的调试错误自行修复此问题,并且在动画中看到一些闪光,但我尝试了以下操作,并且对我来说效果很好:
private var isListLayout = true{
didSet{
UIScreen.main.snapshotView(afterScreenUpdates: true)
collectionView!.collectionViewLayout.invalidateLayout()
if isListLayout {
DispatchQueue.main.async {
self.collectionView!.setCollectionViewLayout(ListLayout(), animated: true)
}
}else{
DispatchQueue.main.async {
self.collectionView!.setCollectionViewLayout(GridLayout(), animated: true)
}
}
}
}
如果您忽略var,关键是调用方法
UIScreen.main.snapshotView(afterScreenUpdates: true)
并在下一个主框架上更新新的布局:
DispatchQueue.main.async {
self.collectionView!.setCollectionViewLayout(ListLayout(), animated: true)
}
这对我来说很好,没有更多的调试问题,也没有间歇性的浮华动画
答案 6 :(得分:0)
在使布局无效之后,立即将DispatchQueue.main.async中的collectionView layoutIfNeeded()函数放入。
let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
flowLayout?.invalidateLayout()
DispatchQueue.main.async { [weak self] in
self?.collectionView.layoutIfNeeded()
}
答案 7 :(得分:0)
我有一个带有可调整大小单元格的收集视图,每当我旋转设备方向时,该单元格都会发出此警告。如果在旋转后可见某个单元,但在旋转前看不到该单元,则该设备仍将尝试对尚未渲染的单元的旋转前版本进行快照。因此,我最后在集合视图控制器中进行了检查,以查看旋转之前可见的单元格。这是用于垂直滚动集合视图的,但是您可能只是将引用交换为x,y,minX,minY等,以使其适用于水平集合视图。
override func viewWillTransition(
to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator)
{
super.viewWillTransition(to: size, with: coordinator)
let contentOffset = collectionView.contentOffset
let visibleFrame = view.safeAreaLayoutGuide.layoutFrame
collectionView.visibleCells.forEach { cell in
guard let customCell = cell as? CustomCell else {
return
}
let minY = customCell.frame.minY - contentOffset.y
let maxY = customCell.frame.maxY - contentOffset.y
if
visibleFrame.contains(CGPoint(x: visibleFrame.minX, y: minY)) ||
visibleFrame.contains(CGPoint(x: visibleFrame.minX, y: maxY))
{
customCell.shouldSnapshot = true
}
}
}
其中自定义单元格是具有以下内容的UICollectionViewCell子类:
class CustomCell: UICollectionViewCell {
var shouldSnapshot = false
override func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView? {
if shouldSnapshot {
shouldSnapshot = false
return super.snapshotView(afterScreenUpdates: afterUpdates)
} else {
return nil
}
}
}
我认为这已经完全摆脱了。我不能仅仅使用collectionView.visibleCells
返回的所有可见单元格来确定要快照的单元格,因为我仍在显示屏幕上几乎没有的单元格的日志消息(我目前的假设是,无论出于何种原因,安全区域不视为已渲染)。
答案 8 :(得分:0)
只需添加到UICollectionView
[pCollectionView snapshotViewAfterScreenUpdates:YES];
它将在Objective-C上查看,
pCollectionFlowLayot = [[UICollectionViewFlowLayout alloc] init];
[pCollectionFlowLayot setMinimumLineSpacing:10];
[pCollectionFlowLayot setMinimumLineSpacing:10];
[pCollectionFlowLayot setSectionInset:UIEdgeInsetsMake(10, 10, 10, 10)];
pCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:pCollectionFlowLayot];
[pCollectionView snapshotViewAfterScreenUpdates:YES];