First, the effect of the picture:
In the project before the use of Uicollectionview to achieve a circular distribution of the menu, but can not rotate with the gesture, just the two days of vacation, reference to some of the great God's article, to create a rotating menu. Let's say the code implementation.
1. Since Uicollectionview is dependent on uicollectionviewflowlayout for layout, and Uicollectionviewflowlayout inherits from Uicollectionviewlayout, So if we want to personalize the layout, we can create a new uicollectionviewlayout subclass to personalize the layout.
#import <UIKit/UIKit.h>
@interface ymlrotationlayout:uicollectionviewlayout
/** button radius * *
Property (Assign, nonatomic) cgfloat Itemradius;
/** Button Center relative to the center of the menu rotation angle * * * *
@property (assign, nonatomic) cgfloat RotationAngle;
@end
#import "YMLRotationLayout.h" @implementation ymlrotationlayout{nsmutablearray * _attributeattay;
CGFloat _rlength;
Nsinteger _itemcount;
}-(void) preparelayout{[Super Preparelayout];
Number of buttons _itemcount = (int) [Self.collectionview numberofitemsinsection:0];
_attributeattay = [[Nsmutablearray alloc] init]; First set the radius of the great circle and the shortest cgfloat radius = MIN (self.collectionView.frame.size.width, Self.collectionView.frame.size.height)
/2.2; Center position Cgpoint Center = cgpointmake (self.collectionview.frame.size.width/2.0, Self.collectionView.frame.size.height
/2.0);
_rlength = _itemradius; Sets the size for each item for (int idx = 0; idx < _itemcount idx + +) {Nsindexpath *indexpath = [Nsindexpath
Indexpathforitem:idx insection:0]; Uicollectionviewlayoutattributes * Attris = [Uicollectionviewlayoutattributes layoutattributesforcellwithindexpath:
Indexpath]; Set Item size attris.size = CgsizEmake (_rlength, _rlength);
if (_itemcount = = 1) {attris.center = Self.collectionView.center;
else {//Calculate the center position of each item/*. .
. . . R.
. ...///calculate the coordinates of each item center//Figure out the X,y value and subtract the size of the item itself float x = center.
x + COSF (2 * m_pi/_itemcount * idx + _rotationangle) * (RADIUS-_rlength/2.0);
Float y = center.y + sinf (2 * m_pi/_itemcount * idx + _rotationangle) * (RADIUS-_rlength/2.0);
Attris.center = Cgpointmake (x, y);
} [_attributeattay Addobject:attris];
}//Contentsize size-(cgsize) collectionviewcontentsize{return self.collectionView.frame.size;} Cell/header/footer array of frame-(nsarray<uicollectionviewlayoutattributes *> *) Layoutattributesforelementsinrect: (cgrect) rect{return _attributeaTtay; } @end
2. The overload Uicollectionview event method is required because of the need to listen for sliding gestures to adjust the layout
-(void) Touchesbegan: (Nsset<uitouch *> *) touches withevent: (uievent *) event{cgpoint = CenterPoint
ter
Uitouch *touch = Touches.anyobject;
Cgpoint point = [Touch locationinview:self]; CGFloat rlength = sqrt ((point.x-centerpoint.x) * (point.x-centerpoint.x) + (POINT.Y-CENTERPOINT.Y) * (point.y-cent
ERPOINT.Y)); Gesture Range limits if (!) (
Rlength <= [Self.largeradius floatvalue] && rlength >= [Self.smallradius Floatvalue])) {return; [[Nsnotificationcenter Defaultcenter] postnotificationname:@ "Touchbegin" Object:nil userInfo:@{@ "x": [NSString
stringwithformat:@ "%f", point.x],@ "y": [NSString stringwithformat:@ "%f", Point.y]}]; }-(void) touchesmoved: (Nsset<uitouch *> *) touches withevent: (uievent *) event{cgpoint = self.
Center
Uitouch *touch = Touches.anyobject;
Cgpoint point = [Touch locationinview:self]; CGFloat rlength = sqrt ((point.x-centerpoint.x) * (poinT.x-centerpoint.x) + (POINT.Y-CENTERPOINT.Y) * (POINT.Y-CENTERPOINT.Y)); Gesture Range limits if (!) (
Rlength <= [Self.largeradius floatvalue] && rlength >= [Self.smallradius Floatvalue])) {return; [[Nsnotificationcenter Defaultcenter] postnotificationname:@ "touchmoving" Object:nil userInfo:@{@ "x": [NSStrin
G stringwithformat:@ "%f", point.x],@ "y": [NSString stringwithformat:@ "%f", Point.y]}]; }
3. After the completion of the two steps, and then based on the position of the movement before and after the slide, calculate the sliding angle, recalculate the coordinates of each item, and then rearrange
#pragma mark--button sliding, touchbegin//sliding Start-(void): (nsnotification *) sender{if (!_rotate) return;
_centerpoint = Self.collectionView.center;
Nsdictionary *dic = Sender.userinfo;
Cgpoint point = Cgpointmake ([dic[@ "X"] floatvalue], [dic[@ "Y"] floatvalue]);
_lastpoint = point;
}//Is slipping-(void) touchmoving: (nsnotification *) sender{if (!_rotate) return;
Nsdictionary *dic = Sender.userinfo;
Cgpoint point = Cgpointmake ([dic[@ "X"] floatvalue], [dic[@ "Y"] floatvalue]); Calculates the sliding angle centered on CollectionView Center cgfloat rads = [self anglebetweenfirstlinestart:_centerpoint firstlineend:_lastpoin
T Andsecondlinestart:_centerpoint Secondlineend:point]; if (_lastpoint.x!= _centerpoint.x && point.x!= _centerpoint.x) {cgfloat K1 = (_lastpoint.y-_
CENTERPOINT.Y)/(_lastpoint.x-_centerpoint.x);
CGFloat K2 = (Point.y-_centerpoint.y)/(Point.x-_centerpoint.x); if (K2 > K1) {_totalrads += Rads;
else {_totalrads-= rads;
} _layout.rotationangle = _totalrads;
Re-layout [_layout invalidatelayout];
Update record points _lastpoint = point; The angle between the//two lines-(cgfloat) Anglebetweenfirstlinestart: (cgpoint) Firstlinestart firstlineend: (cgpoint) Firstlineend Andsecondlinestart: (cgpoint) Secondlinestart secondlineend: (cgpoint) secondlineend{cgfloat a1 = Firstlineend.x-f
Irstlinestart.x;
CGFloat B1 = Firstlineend.y-firstlinestart.y;
CGFloat A2 = Secondlineend.x-secondlinestart.x;
CGFloat b2 = Secondlineend.y-secondlinestart.y;
Angle cosine Double cos = (A1 * A2 + B1 * b2)/(sqrt (POW (A1, 2) + POW (B1, 2)) * sqrt (POW (A2, 2) + POW (B2, 2)); Floating-point calculations may exceed 1, need to control cos = cos > 1?
1:cos;
return acos (COS); }
Demo Address: Https://github.com/HuberyYang/YMLMenuDemo.git
New address: iOS using Uicollectionview to implement a rotatable menu