5

I have a UICollectionView and two subclasses of UICollectionViewFlowLayout. When a cell is selected, I call setCollectionViewLayout:animated: to switch between the layouts. After the transition is done, the selected cell is centered, which is fine.

Can the same centering behavior be done without making the cell actually selected? I've tried to call setContentOffset:animated: in different methods without any success. Alternatively, can I specify a self defined contentOffset for the layout to be displayed?

To be more clear, I'd like to have something like this without modifying a cell's selected property:enter image description here

EDIT #1

This is what I already have:

[self.collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
[self.collectionView setCollectionViewLayout:layout animated:YES];

Looks fine: https://www.dropbox.com/s/9u6cnwwdbe9vss0/17249646-0.mov


But if I skip selectItemAtIndexPath:

[self.collectionView setCollectionViewLayout:layout animated:YES];
[self.collectionView scrollRectToVisible:targetFrame animated:YES];

This is not that fine (kind of waving animation): https://www.dropbox.com/s/s3u2eqq16tmex1v/17249646-1.mov

Attila H
  • 3,616
  • 2
  • 24
  • 37
  • Is the problem in the second scenario that the cell ends up too high? A couple of things come to mind. First, you might be affected by this [issue with `contentOffset`](http://stackoverflow.com/questions/13780138/dynamically-setting-layout-on-uicollectionview-causes-inexplicable-contentoffset). The suggestions in there might help you. Second, did you verify whether the frame passed to `scrollRectToVisible` is actually visible or not? Knowing that may help narrow down a solution. – Timothy Moose Jun 23 '13 at 17:10
  • If you check the second video, you can see that the contentOffset is kind of "waving". I goes up and down until it reaches it's final position. At the same time, on the first video there is only one straight motion. The problem is, that I can't reproduce that! – Attila H Jun 23 '13 at 17:29
  • I noticed that the final position in the two vids is different. So it might be that the frame you pass to scrollRectToVisible isn't right. I would suggest modifying that frame until you get the same final position and see if that helps. – Timothy Moose Jun 23 '13 at 17:45
  • Also, could you check the final values of `contentSize`, `contentOffset` and the cell's frame to verify that all values match between the two scenarios? – Timothy Moose Jun 23 '13 at 17:50
  • But shouldn't it work with any rect I specify? I mean, it's not restricted to use a rect that is perfectly centered. I guess the animation blocks of `setCollectionViewLayout` and `scrollRectToVisible` are in conflict somehow, which causes the waving thing. What do you think? – Attila H Jun 24 '13 at 05:30
  • Yes, conflicting. Just trying to eliminate variables. – Timothy Moose Jun 24 '13 at 12:38

1 Answers1

0

EDIT (changed answer after further clarification)

I've done similar with table views here. Basically, you call scrollRectToVisible:animated: having calculate a rect that will position your scroll view where you want it to end up. For exact positioning, I think you just need to calculate a rect the same size as your view. Note that if the content size is going to change, the rect should be calculated in the expected final content size.

ORIGINAL ANSWER

You can modify the layout generated by the super class by overriding layoutAttributesForElementsInRect:rect with something like this:

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSArray *poses = [super layoutAttributesForElementsInRect:rect];
    if (<test whether we want to modify poses>) {
        UICollectionViewLayoutAttributes *pose = poses[<index of pose to be modified>];
        pose.frame = <some other frame>;//modify the frame, for example
    }
    return poses;
}

You'd also need to override layoutAttributesForItemAtIndexPath with similar logic. The next step would be to invalidate or replace your layout when you want the changes to happen. You'd also need to pass some information. The layout would need to know what to do, so you could either pass it the relevant data or extend UICollectionViewDelegateFlowLayout1.

Timothy Moose
  • 9,895
  • 3
  • 33
  • 44
  • I don't want to modify the cells' (poses') frame. I only want to set a new content offset on the collection view upon the layout switch. So basically, something like calling setCollectionViewLayout:animated: and setContentOffset:animated: at the same time. – Attila H Jun 22 '13 at 16:30
  • Thanks for your edit, I've also edited the question. Take a look! – Attila H Jun 23 '13 at 13:49
  • I looked at this some more and the wavy motion is most certainly caused by two independent animations running for different durations. Is the effect really noticeable at full speed though? If you really want to fix it, you can use CADisplayLink (instead of `scrollRectToVisible`) to explicitly control the contentOffset at every step of the animation to force things to move in a straight line. But this seems like overkill to me given that things are moving smoothly between states as it is. – Timothy Moose Jun 30 '13 at 19:52
  • Yes, it's very noticeable and disturbing at full speed. If there is no workaround for this, I'll stick with manipulating the `selected` property. – Attila H Jul 01 '13 at 05:36