#import "TGMenuView.h" #import "LegacyComponentsInternal.h" #import "TGFont.h" #import "TGImageUtils.h" #import #pragma mark - static CGFloat diameter = 16.0f; static UIColor *highlightColor() { static UIColor *color = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ color = [UIColor colorWithWhite:1.0f alpha:0.25f]; }); return color; } static UIImage *menuBackgroundMask() { static UIImage *image = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ UIColor *color = [UIColor whiteColor]; UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, color.CGColor); CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter)); image = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:(NSInteger)(diameter / 2.0f) topCapHeight:(NSInteger)(diameter / 2.0f)]; UIGraphicsEndImageContext(); }); return image; } static UIImage *menuHighlightedBackground() { static UIImage *image = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ UIColor *color = highlightColor(); UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, color.CGColor); CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter)); image = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:(NSInteger)(diameter / 2.0f) topCapHeight:(NSInteger)(diameter / 2.0f)]; UIGraphicsEndImageContext(); }); return image; } static CGFloat pagerButtonWidth = 32.0f; static UIImage *pagerLeftButtonImage() { static UIImage *image = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ CGSize size = CGSizeMake(pagerButtonWidth, 36.0f); UIGraphicsBeginImageContextWithOptions(size, false, 0.0f); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); CGContextSaveGState(context); CGContextTranslateCTM(context, size.width / 2.0f, size.height / 2.0f); CGContextScaleCTM(context, -0.5f, 0.5f); CGContextTranslateCTM(context, -size.width / 2.0f + 8.0f, -size.height / 2.0f + 7.0f); TGDrawSvgPath(context, @"M0,0 L0,22 L18,11 L0,0 L0,0 Z "); CGContextSetFillColorWithColor(context, highlightColor().CGColor); CGContextRestoreGState(context); CGContextSetFillColorWithColor(context, highlightColor().CGColor); CGContextFillRect(context, CGRectMake(size.width - 1.0f, 0.0f, 1.0f, size.height)); image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); }); return image; } static UIImage *pagerLeftButtonHighlightedImage() { static UIImage *image = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ CGSize size = CGSizeMake(pagerButtonWidth, 36.0f); UIGraphicsBeginImageContextWithOptions(size, false, 0.0f); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, highlightColor().CGColor); [menuHighlightedBackground() drawInRect:CGRectMake(0.0f, 0.0f, size.width * 2.0f, size.height)]; CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); CGContextSaveGState(context); CGContextTranslateCTM(context, size.width / 2.0f, size.height / 2.0f); CGContextScaleCTM(context, -0.5f, 0.5f); CGContextTranslateCTM(context, -size.width / 2.0f + 8.0f, -size.height / 2.0f + 7.0f); TGDrawSvgPath(context, @"M0,0 L0,22 L18,11 L0,0 L0,0 Z "); CGContextSetFillColorWithColor(context, highlightColor().CGColor); CGContextRestoreGState(context); image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); }); return image; } @protocol TGMenuButtonViewDelegate - (void)menuButtonHighlighted; @end @interface TGMenuButtonView () { UIView *_highlightedView; } @property (nonatomic) bool highlightDisabled; @property (nonatomic) bool isOptional; @property (nonatomic) bool isTrailing; @property (nonatomic, weak) id delegate; @property (nonatomic) bool isMultiline; @property (nonatomic) CGFloat maxWidth; @end @implementation TGMenuButtonView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self != nil) { _highlightedView = [[UIView alloc] init]; _highlightedView.backgroundColor = highlightColor(); [self addSubview:_highlightedView]; _highlightedView.hidden = true; } return self; } - (void)setHighlighted:(BOOL)highlighted { [super setHighlighted:highlighted]; bool selected = self.selected; __strong id delegate = _delegate; [delegate menuButtonHighlighted]; highlighted = highlighted || selected; _highlightedView.hidden = !(highlighted || selected) || _highlightDisabled; } - (void)setSelected:(BOOL)selected { [super setSelected:selected]; bool highlighted = self.highlighted; __strong id delegate = _delegate; [delegate menuButtonHighlighted]; selected = selected || highlighted; _highlightedView.hidden = !(highlighted || selected) || _highlightDisabled; } - (void)sizeToFit { NSString *title = [self attributedTitleForState:UIControlStateNormal].string; if (title.length == 0) title = [self titleForState:UIControlStateNormal]; if (title.length > 0) { if (self.isMultiline) { CGSize size = [title sizeWithFont:self.titleLabel.font constrainedToSize:CGSizeMake(self.maxWidth - 18.0f, FLT_MAX) lineBreakMode:NSLineBreakByWordWrapping]; self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, ceil(size.width) + 18, MAX(41.0f, ceil(size.height) + 20.0f)); } else { self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, [title sizeWithFont:self.titleLabel.font].width + 34, 41); } } else { self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.imageView.frame.size.width + 24.0f, 41); } } - (void)layoutSubviews { [super layoutSubviews]; _highlightedView.frame = CGRectMake(0.0f, -20.0f, self.frame.size.width, self.frame.size.height + 40.0f); } @end #pragma mark - @interface TGMenuView () { NSDictionary *_userInfo; UIScrollView *_buttonContainer; UIView *_buttonContainerContainer; UIButton *_leftPagerButton; UIButton *_rightPagerButton; UIImageView *_containerMaskView; } @property (nonatomic, strong) NSMutableArray *buttonViews; @property (nonatomic, strong) NSMutableArray *separatorViews; @property (nonatomic, strong) NSArray *buttonDescriptions; @property (nonatomic) CGFloat arrowLocation; @property (nonatomic) bool arrowOnTop; @property (nonatomic, strong) UIImageView *arrowTopView; @property (nonatomic, strong) UIImageView *arrowBottomView; @property (nonatomic, strong) ASHandle *watcherHandle; @end @implementation TGMenuView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.alpha = 0.0f; self.layer.anchorPoint = CGPointMake(0.5f, 1.0f); self.transform = CGAffineTransformMakeScale(0.1f, 0.1f); _maxWidth = 310.0f; _arrowTopView = [[UIImageView alloc] init]; _arrowTopView.frame = CGRectMake(0.0f, 0.0f, 20.0f, 12.0f); [self addSubview:_arrowTopView]; _arrowBottomView = [[UIImageView alloc] init]; _arrowBottomView.frame = CGRectMake(0.0f, 0.0f, 20.0f, 14.5f); [self addSubview:_arrowBottomView]; _buttonContainerContainer = [[UIView alloc] init]; if (iosMajorVersion() >= 8) { UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]]; effectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; effectView.frame = CGRectMake(0.0f, -20.0f, 0.0f, 40.0f); [_buttonContainerContainer addSubview:effectView]; } UIView *effectView = [[UIView alloc] init]; effectView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:iosMajorVersion() >= 8 ? 0.8f : 0.9f]; effectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; effectView.frame = CGRectMake(0.0f, -20.0f, 0.0f, 40.0f); [_buttonContainerContainer addSubview:effectView]; [self addSubview:_buttonContainerContainer]; _buttonContainer = [[UIScrollView alloc] init]; _buttonContainer.clipsToBounds = true; _buttonContainer.alwaysBounceHorizontal = false; _buttonContainer.alwaysBounceVertical = false; _buttonContainer.showsHorizontalScrollIndicator = false; _buttonContainer.showsVerticalScrollIndicator = false; _buttonContainer.pagingEnabled = true; _buttonContainer.delaysContentTouches = false; _buttonContainer.canCancelContentTouches = true; _buttonContainer.delegate = self; _buttonContainer.scrollEnabled = false; [_buttonContainerContainer addSubview:_buttonContainer]; _leftPagerButton = [[UIButton alloc] init]; [_leftPagerButton setBackgroundImage:pagerLeftButtonImage() forState:UIControlStateNormal]; [_leftPagerButton setBackgroundImage:pagerLeftButtonHighlightedImage() forState:UIControlStateHighlighted]; [_leftPagerButton addTarget:self action:@selector(pagerButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; _rightPagerButton = [[UIButton alloc] init]; [_rightPagerButton setBackgroundImage:pagerLeftButtonImage() forState:UIControlStateNormal]; [_rightPagerButton setBackgroundImage:pagerLeftButtonHighlightedImage() forState:UIControlStateHighlighted]; _rightPagerButton.transform = CGAffineTransformMakeScale(-1.0f, 1.0f); [_rightPagerButton addTarget:self action:@selector(pagerButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:_leftPagerButton]; [self addSubview:_rightPagerButton]; _buttonViews = [[NSMutableArray alloc] init]; _separatorViews = [[NSMutableArray alloc] init]; _arrowLocation = 50; } return self; } - (void)setButtonsAndActions:(NSArray *)buttonsAndActions watcherHandle:(ASHandle *)watcherHandle { _watcherHandle = watcherHandle; _buttonDescriptions = buttonsAndActions; int index = -1; for (NSDictionary *dict in buttonsAndActions) { index++; NSString *title = nil; NSAttributedString *attributedTitle = nil; id titleValue = [dict objectForKey:@"title"]; if ([titleValue isKindOfClass:[NSString class]]) title = titleValue; else if ([titleValue isKindOfClass:[NSAttributedString class]]) attributedTitle = titleValue; id imageValue = [dict objectForKey:@"image"]; TGMenuButtonView *buttonView = nil; if (index < (int)_buttonViews.count) buttonView = [_buttonViews objectAtIndex:index]; else { buttonView = [[TGMenuButtonView alloc] init]; if (self.multiline) { buttonView.titleLabel.numberOfLines = 0; buttonView.isMultiline = true; buttonView.maxWidth = _maxWidth; } buttonView.delegate = self; [buttonView setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [buttonView setTitleColor:UIColorRGBA(0xffffff, 0.5f) forState:UIControlStateDisabled]; buttonView.titleLabel.font = TGSystemFontOfSize(14); [buttonView addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; [_buttonViews addObject:buttonView]; [_buttonContainer addSubview:buttonView]; } buttonView.isTrailing = [dict[@"trailing"] boolValue]; buttonView.isOptional = [dict[@"optional"] boolValue]; if (title) [buttonView setTitle:title forState:UIControlStateNormal]; else if (attributedTitle) [buttonView setAttributedTitle:attributedTitle forState:UIControlStateNormal]; if ([imageValue isKindOfClass:[UIImage class]]) { [buttonView setImage:imageValue forState:UIControlStateNormal]; //buttonView.imageEdgeInsets = UIEdgeInsetsMake(0.0f, 10.0f, 0.0f, 10.0f); } buttonView.selected = false; } while ((int)_buttonViews.count > index + 1) { TGMenuButtonView *buttonView = [_buttonViews lastObject]; buttonView.delegate = nil; [buttonView removeFromSuperview]; [_buttonViews removeLastObject]; } if (_buttonViews.count != 0) { while (_separatorViews.count < _buttonViews.count - 1) { UIView *separatorView = [[UIImageView alloc] init]; separatorView.backgroundColor = highlightColor(); [_buttonContainer addSubview:separatorView]; [_separatorViews addObject:separatorView]; } } if (_buttonViews.count != 0) { while (_separatorViews.count > _buttonViews.count - 1) { UIImageView *separatorView = [_separatorViews lastObject]; [separatorView removeFromSuperview]; [_separatorViews removeLastObject]; } } index = -1; for (TGMenuButtonView *buttonView in _buttonViews) { index++; [buttonView sizeToFit]; if (index == 0 || index == (int)_buttonViews.count - 1) { CGRect buttonFrame = buttonView.frame; buttonFrame.size.width += 1; buttonView.frame = buttonFrame; } } [self updateBackgrounds]; [self setNeedsLayout]; } - (void)setButtonHighlightDisabled:(bool)buttonHighlightDisabled { _buttonHighlightDisabled = buttonHighlightDisabled; for (TGMenuButtonView *view in _buttonViews) view.highlightDisabled = buttonHighlightDisabled; } - (void)menuButtonHighlighted { if (self.buttonHighlightDisabled) return; NSInteger highlightedIndex = -1; bool arrowHighlighted = false; NSInteger index = -1; for (TGMenuButtonView *buttonView in _buttonViews) { index++; bool containsArrow = _arrowLocation >= buttonView.frame.origin.x && _arrowLocation < buttonView.frame.origin.x + buttonView.frame.size.width; if (index == 0) { if (_arrowLocation < buttonView.frame.size.width) containsArrow = true; } if (index == (NSInteger)_buttonViews.count - 1) { if (_arrowLocation >= buttonView.frame.origin.x) containsArrow = true; } if (buttonView.highlighted || buttonView.selected) { arrowHighlighted = containsArrow; highlightedIndex = index; break; } } } - (UIImage *)highlightMask { UIGraphicsBeginImageContextWithOptions(_buttonContainer.bounds.size, false, 0.0f); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); [menuBackgroundMask() drawInRect:CGRectMake(0.0f, 10.0f, _buttonContainer.bounds.size.width, _buttonContainer.bounds.size.height - 20.0f)]; if (!_arrowBottomView.hidden) { CGPoint arrow = [_arrowBottomView convertRect:_arrowBottomView.bounds toView:_buttonContainerContainer].origin; arrow.x += 1.0f; CGContextBeginPath(context); CGContextMoveToPoint(context, arrow.x, arrow.y); CGContextAddLineToPoint(context, arrow.x + 18.0f, arrow.y); CGContextAddLineToPoint(context, arrow.x + 18.0f / 2.0f, arrow.y + 10.0f); CGContextClosePath(context); CGContextFillPath(context); } else if (!_arrowTopView.hidden) { CGPoint arrow = [_arrowTopView convertRect:_arrowTopView.bounds toView:_buttonContainerContainer].origin; arrow.x += 1.0f; arrow.y += 1.0f; CGContextBeginPath(context); CGContextMoveToPoint(context, arrow.x, arrow.y + 10.0f); CGContextAddLineToPoint(context, arrow.x + 18.0f / 2.0f, arrow.y); CGContextAddLineToPoint(context, arrow.x + 18.0f, arrow.y + 10.0f); CGContextClosePath(context); CGContextFillPath(context); } UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } - (void)updateBackgrounds { NSInteger index = -1; for (TGMenuButtonView *buttonView in _buttonViews) { index++; UIEdgeInsets titleInset = UIEdgeInsetsMake(0, 0, 1, 0); if (index == 0) { //titleInset.left += 2; } if (index == (NSInteger)_buttonViews.count - 1) { //titleInset.right += 2; } if (_multiline) { titleInset.left = 9.0f; titleInset.right = 9.0f; } buttonView.titleEdgeInsets = titleInset; } } - (void)sizeToFitToWidth:(CGFloat)maxWidth { _maxWidth = maxWidth - 20.0f; [self sizeToFit]; } - (void)sizeToFit { CGAffineTransform transform = self.transform; self.transform = CGAffineTransformIdentity; CGFloat maxWidth = _maxWidth; CGFloat buttonHeight = 41.0f; NSMutableArray *pages = [[NSMutableArray alloc] init]; NSMutableArray *currentPageButtons = [[NSMutableArray alloc] init]; CGFloat currentPageWidth = 0.0f; NSMutableArray *optionalButtons = [[NSMutableArray alloc] init]; for (TGMenuButtonView *buttonView in _buttonViews) { if (buttonView.isOptional) { buttonView.hidden = true; [optionalButtons addObject:buttonView]; } else { CGFloat buttonWidth = buttonView.frame.size.width; bool added = false; if (currentPageWidth + buttonWidth > maxWidth) { if (currentPageButtons.count == 0) { [currentPageButtons addObject:buttonView]; added = true; } [pages addObject:currentPageButtons]; currentPageButtons = [[NSMutableArray alloc] init]; currentPageWidth = 0.0f; } if (!added) { currentPageWidth += buttonWidth; [currentPageButtons addObject:buttonView]; } } } if (currentPageButtons.count != 0) { if (currentPageButtons.count == 1) { for (TGMenuButtonView *buttonView in optionalButtons) { CGFloat buttonWidth = buttonView.frame.size.width; if (currentPageWidth + buttonWidth > maxWidth) { break; } buttonView.hidden = false; currentPageWidth += buttonWidth; [currentPageButtons addObject:buttonView]; } } [pages addObject:currentPageButtons]; } for (NSMutableArray *page in pages) { NSUInteger index = 0; for (TGMenuButtonView *button in page) { if (button.isTrailing) { if (index + 1 != page.count) { [page removeObjectAtIndex:index]; [page addObject:button]; } break; } index++; } } CGFloat maxPageWidth = 0.0f; NSInteger pageIndex = -1; for (NSArray *buttons in pages) { CGFloat sumWidth = 0.0f; NSInteger buttonIndex = -1; for (UIView *button in buttons) { [button sizeToFit]; buttonIndex++; if (buttonIndex != 0) { sumWidth += 1.0f; } sumWidth += button.frame.size.width; if (_multiline) { buttonHeight = MAX(buttonHeight, button.frame.size.height); } } if (pages.count > 1) { if (pageIndex == 0) { sumWidth += pagerButtonWidth; } else if (pageIndex == (NSInteger)pages.count - 1) { sumWidth += pagerButtonWidth; } else { sumWidth += pagerButtonWidth * 2.0f; } } maxPageWidth = MAX(maxPageWidth, MIN(maxWidth, sumWidth)); } NSInteger nextSeparatorIndex = 0; CGFloat diff = buttonHeight - 41.0f; CGFloat currentPageStart = 0.0f; pageIndex = -1; for (NSArray *buttons in pages) { pageIndex++; CGFloat sumWidth = 0.0f; NSInteger buttonIndex = -1; for (UIView *button in buttons) { buttonIndex++; if (buttonIndex != 0) { sumWidth += 1.0f; } sumWidth += button.frame.size.width; } CGFloat leftOffset = 0.0f; CGFloat pageContentWidth = maxPageWidth; if (pages.count > 1) { if (pageIndex == 0) { pageContentWidth -= pagerButtonWidth; } else if (pageIndex == (NSInteger)pages.count - 1) { leftOffset = pagerButtonWidth; pageContentWidth -= pagerButtonWidth; } else { leftOffset = pagerButtonWidth; pageContentWidth -= pagerButtonWidth * 2.0f; } } CGFloat factor = pageContentWidth / sumWidth; CGFloat buttonStart = currentPageStart + leftOffset; buttonIndex = -1; for (UIView *button in buttons) { buttonIndex++; if (buttonIndex != 0) { UIView *separatorView = _separatorViews[nextSeparatorIndex++]; separatorView.frame = CGRectMake(buttonStart, 0.0f, 1.0f, 36.0f + 20.0f); buttonStart += 1.0f; } CGFloat buttonWidth = CGFloor(button.frame.size.width * factor); if (buttonIndex == (NSInteger)buttons.count - 1) { buttonWidth = MAX(buttonWidth, currentPageStart + leftOffset + pageContentWidth - buttonStart); } button.frame = CGRectMake(buttonStart, -2.0f + 10.0f, buttonWidth, button.frame.size.height); buttonStart += buttonWidth; } currentPageStart += maxPageWidth; } _buttonContainerContainer.frame = CGRectMake(0.0f, 2.0f - 10.0f, maxPageWidth, 36.0f + 20.0f + diff); _buttonContainer.frame = _buttonContainerContainer.bounds; _buttonContainer.contentSize = CGSizeMake(maxPageWidth * pages.count, _buttonContainer.frame.size.height); _buttonContainer.contentOffset = CGPointZero; _leftPagerButton.frame = CGRectMake(0.0f, 2.0f, pagerButtonWidth, 36.0f); _rightPagerButton.frame = CGRectMake(maxPageWidth - pagerButtonWidth, 2.0f, pagerButtonWidth, 36.0f); //_backgroundView.frame = CGRectMake(0.0f, 2.0f, maxPageWidth, 36.0f); self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, maxPageWidth, buttonHeight); CGFloat minArrowX = 10.0f; CGFloat maxArrowX = self.frame.size.width - 10.0f; CGFloat arrowX = CGFloor(_arrowLocation - _arrowTopView.frame.size.width / 2); arrowX = MIN(MAX(minArrowX, arrowX), maxArrowX); _arrowTopView.frame = CGRectMake(arrowX, -9.0 + TGScreenPixel, _arrowTopView.frame.size.width, _arrowTopView.frame.size.height); _arrowBottomView.frame = CGRectMake(arrowX, 37.0f + diff, _arrowBottomView.frame.size.width, _arrowBottomView.frame.size.height); _arrowTopView.hidden = !_arrowOnTop; _arrowBottomView.hidden = _arrowOnTop; if (_containerMaskView == nil) { _containerMaskView = [[UIImageView alloc] init]; //[_buttonContainerContainer addSubview:_containerMaskView]; } _containerMaskView.image = [self highlightMask]; [_containerMaskView sizeToFit]; _buttonContainerContainer.layer.mask = _containerMaskView.layer; [self scrollViewDidScroll:_buttonContainer]; self.transform = transform; } - (void)showInView:(UIView *)view fromRect:(CGRect)rect { [self showInView:view fromRect:rect animated:true]; } - (void)showInView:(UIView *)view fromRect:(CGRect)rect animated:(bool)animated { CGAffineTransform transform = self.transform; self.transform = CGAffineTransformIdentity; CGRect frame = self.frame; frame.origin.x = CGFloor(rect.origin.x + rect.size.width / 2 - frame.size.width / 2); if (frame.origin.x < 4) frame.origin.x = 4; if (frame.origin.x + frame.size.width > view.frame.size.width - 4) frame.origin.x = view.frame.size.width - 4 - frame.size.width; frame.origin.y = rect.origin.y - frame.size.height - 14; if (self.forceArrowOnTop) { _arrowOnTop = true; } else { if (frame.origin.y < 2) { frame.origin.y = rect.origin.y + rect.size.height + 17; if (self.forceCenter || frame.origin.y + frame.size.height > view.frame.size.height - 14) { frame.origin.y = CGFloor((view.frame.size.height - frame.size.height) / 2); _arrowOnTop = false; } else { _arrowOnTop = true; } } else { _arrowOnTop = false; } } _arrowLocation = CGFloor(rect.origin.x + rect.size.width / 2) - frame.origin.x; self.layer.anchorPoint = CGPointMake(MAX(0.0f, MIN(1.0f, _arrowLocation / frame.size.width)), _arrowOnTop ? -0.2f : 1.2f); self.frame = frame; [self setNeedsLayout]; [self layoutIfNeeded]; [self sizeToFit]; self.transform = transform; self.layer.rasterizationScale = [[UIScreen mainScreen] scale]; self.layer.shouldRasterize = true; self.alpha = 1.0f; if (animated) { [UIView animateWithDuration:0.142 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState animations:^ { self.transform = CGAffineTransformMakeScale(1.07f, 1.07f); } completion:^(BOOL finished) { if (finished) { [UIView animateWithDuration:0.06 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState animations:^ { self.transform = CGAffineTransformIdentity; } completion:^(BOOL finished) { if (finished) { self.layer.shouldRasterize = false; } }]; } }]; } else { self.transform = CGAffineTransformIdentity; self.alpha = 0.0f; [UIView animateWithDuration:0.3 animations:^ { self.alpha = 1.0f; }]; } } - (void)hide:(dispatch_block_t)completion { [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^ { self.alpha = 0.0f; } completion:^(BOOL finished) { if (finished) { self.transform = CGAffineTransformMakeScale(0.1f, 0.1f); if (completion) completion(); } }]; } - (void)layoutSubviews { [super layoutSubviews]; /*_buttonContainer.frame = CGRectMake(0.0f, 2.0f, self.frame.size.width, self.frame.size.height - 5.0f); float currentX = 0; NSInteger index = -1; for (TGMenuButtonView *buttonView in _buttonViews) { index++; buttonView.frame = CGRectMake(currentX, -2.0f, buttonView.frame.size.width, buttonView.frame.size.height); currentX += buttonView.frame.size.width; [buttonView layoutSubviews]; } index = -1; for (TGMenuButtonView *buttonView in _buttonViews) { index++; CGFloat linePosition = 0.0f; CGFloat lineWidth = buttonView.frame.size.width; if (index > 0) { UIImageView *separatorView = [_separatorViews objectAtIndex:index - 1]; separatorView.frame = CGRectMake(buttonView.frame.origin.x - 1, 0.0f, separatorView.image.size.width, 36.0f); } bool containsArrow = _arrowLocation >= buttonView.frame.origin.x && _arrowLocation < buttonView.frame.origin.x + buttonView.frame.size.width; if (index == 0) { linePosition += 10; lineWidth -= 10; if (_arrowLocation < buttonView.frame.size.width) containsArrow = true; } if (index == (NSInteger)_buttonViews.count - 1) { lineWidth -= 10; if (_arrowLocation >= buttonView.frame.origin.x) containsArrow = true; } }*/ } #pragma mark - - (void)buttonPressed:(TGMenuButtonView *)buttonView { NSInteger index = -1; for (TGMenuButtonView *listButtonView in _buttonViews) { index++; if (listButtonView == buttonView) { buttonView.selected = true; if (index < (NSInteger)_buttonDescriptions.count) { NSString *action = [[_buttonDescriptions objectAtIndex:index] objectForKey:@"action"]; NSMutableDictionary *options = [[NSMutableDictionary alloc] init]; options[@"action"] = action; if (_userInfo != nil) options[@"userInfo"] = _userInfo; [_watcherHandle requestAction:@"menuAction" options:options]; } if ([self.superview isKindOfClass:[TGMenuContainerView class]]) [(TGMenuContainerView *)self.superview hideMenu]; break; } } } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == _buttonContainer) { if (scrollView.contentSize.width > scrollView.bounds.size.width + FLT_EPSILON) { CGFloat leftDistance = scrollView.contentOffset.x; CGFloat rightDistance = scrollView.contentSize.width - (scrollView.contentOffset.x + scrollView.bounds.size.width); _leftPagerButton.alpha = MAX(0.0f, MIN(1.0f, leftDistance / _leftPagerButton.frame.size.width)); _rightPagerButton.alpha = MAX(0.0f, MIN(1.0f, rightDistance / _rightPagerButton.frame.size.width)); } else { _leftPagerButton.alpha = 0.0f; _rightPagerButton.alpha = 0.0f; } } } - (void)pagerButtonPressed:(UIView *)button { CGFloat targetOffset = _buttonContainer.contentOffset.x; if (button == _leftPagerButton) { NSInteger page = ((NSInteger)_buttonContainer.contentOffset.x) / ((NSInteger)_buttonContainer.bounds.size.width); if (page > 0) { targetOffset = (page - 1) * _buttonContainer.bounds.size.width; } } else if (button == _rightPagerButton) { NSInteger page = ((NSInteger)_buttonContainer.contentOffset.x) / ((NSInteger)_buttonContainer.bounds.size.width); if (page + 1 < (NSInteger)(_buttonContainer.contentSize.width / _buttonContainer.bounds.size.width)) { targetOffset = (page + 1) * _buttonContainer.bounds.size.width; } } if (ABS(targetOffset - _buttonContainer.contentOffset.x) > FLT_EPSILON) { if (iosMajorVersion() >= 7) { [UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:0.8f initialSpringVelocity:0.0f options:0 animations:^{ _buttonContainer.contentOffset = CGPointMake(targetOffset, 0.0f); } completion:nil]; } else { [UIView animateWithDuration:0.2 animations:^{ _buttonContainer.contentOffset = CGPointMake(targetOffset, 0.0f); }]; } } } @end #pragma mark - @interface TGMenuContainerView () @end @implementation TGMenuContainerView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self != nil) { _menuView = [[TGMenuView alloc] init]; [self addSubview:_menuView]; } return self; } - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *result = [super hitTest:point withEvent:event]; if (result == self || result == nil) { [self hideMenu]; return nil; } return result; } - (void)showMenuFromRect:(CGRect)rect { [self showMenuFromRect:rect animated:true]; } - (void)showMenuFromRect:(CGRect)rect animated:(bool)animated { _isShowingMenu = true; _showingMenuFromRect = rect; [_menuView showInView:self fromRect:rect animated:animated]; } - (void)setFrame:(CGRect)frame { if (!CGSizeEqualToSize(frame.size, self.frame.size)) [self hideMenu]; [super setFrame:frame]; } - (void)hideMenu { if (_isShowingMenu) { _isShowingMenu = false; _showingMenuFromRect = CGRectZero; [_menuView.watcherHandle requestAction:@"menuWillHide" options:nil]; [_menuView hide:^ { [self removeFromSuperview]; }]; } } @end