iOS Flow Layout Uicollectionview Series six--apply layouts from flat to spaceFirst, Introduction
Earlier, we expanded the layout from a linear waterfall flow layout to a ring layout, which allowed us to take a big step forward with the layout of the Uicollectionview, this time, we played a little more flashy, think of ways to apply the layout space, do you still remember, In the class Uicollectionviewlayoutattributrs class that manages the specific properties of the layout of item, there is Transform3D this property, which, through the setting of this property, we can really design the layout in the coordinate system of the space. iOS system controls, nor is there no such precedent, Uipickerview is a good example of this blog, we use Uicollectionview to implement a similar system Uipickerview layout view, To experience the charm of Uicollectionview in the layout of 3D controls. The Pickerview effect of the system is as follows:
Second, first to achieve a cool roller space layout
Lofty high-rise is also made up of brick by brick, before we fully simulate the system Pickerview, we should first put the layout of the view to solve the problem. We're still going to create a class that inherits from Uicollectionviewlayout:
@interface Mylayout:uicollectionviewlayout@end
For the contents of the. m file, we've all made static layouts in preparelayout for the previous blogs, because the layouts in our previous blogs are static, and the layout doesn't change too much with our gesture operations, so we're all configured in Preparelayout. And the layout we're going to talk about is different, Pickerview will scroll with the drag of our fingers, so the layout of each item in Uicollectionview is constantly changing, so this time, we use dynamic configuration, The Layout property settings for each item are made in the Layoutattributesforitematindexpath method.
As for the Layoutattributesforitematindexpath method, it is also a method in the Uicollectionviewlayout class for rewriting when we customize, as to why dynamic layouts are configured to configure the item's layout properties here. We'll find out later.
Before writing our layout class, get ready to do the following code in Viewcontroller:
- (void) viewdidload { [super viewdidload]; // Do any additional setup after loading the view, typically From a nib. mylayout * layout = [[mylayout alloc] Init]; uicollectionview * collect = [[uicollectionview alloc]initwithframe:cgrectmake (0, 0, 320, 400) collectionViewLayout:layout]; collect.delegate=self; collect.dataSource=self; [collect registerclass:[uicollectionviewcell class] forcellwithreuseidentifier:@ "Cellid"] ; [self.view addsubview:collect];} -(Nsinteger) Numberofsectionsincollectionview: (uicollectionview *) collectionview{ return 1;} -(Nsinteger) CollectionView: (uicollectionview *) CollectIonview numberofitemsinsection: (Nsinteger) section{ return 10;} -(uicollectionviewcell *) CollectionView: (uicollectionview *) collectionview Cellforitematindexpath: (nsindexpath *) indexpath{ uicollectionviewcell * cell = [collectionview dequeuereusablecellwithreuseidentifier:@ "Cellid" forIndexPath : Indexpath]; cell.backgroundcolor = [uicolor colorwithred:arc4random ()% 255/255.0 green:arc4random ()%255/255.0 blue:arc4random ()%255/255.0 alpha:1]; uilabel * label = [[uilabel alloc]initwithframe:cgrectmake (0, 0, 250,  80)]; label.text = [nsstring stringwithformat:@ "I am the first line of%ld", (long) Indexpath.row]; [cell.contentview addsubview:label]; return cell;}
I created 10 item above and added a label on each item to mark the first few lines.
In our custom layout class, rewrite Layoutattributesforelementsinrect, where we return the array of layouts:
-(nsarray<uicollectionviewlayoutattributes *> *) Layoutattributesforelementsinrect: (CGRect) rect{ Nsmutablearray * attributes = [[Nsmutablearray alloc]init]; Traversal sets the layout properties for each item for (int i=0; I<[self.collectionview numberofitemsinsection:0]; i++) {[Attributes Addobjec T:[self Layoutattributesforitematindexpath:[nsindexpath indexpathforitem:i insection:0]]; } return attributes;}
After that, override the Layoutattributesforitematindexpath method in our layout class:
-(Uicollectionviewlayoutattributes *) Layoutattributesforitematindexpath: (Nsindexpath *) indexPath{//Create an item Layout property class Uicollectionviewlayoutattributes * Atti = [Uicollectionviewlayoutattributes layoutattributesforcellwithindexpath: Indexpath]; Gets the number of item int itemcounts = (int) [Self.collectionview numberofitemsinsection:0]; Set the size of each item to 260*100 atti.size = Cgsizemake (260, 100); /* Add the code that is described here */return Atti;}
In the above code, we have nothing to do, below we step by step to achieve the 3D roller effect.
First, we set all the item's locations to the center of CollectionView:
Atti.center = Cgpointmake (SELF.COLLECTIONVIEW.FRAME.SIZE.WIDTH/2, SELF.COLLECTIONVIEW.FRAME.SIZE.HEIGHT/2);
At this point, if we run the program, all item will be posted to the center of the screen, as follows:
It's ugly, right, then let's set the 3D effect for each item and add the following code to the layout method above:
//Create a Transform3D class //catransform3d is a matrix-like struct //catransform3didentity Creating an empty matrix CATransform3D trans3D = catransform3didentity; //This value sets the perspective, which affects the distance of the visual from the projection plane trans3d.m34 = -1/900.0; //These properties The following details //this is the radius of the 3D wheel &NBSP;&NBSP;&NBSP;CGFLOAT&NBSP;RADIUS&NBSP;=&NBSP;50/TANF (M_PI*2/ITEMCOUNTS/2); // Calculate the angle CGFloat angle = (float) (indexpath.row) that each item should rotate/itemcounts*m_pi*2 //This method returns a new Catransform3d object with the rotation effect appended to the original //the first parameter is a rotational radian, The following three correspond to the x, Y, z axes, which we need to rotate trans3d = catransform3drotate (Trans3d, angle, 1.0, 0, 0); //settings atti.transform3D = Trans3D;
For the RADIUS attribute above, some simple knowledge of geometry and trigonometric functions is used. If we turn the system's Pickerview along the Y axis 90 °, you will find that the side of it is a regular regular polygon, where the radius is the center of the polygon to its edge of the vertical distance, is also the radius of the inscribed circle, all the item is spelled into a regular polygon, the example is as follows:
With a simple mathematical knowledge, the angle of the H/2 chord corresponds to the radian of 2*pi/(number of sides)/2, the tangent of this angle is H/2/radius, which is the origin of our radius, according to the relevant knowledge of trigonometric functions.
For the Angle property, it is the x-axis rotation of each item in degrees, and if we put all of the item's centers at a point, rotate them to scatter as shown:
The radian of each item rotation is its index/(2*PI).
With the above settings, we run the code again, with the following effect:
Careful observation we can find that the item in the X axis of the rotation of the average layout, the side effect is our above the simple strokes, the following to carry out our third step, the item, all along its z-axis pull forward, you can become the effect of our scroll wheel, the example diagram is as follows:
We continue to add this line of code after the code we just made:
This method also returns a Transform3D object, with the addition of a translation effect, followed by three parameters, corresponding to the x, Y, Z axis of the translation, we translate trans3d = catransform3dtranslate (trans3d, 0, 0, radius) along the z axis;
Run again with the following effect:
The effect of the layout we have finished, very close to success, right, but now the layout is static, we can not slide this wheel, we also need to use dynamic sliding to do some processing.
Three, let the roller skating move Up
with the effort above, we have statically laid out a scroll wheel similar to Pickerview, and now let's add the effect of sliding scrolling.
First, we need to give CollectionView a sliding range, we use the sliding distance of a screen collectionview as a reference to scroll the wheel, we return the sliding area in the layout class as follows:
-(cgsize) collectionviewcontentsize{return Cgsizemake (Self.collectionView.frame.size.width, Self.collectionview.frame.size.height*[self.collectionview numberofitemsinsection:0]);}
At this point our CollectionView has been able to slide, but not the effect we want, the wheel does not scroll, but with the slide out of the screen, so we need to slide when the dynamic layout, the wheel is always fixed in the center of CollectionView, First you need to implement the following methods in the layout class:
Returns Yes, the layout is refreshed when a change is changed-(BOOL) Shouldinvalidatelayoutforboundschange: (cgrect) newbounds{return YES; }
Add a dynamic offset to the center point setting of the above layout:
Atti.center = Cgpointmake (SELF.COLLECTIONVIEW.FRAME.SIZE.WIDTH/2, self.collectionview.frame.size.height/2+ SELF.COLLECTIONVIEW.CONTENTOFFSET.Y);
Now running, you will find that the scroll wheel will always be fixed in the middle with the slide, but still unsatisfactory, the wheel does not turn up, we also need to dynamically set the rotation angle of each item, so that the continuous look, the wheel is spinning, in the method of setting layout above, we add some processing:
Gets the current offset of float offset = self.collectionview.contentoffset.y; On the angle setting, add an offset angle of float angleoffset = offset/self.collectionview.frame.size.height; CGFloat angle = (float) (indexpath.row+angleoffset)/itemcounts*m_pi*2;
Then look at the effect, yes, it is so simple, the wheel has been turned up.
Iv. the logic to let it cycle through
We further, if scrolling can be looped, this control will be even more cool, adding such logic is also very simple, by monitoring the ScrollView offset, we can align to deal with, because CollectionView inherits from ScrollView, We can implement its proxy method directly in Viewcontroller, as follows:
-(void) Scrollviewdidscroll: (Uiscrollview *) scrollview{//Small Yu Shan is placed to the last screen most screen if (scrollview.contentoffset.y<200) { Scrollview.contentoffset = Cgpointmake (0, scrollview.contentoffset.y+10*400); More than the last screen more than one screen put back to the first screen}else if (scrollview.contentoffset.y>11*400) {scrollview.contentoffset = Cgpointmake (0, Scro LLVIEW.CONTENTOFFSET.Y-10*400); }}
Because of our ring layout, the above logic can be seamlessly docked, but there will be new problems, first run, the scroll wheel is in the last item location, not the first one, and some related places, we also need some adaptation:
In the Viewcontroller:
Initially set the offset of the CollectionView to 1 screen offset collect.contentoffset = cgpointmake (0, 400);
In the layout class:
Set scroll range to (item total +2) * per screen height-(cgsize) collectionviewcontentsize{return Cgsizemake ( Self.collectionView.frame.size.width, self.collectionview.frame.size.height* ([Self.collectionview numberofitemsinsection:0]+2));}
The concrete item angle to be calculated forwards a cgfloat angle = (float) (indexpath.row+angleoffset-1)/itemcounts*m_pi*2;
OK, we are finally done, we can find that the implementation of such a cool layout effect of the control, the code is actually not much, compared to the mathematical logic is more difficult than the code itself, which is very similar to the geometric problem in mathematics, if you understand the logic, the solution is divided into minutes, we can pass such a train of thought, Design more 3D or graphic layout of special effects, draw the rotation of the disc, book page, or even three-dimensional label cloud, Uicollectionview can be achieved, the code in this blog in the following connection, the omission of the place, welcome correction!
Http://pan.baidu.com/s/1jGCmbKM
iOS Flow Layout Uicollectionview Series six--apply layouts from flat to space