blob: 8f3283eb4283b530992796983de0aaaa6fc35172 [file] [log] [blame]
// Copyright 2016-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/* IMPORTANT:
This file contains supplemental code used to populate the examples with dummy data and/or
instructions. It is not necessary to import this file to use Material Components for iOS.
*/
#import "ButtonsTypicalUseSupplemental.h"
#import "MDCButton.h"
#import "MDCTypography.h"
#import "MDCMath.h"
static const CGFloat kViewOffsetToCenter = 20;
#pragma mark - ButtonsTypicalUseViewController
@implementation ButtonsTypicalUseExample (CatalogByConvention)
+ (NSDictionary *)catalogMetadata {
return @{
@"breadcrumbs" : @[ @"Buttons", @"Buttons" ],
@"description" : @"Buttons allow users to take actions, and make choices, with a single tap."
@"\nA floating action button (FAB) represents the primary action of a screen.",
@"primaryDemo" : @YES,
@"presentable" : @YES,
};
}
@end
@implementation ButtonsTypicalUseViewController
- (UILabel *)addLabelWithText:(NSString *)text {
UILabel *label = [[UILabel alloc] init];
label.text = text;
label.font = [MDCTypography captionFont];
[label sizeToFit];
[self.view addSubview:label];
return label;
}
- (CGRect)contentBounds {
return UIEdgeInsetsInsetRect(self.view.bounds, self.view.safeAreaInsets);
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGRect contentBounds = [self contentBounds];
CGFloat centerX = CGRectGetMidX(contentBounds);
[self layoutButtonsInRange:NSMakeRange(0, self.buttons.count) around:centerX];
UIView *lastButton = self.buttons.lastObject;
CGFloat lastButtonMaxY = (CGRectGetHeight(lastButton.bounds) / 2) + lastButton.center.y;
if (lastButtonMaxY > CGRectGetMaxY(contentBounds)) {
CGFloat columnOffset = CGRectGetWidth(contentBounds) / 4;
NSUInteger splitIndex = (NSUInteger)ceil(self.buttons.count / 2);
if (((MDCButton *)self.buttons[splitIndex - 1]).enabled) {
splitIndex++;
}
[self layoutButtonsInRange:NSMakeRange(0, splitIndex) around:centerX - columnOffset];
[self layoutButtonsInRange:NSMakeRange(splitIndex, self.buttons.count - splitIndex)
around:centerX + columnOffset];
}
}
- (void)layoutButtonsInRange:(NSRange)range around:(CGFloat)centerX {
CGFloat heightSum = 0;
CGRect contentBounds = [self contentBounds];
CGFloat viewHeight = CGRectGetHeight(contentBounds);
// Calculate the overall height of the labels + buttons
for (NSUInteger i = range.location; i < NSMaxRange(range); i++) {
MDCButton *button = self.buttons[i];
UILabel *label = self.labels[i];
button.center = CGPointMake(centerX + kViewOffsetToCenter + (CGRectGetWidth(button.bounds) / 2),
heightSum + (CGRectGetHeight(button.bounds) / 2));
CGFloat labelOffset = (CGRectGetHeight(button.bounds) - CGRectGetHeight(label.bounds)) / 2;
label.center = CGPointMake(centerX - (CGRectGetWidth(label.bounds) / 2) - kViewOffsetToCenter,
heightSum + labelOffset + (CGRectGetHeight(label.bounds) / 2));
// Pin the label's frame to pixel boundaries to reduce snapshot flakiness due to inaccuracies in
// floating point rounding behavior on the GPU when taking snapshots.
CGRect labelFrame = label.frame;
labelFrame.origin.x = floor(labelFrame.origin.x);
labelFrame.origin.y = floor(labelFrame.origin.y);
label.frame = labelFrame;
heightSum += CGRectGetHeight(button.bounds);
if (i < self.buttons.count - 1) {
heightSum += button.enabled ? 24 : 36;
}
}
// Center the labels and buttons within the content bounds
MDCButton *lastButton = self.buttons[NSMaxRange(range) - 1];
CGFloat verticalCenterY =
(viewHeight - (lastButton.center.y + (CGRectGetHeight(lastButton.bounds) / 2))) / 2;
verticalCenterY += CGRectGetMinY(contentBounds);
for (NSUInteger i = range.location; i < NSMaxRange(range); i++) {
MDCButton *button = self.buttons[i];
UILabel *label = self.labels[i];
button.center = MDCRoundCenterWithBoundsAndScale(
CGPointMake(button.center.x, button.center.y + verticalCenterY), button.bounds,
self.view.window.screen.scale);
CGFloat labelWidth = CGRectGetWidth(label.bounds);
CGFloat labelHeight = CGRectGetHeight(label.bounds);
CGPoint labelOrigin = CGPointMake(label.center.x - (labelWidth / 2),
label.center.y - (labelHeight / 2) + verticalCenterY);
CGRect alignedFrame = MDCRectAlignToScale(
(CGRect){labelOrigin, CGSizeMake(labelWidth, labelHeight)}, [UIScreen mainScreen].scale);
label.center = CGPointMake(CGRectGetMidX(alignedFrame), CGRectGetMidY(alignedFrame));
label.bounds = (CGRect){label.bounds.origin, alignedFrame.size};
// Adjust the label's center and bounds so it doesn't exceed the safe area on the left side of
// the screen, the situation that button exceeds the safe area on the right side is not
// considered yet
CGFloat labelOriginX = label.center.x - label.bounds.size.width / 2;
if (labelOriginX < contentBounds.origin.x) {
CGFloat labelXOffset = contentBounds.origin.x - labelOriginX;
CGFloat maxLabelWidth = label.bounds.size.width - labelXOffset;
label.numberOfLines = 0;
CGSize newSizeToFitLabel = [label sizeThatFits:CGSizeMake(maxLabelWidth, CGFLOAT_MAX)];
label.center =
CGPointMake(centerX - newSizeToFitLabel.width / 2 - kViewOffsetToCenter, label.center.y);
label.bounds = CGRectMake(label.center.x - newSizeToFitLabel.width / 2, label.center.y,
newSizeToFitLabel.width, newSizeToFitLabel.height);
label.textAlignment = NSTextAlignmentRight;
}
}
}
@end