Objective c setCollectionViewLayout:动画导致调试错误:快照未渲染的视图会导致空快照
我正忙于iOS7中的UICollectionView 我正在两个不同的布局之间更改集合视图的布局。是UICollectionViewFlowLayout的子类 这是我在点击按钮时更改视图的方式:Objective c setCollectionViewLayout:动画导致调试错误:快照未渲染的视图会导致空快照,objective-c,ios7,uicollectionviewlayout,Objective C,Ios7,Uicollectionviewlayout,我正忙于iOS7中的UICollectionView 我正在两个不同的布局之间更改集合视图的布局。是UICollectionViewFlowLayout的子类 这是我在点击按钮时更改视图的方式: -(void)changeViewLayoutButtonPressed { self.changeLayout = !self.changeLayout; if (self.changeLayout){ [self.tableViewLayout invalidate
-(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];
}
}
此方法按预期工作,并通过漂亮的动画更改视图。但是,在控制台中,我收到以下消息:
对尚未渲染的视图进行快照将导致空视图
快照确保您的视图以前至少已渲染过一次
屏幕更新后的快照或快照
你知道是什么引起的吗 当方法-(UIView*)SnapshotViewAfterScreen更新时:
在尚未渲染的视图上生成此控制台警告
您正在某处调用此方法,或者更可能的情况是,setCollectionViewLayout:animated:
正在使用此方法,并且集合视图在使用时尚未呈现
我的建议是不要在集合视图上调用
-(void)invalidateLayout
,看看会发生什么。请不要扩展上面的评论
关于我收到的警告,奇怪的是我的简历有三个可能的数据源。所有这些数据基本上与:收集1、收集2、收集1和收集2相同
当我刚刚查看集合1或集合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
而不是
willAnimateRotationInterfaceOrientation:(UIInterfaceOrientation)到InterfaceOrientation持续时间:(NSTimeInterval)持续时间
解决了警告问题,但使转换更加粗糙
2。
摆脱对UICollectionViewFlowLayout
的显式更改,使用DelegateFlowLayout
方法并从willAnimateRotation…
调用reloadData
:
- (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个数据子集的消息总是为零,而整个数据集的消息总是一致的
祝你好运,希望有帮助。我遇到了同样的问题。我在我的收藏视图中使用了
UICollectionViewFlowLayout
。我想根据界面方向来安排布局
像往常一样,我超越了WillAnimateRotationInterfaceOrientation: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
属性和视图边界仍然是旧值。但是当事情发展到WillAnimateRotationInterfaceOrientation:duration:
时,这些值被更新了。这个问题也发生在我身上。
我通过调用:UIScreen.mainScreen().SnapshotViewAfterScreen更新(true)
beforesetCollectionViewLayout
方法来解决这个问题。
我也不知道为什么。
我希望它能有所帮助。我遇到了这个问题,因为我只在横向模式下使用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;
}
我需要做更多的测试,看看这是否是正确的方法,但现在它正在工作。当我试图自己解决这个问题时,由于同样的调试错误以及在动画中看到一些flash,我尝试了以下方法,效果很好:
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(AfterScreen更新:true)
以及在下一个主框架上更新新布局:
DispatchQueue.main.async{
self.collectionView!.setCollectionViewLayout(ListLayout(),动画:true)
}
这很有效
let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
flowLayout?.invalidateLayout()
DispatchQueue.main.async { [weak self] in
self?.collectionView.layoutIfNeeded()
}
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
}
}
}
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
}
}
}
[pCollectionView snapshotViewAfterScreenUpdates:YES];
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];