-->

Can I “take out” or “tear off” a cell from a UICol

2020-08-01 05:35发布

问题:

Note - it's possible UIViewControllerAnimatedTransitioning

https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewControllerAnimatedTransitioning_Protocol/Reference/Reference.html

is relevant here.

Note - I've just realised the new iOS7 "swipe-away" gesture is this concept

there are some answers HERE:

The UICollectionView "swipe-away" in iOS7 app manager?


Imagine your iPad has a UICollectionView ("bigView"), vertical, which contains 10 cells, each about 400x400 say. Imagine the bigView is on the right half of the screen, say.

I want to do this:

Cell number 3 is perhaps clicked.

That cell moves away from the collection view (say, to the left of the screen). TBC it moves outside the boundary of the UICollectionView. Ideally it becomes a normal UIView (say).

In fact, I want to:

(1) destroy the other 9 cells

(2) destroy entirely the UICollectionView

(3) in fact, convert the one cell, #3, to (I guess) a UIView

I'll take it from there!

Can this be done??

(a) can you "convert" a UICollectionViewCell to a UIView (does it have a UIView guts you can "remove" ??)

(b) can you (perhaps) destroy all of the other cells, leaving the UICollectionView as, indeed, really being only that one cell (and perhaps move the "whole thing") ...

(c) is there any other sort of "tear off" mechanism from a UICollectionView?


Having worked on this many, many times now, here's pretty much the simplest basic solution.

You'll have a class that is literally the collection view,

@interface BouncyItems : UICollectionViewController

in that class you'll have a didSelectItemAtIndexPath: or similar:

in there, you can easily get at the cell in question.

-(void)collectionView:(UICollectionView *)cv
  didSelectItemAtIndexPath:(NSIndexPath *)indexPath
    {
    NSInteger thisRow = indexPath.row;
    NSString *thatName = yourData.stuff[thisRow][@"nameField"];
    YourCellClass *cell = [cv cellForItemAtIndexPath:indexPath];
    
    NSLog(@"Yo, peeling off ....... %@  %@", theName);
    
    YourScene *parent = (YourScene *)self.parentViewController;
    [parent peelOff:cell.holder];
    }

But more importantly, you're going to have an actual scene, that has a container view, which is the collection view.

So in the example, "YourScene" is the UIViewController, which indeed has a few container views. One of those container views is indeed the collection view in question.

@interface YourScene:UIViewController
@property (nonatomic, strong) IBOutlet UIView *bouncyItemsContainer;
-(void)peelOff:(UIView *)peelMe;
@end

Note that in storyboard, looking at your BouncyItems, you would have dragged back the connection from it to "bouncyItemsContainer"

(No different than how you'd hook up buttons in "YourScene" to the relevant IBOutlet items.)

So, looking at the code in didSelectItemAtIndexPath, it's this easy,

    YourScene *parent = (YourScene *)self.parentViewController;
    [parent peelOff:cell.holder];

What is ".holder" .. explained below.

Now what is the routine peelOff ? Amazingly it's this simple.

The secret sauce is the convertPoint: line of code...

-(void)peelOff:(UIView *)peelMe
    {
    CGPoint oldCenter = [self.view
      convertPoint:peel.center
      fromView:peel.superview];
    [self.view addSubview:peelMe];
    peelMe.center = oldCenter;
    [self.bouncyItemsContainer exitLeft];
    }

{Recall that addSubview: conveniently removes the view from it's old superview, so it does all that for you in one line of code.}

So, that's it - the first three lines of code, you've removed the one cell, peelMe, from the container view. It is now just part of the normal scene, YourScene.

Next, simply "get rid of" the collection view. In my example, exitLeft simply animates it off the screen to the left.

So, it's perfect - you click on one cell; all the rest of the collection view animates off the screen (you could do whatever you want there, make them "fly off", face out, tumble - whatever), and the one chosen cell remains behind. Due to the "magic" convertPoint line of code, everything stays correctly in place.

Finally all cells must have a ".holder" which is.....

a UIView that holds everything in the cell; that's what you peel off. (This is the only practical solution, don't take out the underlying .contentView of the cell.) You can carefully arrange white/clear etc backgrounds so that everything "works" properly if you're flying stuff around in the scene.

So, that's all there is to it.

You now have (1) got rid of the collection view, and (2) your YourScene owns the thing that was a cell.

So, in peelOff: you would pass through the .holder UIVIew, and, you would probably also pass through some of your data, as in "the user has selected this house to see the interior" or whatever your context is.

Finally in the original question, it mentions then moving the peeled view, to some position on the YourScene. Of course, just animate it whether you want, probably in peelOff:.

Hope it helps.

回答1:

I've done something along these lines. I've implemented dragging of cells around the collection view and between sections. I also needed an 'external target' to the collection view to drag cells onto. I simply turned off masksToBounds on the collectionView's layer, and I was able to drag my fake floating cell (representing the real, hidden cell) beyond the bounds of the collection view.

Regardless, I think it's much easier to basically hide the cells that are not "focused" in your example, and animate out the changes for the focussed cell as needed.

Consider implementing - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect and - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath on your collection view layout/s. You can both relayout your collectionView to move/resize the focussed cell, as well as setting the frame of the "destroyed" cells to off screen, smaller, or otherwise modified.

You can also animate these layout changes, or even move between layouts, which can make for very nifty transitions.

There is no reason one cell in the collectionView cannot be very large and have a very different frame than all the other cells. If I were to do this, I might keep the normal cells in one section, and the focussed cell as the only cell in another (as it's trivial to move cells between sections). Then, using the above methods, I'd have an easier time theming the layout for the cells en masse, as I could refer the the items by section.