diff --git a/Source/KxMenu.m b/Source/KxMenu.m index bdfb6a3..bd6aa56 100644 --- a/Source/KxMenu.m +++ b/Source/KxMenu.m @@ -29,12 +29,12 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + */ /* Some ideas was taken from QBPopupMenu project by Katsuma Tanaka. https://github.com/questbeat/QBPopupMenu -*/ + */ #import "KxMenu.h" #import @@ -52,8 +52,6 @@ @interface KxMenuOverlay : UIView @implementation KxMenuOverlay -// - (void) dealloc { NSLog(@"dealloc %@", self); } - - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; @@ -143,7 +141,7 @@ - (NSString *) description //////////////////////////////////////////////////////////////////////////////// typedef enum { - + KxMenuViewArrowDirectionNone, KxMenuViewArrowDirectionUp, KxMenuViewArrowDirectionDown, @@ -162,9 +160,9 @@ @implementation KxMenuView { - (id)init { - self = [super initWithFrame:CGRectZero]; + self = [super initWithFrame:CGRectZero]; if(self) { - + self.backgroundColor = [UIColor clearColor]; self.opaque = YES; self.alpha = 0; @@ -177,8 +175,6 @@ - (id)init return self; } -// - (void) dealloc { NSLog(@"dealloc %@", self); } - - (void) setupFrameInView:(UIView *)view fromRect:(CGRect)fromRect { @@ -202,7 +198,7 @@ - (void) setupFrameInView:(UIView *)view const CGFloat kMargin = 5.f; if (heightPlusArrow < (outerHeight - rectY1)) { - + _arrowDirection = KxMenuViewArrowDirectionUp; CGPoint point = (CGPoint){ rectXM - widthHalf, @@ -216,9 +212,8 @@ - (void) setupFrameInView:(UIView *)view point.x = outerWidth - contentSize.width - kMargin; _arrowPosition = rectXM - point.x; - //_arrowPosition = MAX(16, MIN(_arrowPosition, contentSize.width - 16)); _contentView.frame = (CGRect){0, kArrowSize, contentSize}; - + self.frame = (CGRect) { point, @@ -308,7 +303,7 @@ - (void) setupFrameInView:(UIView *)view (outerHeight - contentSize.height) * 0.5f, contentSize, }; - } + } } - (void)showMenuInView:(UIView *)view @@ -321,7 +316,7 @@ - (void)showMenuInView:(UIView *)view [self addSubview:_contentView]; [self setupFrameInView:view fromRect:rect]; - + KxMenuOverlay *overlay = [[KxMenuOverlay alloc] initWithFrame:view.bounds]; [overlay addSubview:self]; [view addSubview:overlay]; @@ -339,16 +334,16 @@ - (void)showMenuInView:(UIView *)view } completion:^(BOOL completed) { _contentView.hidden = NO; }]; - + } - (void)dismissMenu:(BOOL) animated { if (self.superview) { - + if (animated) { - _contentView.hidden = YES; + _contentView.hidden = YES; const CGRect toFrame = (CGRect){self.arrowPoint, 1, 1}; [UIView animateWithDuration:0.2 @@ -384,30 +379,50 @@ - (void)performAction:(id)sender - (UIView *) mkContentView { + bool scrollable = false; + for (UIView *v in self.subviews) { [v removeFromSuperview]; } if (!_menuItems.count) return nil; - + + NSUInteger itemNum = [_menuItems count]; + const CGFloat kMinMenuItemHeight = 32.f; const CGFloat kMinMenuItemWidth = 32.f; const CGFloat kMarginX = 10.f; - const CGFloat kMarginY = 5.f; + const CGFloat kMarginY = 3.5f; + + CGRect screen = [[UIScreen mainScreen] bounds]; + CGFloat screenY = screen.size.height; + + CGFloat hypotheticalSize = kMinMenuItemHeight + 60 * 2 + kArrowSize; + + int maxItemsToFitOnScreen = 0; + + for (; ((maxItemsToFitOnScreen < itemNum) && (hypotheticalSize < screenY)); maxItemsToFitOnScreen++) { + hypotheticalSize += kMinMenuItemHeight; + } + + itemNum = 0; + + scrollable = (maxItemsToFitOnScreen < [_menuItems count]); + UIFont *titleFont = [KxMenu titleFont]; if (!titleFont) titleFont = [UIFont boldSystemFontOfSize:16]; - CGFloat maxImageWidth = 0; + CGFloat maxImageWidth = 0; CGFloat maxItemHeight = 0; CGFloat maxItemWidth = 0; for (KxMenuItem *menuItem in _menuItems) { - const CGSize imageSize = menuItem.image.size; + const CGSize imageSize = menuItem.image.size; if (imageSize.width > maxImageWidth) - maxImageWidth = imageSize.width; + maxImageWidth = imageSize.width; } if (maxImageWidth) { @@ -415,10 +430,10 @@ - (UIView *) mkContentView } for (KxMenuItem *menuItem in _menuItems) { - + const CGSize titleSize = [menuItem.title sizeWithFont:titleFont]; const CGSize imageSize = menuItem.image.size; - + const CGFloat itemHeight = MAX(titleSize.height, imageSize.height) + kMarginY * 2; const CGFloat itemWidth = ((!menuItem.enabled && !menuItem.image) ? titleSize.width : maxImageWidth + titleSize.width) + kMarginX * 4; @@ -428,37 +443,38 @@ - (UIView *) mkContentView if (itemWidth > maxItemWidth) maxItemWidth = itemWidth; } - + maxItemWidth = MAX(maxItemWidth, kMinMenuItemWidth); maxItemHeight = MAX(maxItemHeight, kMinMenuItemHeight); - + const CGFloat titleX = kMarginX * 2 + maxImageWidth; const CGFloat titleWidth = maxItemWidth - titleX - kMarginX * 2; UIImage *selectedImage = [KxMenuView selectedImage:(CGSize){maxItemWidth, maxItemHeight + 2}]; UIImage *gradientLine = [KxMenuView gradientLine: (CGSize){maxItemWidth - kMarginX * 4, 1}]; - UIView *contentView = [[UIView alloc] initWithFrame:CGRectZero]; + UIScrollView *contentView = [[UIScrollView alloc] initWithFrame:CGRectZero]; + [contentView setScrollEnabled:scrollable]; contentView.autoresizingMask = UIViewAutoresizingNone; contentView.backgroundColor = [UIColor clearColor]; contentView.opaque = NO; CGFloat itemY = kMarginY * 2; - NSUInteger itemNum = 0; - + CGFloat itemY2 = itemY; + for (KxMenuItem *menuItem in _menuItems) { - + const CGRect itemFrame = (CGRect){0, itemY, maxItemWidth, maxItemHeight}; UIView *itemView = [[UIView alloc] initWithFrame:itemFrame]; itemView.autoresizingMask = UIViewAutoresizingNone; - itemView.backgroundColor = [UIColor clearColor]; + itemView.backgroundColor = [UIColor clearColor]; itemView.opaque = NO; - + [contentView addSubview:itemView]; if (menuItem.enabled) { - + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.tag = itemNum; button.frame = itemView.bounds; @@ -507,7 +523,7 @@ - (UIView *) mkContentView titleLabel.backgroundColor = [UIColor clearColor]; titleLabel.autoresizingMask = UIViewAutoresizingNone; //titleLabel.backgroundColor = [UIColor greenColor]; - [itemView addSubview:titleLabel]; + [itemView addSubview:titleLabel]; } if (menuItem.image) { @@ -521,9 +537,12 @@ - (UIView *) mkContentView [itemView addSubview:imageView]; } - if (itemNum < _menuItems.count - 1) { + ++itemNum; + + if (itemNum < [_menuItems count]) { UIImageView *gradientView = [[UIImageView alloc] initWithImage:gradientLine]; + [gradientView setUserInteractionEnabled:NO]; gradientView.frame = (CGRect){kMarginX * 2, maxItemHeight + 1, gradientLine.size}; gradientView.contentMode = UIViewContentModeLeft; [itemView addSubview:gradientView]; @@ -532,10 +551,15 @@ - (UIView *) mkContentView } itemY += maxItemHeight; - ++itemNum; - } + + if (itemNum <= maxItemsToFitOnScreen) + itemY2 = itemY; + } + - contentView.frame = (CGRect){0, 0, maxItemWidth, itemY + kMarginY * 2}; + // Size of the box + contentView.frame = (CGRect){0, 0, maxItemWidth, (itemY2+10)}; + contentView.contentSize = CGSizeMake(maxItemWidth, ((maxItemHeight+2) * itemNum+10)); return contentView; } @@ -584,7 +608,7 @@ + (UIImage *) gradientLine: (CGSize) size const CGFloat locations[5] = {0,0.2,0.5,0.8,1}; const CGFloat R = 0.44f, G = 0.44f, B = 0.44f; - + const CGFloat components[20] = { R,G,B,0.1, R,G,B,0.4, @@ -682,7 +706,7 @@ - (void)drawBackground:(CGRect)frame } else if (_arrowDirection == KxMenuViewArrowDirectionLeft) { - const CGFloat arrowYM = _arrowPosition; + const CGFloat arrowYM = _arrowPosition; const CGFloat arrowX0 = X0; const CGFloat arrowX1 = X0 + kArrowSize + kEmbedFix; const CGFloat arrowY0 = arrowYM - kArrowSize;; @@ -699,7 +723,7 @@ - (void)drawBackground:(CGRect)frame } else if (_arrowDirection == KxMenuViewArrowDirectionRight) { - const CGFloat arrowYM = _arrowPosition; + const CGFloat arrowYM = _arrowPosition; const CGFloat arrowX0 = X1; const CGFloat arrowX1 = X1 - kArrowSize - kEmbedFix; const CGFloat arrowY0 = arrowYM - kArrowSize;; @@ -716,14 +740,14 @@ - (void)drawBackground:(CGRect)frame } [arrowPath fill]; - + // render body const CGRect bodyFrame = {X0, Y0, X1 - X0, Y1 - Y0}; UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:bodyFrame cornerRadius:8]; - + const CGFloat locations[] = {0, 1}; const CGFloat components[] = { R0, G0, B0, 1, @@ -744,7 +768,7 @@ - (void)drawBackground:(CGRect)frame if (_arrowDirection == KxMenuViewArrowDirectionLeft || _arrowDirection == KxMenuViewArrowDirectionRight) { - + start = (CGPoint){X0, Y0}; end = (CGPoint){X1, Y0}; @@ -756,7 +780,7 @@ - (void)drawBackground:(CGRect)frame CGContextDrawLinearGradient(context, gradient, start, end, 0); - CGGradientRelease(gradient); + CGGradientRelease(gradient); } @end @@ -796,7 +820,7 @@ - (id) init - (void) dealloc { - if (_observing) { + if (_observing) { [[NSNotificationCenter defaultCenter] removeObserver:self]; } } @@ -813,9 +837,9 @@ - (void) showMenuInView:(UIView *)view [_menuView dismissMenu:NO]; _menuView = nil; } - - if (!_observing) { + if (!_observing) { + _observing = YES; [[NSNotificationCenter defaultCenter] addObserver:self @@ -823,10 +847,10 @@ - (void) showMenuInView:(UIView *)view name:UIApplicationWillChangeStatusBarOrientationNotification object:nil]; } - + _menuView = [[KxMenuView alloc] init]; - [_menuView showMenuInView:view fromRect:rect menuItems:menuItems]; + [_menuView showMenuInView:view fromRect:rect menuItems:menuItems]; } - (void) dismissMenu @@ -885,4 +909,4 @@ + (void) setTitleFont: (UIFont *) titleFont } } -@end +@end \ No newline at end of file