iOS uses Uicollectionview to implement a rotatable menu

Source: Internet
Author: User
Tags cos pow uikit

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


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.