| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 |
- //
- // IGLDropDownMenu.m
- // IGLDropDownMenuDemo
- //
- // Created by Galvin Li on 8/30/14.
- // Copyright (c) 2014 Galvin Li. All rights reserved.
- //
- #import "IGLDropDownMenu.h"
- #ifdef NSFoundationVersionNumber_iOS_6_1
- #define IOS7_OR_GREATER (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1)
- #else
- #define IOS7_OR_GREATER NO
- #endif
- @interface IGLDropDownMenu ()
- @property (nonatomic, strong) IGLDropDownItem *menuButton;
- @property (nonatomic, assign) CGFloat offsetX;
- @property (nonatomic, assign) NSInteger selectedIndex;
- @property (nonatomic, assign) CGRect oldFrame;
- @property (nonatomic, assign) CGRect originalFrame;
- @property (nonatomic, copy) void (^selectedItemChangeBlock)(NSInteger selectedIndex);
- @end
- @implementation IGLDropDownMenu
- - (instancetype)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- [self commonInit];
- }
- return self;
- }
- - (instancetype)initWithCoder:(NSCoder *)aDecoder
- {
- self = [super initWithCoder:aDecoder];
- if (self) {
- [self commonInit];
- }
- return self;
- }
- - (void)commonInit
- {
- self.originalFrame = self.frame;
- [self resetParams];
- self.menuButton = [[IGLDropDownItem alloc] init];
- }
- - (void)setFrame:(CGRect)frame
- {
- super.frame = frame;
- self.originalFrame = frame;
- }
- - (void)setExpanding:(BOOL)expanding
- {
- _expanding = expanding;
-
- [self updateView];
- }
- - (void)setDropDownItems:(NSArray *)dropDownItems
- {
- _dropDownItems = [[NSArray alloc] initWithArray:dropDownItems copyItems:YES];
- }
- - (CGFloat)alphaOnFold
- {
- if (_alphaOnFold != -1) {
- return _alphaOnFold;
- }
- if ([self isSlidingInType]) {
- return 0.0;
- }
- return 1.0;
- }
- - (void)selectItemAtIndex:(NSUInteger)index
- {
- if (index < self.dropDownItems.count) {
- [self selectChangeToItem:self.dropDownItems[index]];
- }
- }
- - (void)resetParams
- {
- super.frame = self.oldFrame;
- self.offsetX = 0;
-
- self.animationDuration = 0.3;
- self.animationOption = UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState;
- self.itemAnimationDelay = 0.0;
- self.direction = IGLDropDownMenuDirectionDown;
- self.rotate = IGLDropDownMenuRotateNone;
- self.type = IGLDropDownMenuTypeNormal;
- self.slidingInOffset = -1;
- self.gutterY = 0;
- self.alphaOnFold = -1;
- self.flipWhenToggleView = NO;
- _expanding = NO;
- self.useSpringAnimation = YES;
-
- self.selectedIndex = -1;
- }
- - (void)reloadView
- {
- if (self.isExpanding) {
- super.frame = self.oldFrame;
- } else {
- self.oldFrame = self.frame;
- }
- self.itemSize = self.frame.size;
- // clear all subviews
- for (UIView *view in [self subviews]) {
- [view removeFromSuperview];
- }
-
- if (self.rotate == IGLDropDownMenuRotateLeft) {
- self.offsetX = self.dropDownItems.count * self.dropDownItems.count * self.itemSize.height / 28;
- }
-
- [super setFrame:CGRectMake(self.originalFrame.origin.x - self.offsetX, self.originalFrame.origin.y, self.frame.size.width + self.gutterY, self.frame.size.height)];
-
- self.menuButton.iconImage = self.menuIconImage;
- self.menuButton.text = self.menuText;
- self.menuButton.paddingLeft = self.paddingLeft;
- [self.menuButton setFrame:CGRectMake(self.offsetX + 0, 0, self.itemSize.width, self.itemSize.height)];
- switch (self.direction) {
- case IGLDropDownMenuDirectionDown:
- self.menuButton.layer.anchorPoint = CGPointMake(0.5, 0);
- break;
- case IGLDropDownMenuDirectionUp:
- self.menuButton.layer.anchorPoint = CGPointMake(0.5, 1);
- break;
- default:
- break;
- }
- [self.menuButton addTarget:self action:@selector(toggleView) forControlEvents:UIControlEventTouchUpInside];
- [self addSubview:self.menuButton];
-
- for (int i = (int)self.dropDownItems.count - 1; i >= 0; i--) {
- IGLDropDownItem *item = self.dropDownItems[i];
- item.index = i;
- item.paddingLeft = self.paddingLeft;
- [item addTarget:self action:@selector(itemClicked:) forControlEvents:UIControlEventTouchUpInside];
- [self setUpFoldItem:item];
- [self insertSubview:item belowSubview:self.menuButton];
- }
-
- [self updateSelfFrame];
-
- }
- - (BOOL)isSlidingInType
- {
- switch (self.type) {
- case IGLDropDownMenuTypeNormal:
- case IGLDropDownMenuTypeStack:
- return NO;
- case IGLDropDownMenuTypeSlidingInBoth:
- case IGLDropDownMenuTypeSlidingInFromLeft:
- case IGLDropDownMenuTypeSlidingInFromRight:
- return YES;
- default:
- return NO;
- }
- }
- - (void)updateSelfFrame
- {
- CGFloat buttonHeight = CGRectGetHeight(self.menuButton.frame);
-
- CGFloat x = self.frame.origin.x;
- CGFloat y = self.originalFrame.origin.y;
- CGFloat height = buttonHeight;
- CGFloat width = CGRectGetWidth(self.menuButton.frame);
- if (self.isExpanding) {
- for (IGLDropDownItem *item in self.dropDownItems) {
- if (item.alpha > 0) {
- width = MAX(width, CGRectGetMaxX(item.frame));
- switch (self.direction) {
- case IGLDropDownMenuDirectionDown:
- height = MAX(height, CGRectGetMaxY(item.frame));
- break;
- case IGLDropDownMenuDirectionUp:
- height = MAX(height, -CGRectGetMinY(item.frame));
- break;
- default:
- break;
- }
-
- }
- }
- }
-
- [self.menuButton setFrame:CGRectMake(self.offsetX + 0, 0, self.itemSize.width, self.itemSize.height)];
- if (self.direction == IGLDropDownMenuDirectionUp) {
- if (self.isExpanding) {
- height += buttonHeight;
- }
- y -= height - buttonHeight;
- [self.menuButton setFrame:CGRectMake(self.offsetX + 0, height - buttonHeight, self.itemSize.width, self.itemSize.height)];
-
- for (IGLDropDownItem *item in self.dropDownItems) {
- if (self.isExpanding) {
- item.center = CGPointMake(item.center.x, height - buttonHeight + item.center.y);
- } else {
- item.center = CGPointMake(item.center.x, item.center.y - self.frame.size.height + buttonHeight);
- }
- }
-
- }
-
- [super setFrame:CGRectMake(x, y, width, height)];
- }
- - (void)toggleView
- {
- self.expanding = !self.isExpanding;
- }
- - (void)updateView
- {
- if (self.shouldFlipWhenToggleView) {
- [self flipMainButton];
- }
-
- if (self.isExpanding) {
- [self expandView];
- } else {
- [self foldView];
- }
-
- }
- - (void)expandView
- {
- // expand the view
-
- for (int i = (int)self.dropDownItems.count - 1; i >= 0; i--) {
- IGLDropDownItem *item = self.dropDownItems[i];
- CGFloat delay = 0;
- // item expand after the main button flip up
- if (self.shouldFlipWhenToggleView) {
- delay += 0.1;
- }
- if ([self isSlidingInType]) {
- // first item move first
- delay += self.itemAnimationDelay * i;
- } else {
- // last item move first
- delay += self.itemAnimationDelay * (self.dropDownItems.count - i - 1);
- }
-
- if (self.shouldUseSpringAnimation && IOS7_OR_GREATER) {
- #if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000)
- [UIView animateWithDuration:self.animationDuration * 2 delay:delay usingSpringWithDamping:0.5 initialSpringVelocity:2.0 options:self.animationOption animations:^{
- [self setUpExpandItem:item];
- } completion:^(BOOL finished) {
- if (i == 0) {
- [self updateSelfFrame];
- }
- }];
- #endif
- } else {
- [UIView animateWithDuration:self.animationDuration delay:delay options:self.animationOption animations:^{
- [self setUpExpandItem:item];
- } completion:^(BOOL finished) {
- if (i == 0) {
- [self updateSelfFrame];
- }
- }];
- }
-
-
- }
-
- }
- - (void)foldView
- {
- // fold the view
-
- for (int i = (int)self.dropDownItems.count - 1; i >= 0; i--) {
- IGLDropDownItem *item = self.dropDownItems[i];
- CGFloat delay = 0;
- // item fold after the main button flip up
- if (self.shouldFlipWhenToggleView) {
- delay += 0.1;
- }
- if ([self isSlidingInType]) {
- // last item move first
- delay += self.itemAnimationDelay * (self.dropDownItems.count - i - 1);
- } else {
- // first item move first
- delay += self.itemAnimationDelay * i;
- }
-
- if (self.shouldUseSpringAnimation && IOS7_OR_GREATER) {
- #if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000)
- [UIView animateWithDuration:self.animationDuration delay:delay usingSpringWithDamping:1.0 initialSpringVelocity:2.0 options:self.animationOption animations:^{
- [self setUpFoldItem:item];
- } completion:^(BOOL finished) {
- if (i == 0) {
- [self updateSelfFrame];
- }
- }];
- #endif
- } else {
- [UIView animateWithDuration:self.animationDuration delay:delay options:self.animationOption animations:^{
- [self setUpFoldItem:item];
- } completion:^(BOOL finished) {
- if (i == 0) {
- [self updateSelfFrame];
- }
- }];
- }
-
- }
- }
- - (void)setUpExpandItem:(IGLDropDownItem*)item
- {
- // set alpha for slidingIn
- item.alpha = 1.0;
-
- // set frame (MUST before rotation reset)
- [item setFrame:[self frameOnExpandForItemAtIndex:item.index]];
-
- // set rotate
- item.transform = [self transformOnExpandForItemAtIndex:item.index];
- }
- - (void)setUpFoldItem:(IGLDropDownItem*)item
- {
- // reset rotate
- item.transform = CGAffineTransformMakeRotation(0);
-
- // set frame (MUST after rotation reset)
- [item setFrame:[self frameOnFoldForItemAtIndex:item.index]];
-
- // set alpha for slidingIn
- item.alpha = self.alphaOnFold;
- }
- - (void)flipMainButton
- {
- CGFloat flipAxis = 1;
- if (self.direction == IGLDropDownMenuDirectionUp) {
- flipAxis = -1;
- }
-
- CABasicAnimation *topAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
- topAnimation.autoreverses = YES;
- topAnimation.duration = 0.2;
- topAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DPerspect(CATransform3DMakeRotation(M_PI_2/3*2, flipAxis, 0, 0), CGPointMake(0, 0), 400)];
- [self.menuButton.layer addAnimation:topAnimation forKey:nil];
- }
- - (CGRect)frameOnFoldForItemAtIndex:(NSInteger)index
- {
- CGFloat x = self.offsetX;
- CGFloat y = 0;
- CGFloat width = self.itemSize.width;
- CGFloat height = self.itemSize.height;
-
- NSInteger count = index >= 2 ? 2 : index;
- CGFloat slidingInOffect = self.slidingInOffset != -1 ? self.slidingInOffset : self.itemSize.width / 3;
-
- switch (self.type) {
- case IGLDropDownMenuTypeNormal:
- // just take the default value
- break;
- case IGLDropDownMenuTypeStack:
- x += count * 2;
- y = (count + 1) * 3;
- width -= count * 4;
- break;
- case IGLDropDownMenuTypeSlidingInBoth:
- if (index % 2 != 0) {
- slidingInOffect = -slidingInOffect;
- }
- x = slidingInOffect;
- y = (index + 1) * (height + self.gutterY);
- break;
- case IGLDropDownMenuTypeSlidingInFromLeft:
- x = -slidingInOffect;
- y = (index + 1) * (height + self.gutterY);
- break;
- case IGLDropDownMenuTypeSlidingInFromRight:
- x = slidingInOffect;
- y = (index + 1) * (height + self.gutterY);
- break;
- default:
- break;
- }
-
- if (self.direction == IGLDropDownMenuDirectionUp) {
- if (self.isExpanding) {
- y = -y;
- } else {
- CGFloat buttonHeight = CGRectGetHeight(self.menuButton.frame);
- y = self.frame.size.height - buttonHeight - y;
- NSLog(@"bHeight: %f, height: %f", buttonHeight, self.frame.size.height);
- }
-
- }
-
- return CGRectMake(x, y, width, height);
- }
- - (CGRect)frameOnExpandForItemAtIndex:(NSInteger)index
- {
- CGFloat x = 0;
- CGFloat y = (index + 1) * (self.itemSize.height + self.gutterY);
- CGFloat width = self.itemSize.width;
- CGFloat height = self.itemSize.height;
-
- switch (self.rotate) {
- case IGLDropDownMenuRotateNone:
- // just take the default value
- break;
- case IGLDropDownMenuRotateLeft:
- x = self.offsetX + -index * index * self.itemSize.height / 20.0;
- break;
- case IGLDropDownMenuRotateRight:
- x = index * index * self.itemSize.height / 20.0;
- break;
- case IGLDropDownMenuRotateRandom:
- x = floor([self random0to1] * 11 - 5);
- break;
- default:
- break;
- }
-
- if (self.direction == IGLDropDownMenuDirectionUp) {
- y = -y;
- }
-
- return CGRectMake(x, y, width, height);
- }
- - (CGAffineTransform)transformOnExpandForItemAtIndex:(NSInteger)index
- {
- CGFloat angle = 0;
- switch (self.rotate) {
- case IGLDropDownMenuRotateNone:
- // just take the default value
- break;
- case IGLDropDownMenuRotateLeft:
- angle = 5.0 * index / 180.0 * M_PI;
- break;
- case IGLDropDownMenuRotateRight:
- angle = -5.0 * index / 180.0 * M_PI;
- break;
- case IGLDropDownMenuRotateRandom:
- angle = floor([self random0to1] * 11 - 5) / 180.0 * M_PI;
- break;
- default:
- break;
- }
- if (self.direction == IGLDropDownMenuDirectionUp) {
- angle = -angle;
- }
- return CGAffineTransformMakeRotation(angle);
- }
- - (void)addSelectedItemChangeBlock:(void (^)(NSInteger))block
- {
- self.selectedItemChangeBlock = block;
- }
- - (void)selectChangeToItem:(IGLDropDownItem*)item
- {
- self.menuButton.iconImage = item.iconImage;
- self.object = item.object;
- self.menuButton.text = item.text;
- self.expanding = NO;
- self.selectedIndex = item.index;
- if (self.selectedItemChangeBlock) {
- self.selectedItemChangeBlock(self.selectedIndex);
- }
- if ([self.delegate respondsToSelector:@selector(dropDownMenu:selectedItemAtIndex:)]) {
- [self.delegate dropDownMenu:self selectedItemAtIndex:self.selectedIndex];
- }
- }
- #pragma mark - button action
- - (void)itemClicked:(IGLDropDownItem*)sender
- {
- if (![sender.text isEqualToString:@"没有更多了"]) {
- if (self.isExpanding) {
- [self selectChangeToItem:sender];
- }
- }
-
- }
- #pragma mark -
- - (float)random0to1
- {
- return [self randomFloatBetween:0.0 andLargerFloat:1.0];
- }
- - (float)randomFloatBetween:(float)num1 andLargerFloat:(float)num2
- {
- int startVal = num1*10000;
- int endVal = num2*10000;
-
- int randomValue = startVal +(arc4random()%(endVal - startVal));
- float a = randomValue;
-
- return(a /10000.0);
- }
- CATransform3D CATransform3DMakePerspective(CGPoint center, float disZ)
- {
- CATransform3D transToCenter = CATransform3DMakeTranslation(-center.x, -center.y, 0);
- CATransform3D transBack = CATransform3DMakeTranslation(center.x, center.y, 0);
- CATransform3D scale = CATransform3DIdentity;
- scale.m34 = -1.0f/disZ;
- return CATransform3DConcat(CATransform3DConcat(transToCenter, scale), transBack);
- }
- CATransform3D CATransform3DPerspect(CATransform3D t, CGPoint center, float disZ)
- {
- return CATransform3DConcat(t, CATransform3DMakePerspective(center, disZ));
- }
- @end
|