| // 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. |
| |
| #import <UIKit/UIKit.h> |
| |
| #import "MaterialPalettes.h" |
| #import "MaterialProgressView.h" |
| #import "MaterialColorScheme.h" |
| #import "MaterialTypographyScheme.h" |
| |
| static const CGFloat MDCProgressViewAnimationDuration = 1; |
| static const CGFloat MDCProgressViewIndeterminateAnimationDuration = 4; |
| |
| @interface ProgressViewExample : UIViewController |
| |
| @property(nonatomic, strong) UIView *container; |
| |
| @property(nonatomic, strong) MDCProgressView *stockProgressView; |
| @property(nonatomic, strong) UILabel *stockProgressLabel; |
| |
| @property(nonatomic, strong) MDCProgressView *tintedProgressView; |
| @property(nonatomic, strong) UILabel *tintedProgressLabel; |
| |
| @property(nonatomic, strong) MDCProgressView *fullyColoredProgressView; |
| @property(nonatomic, strong) UILabel *fullyColoredProgressLabel; |
| |
| @property(nonatomic, strong) MDCProgressView *gradientColoredProgressView; |
| @property(nonatomic, strong) UILabel *gradientColoredProgressLabel; |
| |
| @property(nonatomic, strong) MDCProgressView *backwardProgressResetView; |
| @property(nonatomic, strong) UILabel *backwardProgressResetLabel; |
| |
| @property(nonatomic, strong) MDCProgressView *backwardProgressAnimateView; |
| @property(nonatomic, strong) UILabel *backwardProgressAnimateLabel; |
| |
| @property(nonatomic, strong) MDCProgressView *indeterminateProgressView; |
| @property(nonatomic, strong) UILabel *indeterminateProgressLabel; |
| |
| @property(nonatomic, strong) MDCSemanticColorScheme *colorScheme; |
| @property(nonatomic, strong) MDCTypographyScheme *typographyScheme; |
| |
| @end |
| |
| @implementation ProgressViewExample |
| |
| - (void)setupProgressViews { |
| _stockProgressView = [[MDCProgressView alloc] init]; |
| _stockProgressView.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_stockProgressView]; |
| // Hide the progress view at setup time. |
| _stockProgressView.hidden = YES; |
| |
| _tintedProgressView = [[MDCProgressView alloc] init]; |
| _tintedProgressView.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_tintedProgressView]; |
| _tintedProgressView.progressTintColor = self.colorScheme.primaryColor; |
| _tintedProgressView.trackTintColor = |
| [self.colorScheme.primaryColor colorWithAlphaComponent:(CGFloat)0.24]; |
| // Hide the progress view at setup time. |
| _tintedProgressView.hidden = YES; |
| |
| _fullyColoredProgressView = [[MDCProgressView alloc] init]; |
| _fullyColoredProgressView.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_fullyColoredProgressView]; |
| _fullyColoredProgressView.progressTintColor = MDCPalette.greenPalette.tint500; |
| _fullyColoredProgressView.trackTintColor = MDCPalette.yellowPalette.tint500; |
| // Hide the progress view at setup time. |
| _fullyColoredProgressView.hidden = YES; |
| |
| _gradientColoredProgressView = [[MDCProgressView alloc] init]; |
| _gradientColoredProgressView.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_gradientColoredProgressView]; |
| _gradientColoredProgressView.progressTintColors = @[ |
| (id)MDCPalette.greenPalette.tint500.CGColor, (id)MDCPalette.bluePalette.tint500.CGColor, |
| (id)MDCPalette.redPalette.tint500.CGColor |
| ]; |
| _gradientColoredProgressView.trackTintColor = MDCPalette.yellowPalette.tint500; |
| _gradientColoredProgressView.progress = 0.33f; |
| |
| _backwardProgressResetView = [[MDCProgressView alloc] init]; |
| _backwardProgressResetView.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_backwardProgressResetView]; |
| // Have a non-zero progress at setup time. |
| _backwardProgressResetView.progress = (float)0.33; |
| |
| _backwardProgressAnimateView = [[MDCProgressView alloc] init]; |
| _backwardProgressAnimateView.translatesAutoresizingMaskIntoConstraints = NO; |
| _backwardProgressAnimateView.backwardProgressAnimationMode = |
| MDCProgressViewBackwardAnimationModeAnimate; |
| [self.container addSubview:_backwardProgressAnimateView]; |
| // Have a non-zero progress at setup time. |
| _backwardProgressAnimateView.progress = (float)0.33; |
| |
| _indeterminateProgressView = [[MDCProgressView alloc] init]; |
| _indeterminateProgressView.mode = MDCProgressViewModeIndeterminate; |
| _indeterminateProgressView.translatesAutoresizingMaskIntoConstraints = NO; |
| _indeterminateProgressView.progressTintColor = self.colorScheme.primaryColor; |
| _indeterminateProgressView.trackTintColor = |
| [self.colorScheme.primaryColor colorWithAlphaComponent:(CGFloat)0.24]; |
| [self.container addSubview:_indeterminateProgressView]; |
| } |
| |
| @end |
| |
| @implementation ProgressViewExample (Supplemental) |
| |
| - (void)dealloc { |
| [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
| } |
| |
| - (void)viewDidLoad { |
| [super viewDidLoad]; |
| |
| if (!self.colorScheme) { |
| self.colorScheme = |
| [[MDCSemanticColorScheme alloc] initWithDefaults:MDCColorSchemeDefaultsMaterial201804]; |
| } |
| if (!self.typographyScheme) { |
| self.typographyScheme = [[MDCTypographyScheme alloc] init]; |
| } |
| |
| self.title = @"Progress View"; |
| self.view.backgroundColor = self.colorScheme.backgroundColor; |
| |
| [self setupContainer]; |
| [self setupProgressViews]; |
| [self setupLabels]; |
| [self setupConstraints]; |
| |
| self.navigationItem.rightBarButtonItem = |
| [[UIBarButtonItem alloc] initWithTitle:@"Animate" |
| style:UIBarButtonItemStylePlain |
| target:self |
| action:@selector(didPressAnimateButton:)]; |
| self.navigationItem.rightBarButtonItem.accessibilityIdentifier = @"animate_button"; |
| } |
| |
| - (void)viewDidLayoutSubviews { |
| [super viewDidLayoutSubviews]; |
| [self positionContainer]; |
| } |
| |
| - (void)setupContainer { |
| self.container = [[UIView alloc] initWithFrame:self.view.bounds]; |
| [self.view addSubview:self.container]; |
| } |
| |
| - (void)positionContainer { |
| CGFloat originX = CGRectGetMinX(self.view.bounds) + self.view.layoutMargins.left; |
| CGFloat originY = CGRectGetMinY(self.view.bounds) + self.view.layoutMargins.top; |
| CGFloat width = |
| self.view.bounds.size.width - (self.view.layoutMargins.left + self.view.layoutMargins.right); |
| CGFloat height = |
| self.view.bounds.size.height - (self.view.layoutMargins.top + self.view.layoutMargins.bottom); |
| CGRect frame = CGRectMake(originX, originY, width, height); |
| self.container.frame = frame; |
| } |
| |
| - (void)setupLabels { |
| _stockProgressLabel = [[UILabel alloc] init]; |
| _stockProgressLabel.text = @"Progress"; |
| _stockProgressLabel.font = self.typographyScheme.caption; |
| _stockProgressLabel.textColor = self.colorScheme.onBackgroundColor; |
| _stockProgressLabel.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_stockProgressLabel]; |
| |
| _tintedProgressLabel = [[UILabel alloc] init]; |
| _tintedProgressLabel.text = @"Progress with progress tint"; |
| _tintedProgressLabel.font = self.typographyScheme.caption; |
| _tintedProgressLabel.textColor = self.colorScheme.onBackgroundColor; |
| _tintedProgressLabel.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_tintedProgressLabel]; |
| |
| _fullyColoredProgressLabel = [[UILabel alloc] init]; |
| _fullyColoredProgressLabel.text = @"Progress with custom colors"; |
| _fullyColoredProgressLabel.font = self.typographyScheme.caption; |
| _fullyColoredProgressLabel.textColor = self.colorScheme.onBackgroundColor; |
| _fullyColoredProgressLabel.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_fullyColoredProgressLabel]; |
| |
| _gradientColoredProgressLabel = [[UILabel alloc] init]; |
| _gradientColoredProgressLabel.text = @"Progress with gradient colors"; |
| _gradientColoredProgressLabel.font = self.typographyScheme.caption; |
| _gradientColoredProgressLabel.textColor = self.colorScheme.onBackgroundColor; |
| _gradientColoredProgressLabel.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_gradientColoredProgressLabel]; |
| |
| _backwardProgressResetLabel = [[UILabel alloc] init]; |
| _backwardProgressResetLabel.text = @"Backward progress (reset)"; |
| _backwardProgressResetLabel.font = self.typographyScheme.caption; |
| _backwardProgressResetLabel.textColor = self.colorScheme.onBackgroundColor; |
| _backwardProgressResetLabel.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_backwardProgressResetLabel]; |
| |
| _backwardProgressAnimateLabel = [[UILabel alloc] init]; |
| _backwardProgressAnimateLabel.text = @"Backward progress (animate)"; |
| _backwardProgressAnimateLabel.font = self.typographyScheme.caption; |
| _backwardProgressAnimateLabel.textColor = self.colorScheme.onBackgroundColor; |
| _backwardProgressAnimateLabel.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_backwardProgressAnimateLabel]; |
| |
| _indeterminateProgressLabel = [[UILabel alloc] init]; |
| _indeterminateProgressLabel.text = @"Indeterminate progress"; |
| _indeterminateProgressLabel.font = self.typographyScheme.caption; |
| _indeterminateProgressLabel.textColor = self.colorScheme.onBackgroundColor; |
| _indeterminateProgressLabel.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.container addSubview:_indeterminateProgressLabel]; |
| } |
| |
| - (void)setupConstraints { |
| NSDictionary *views = @{ |
| @"container" : _container, |
| @"stockView" : _stockProgressView, |
| @"stockLabel" : _stockProgressLabel, |
| @"tintedView" : _tintedProgressView, |
| @"tintedLabel" : _tintedProgressLabel, |
| @"coloredView" : _fullyColoredProgressView, |
| @"coloredLabel" : _fullyColoredProgressLabel, |
| @"gradientView" : _gradientColoredProgressView, |
| @"gradientLabel" : _gradientColoredProgressLabel, |
| @"backwardResetView" : _backwardProgressResetView, |
| @"backwardResetLabel" : _backwardProgressResetLabel, |
| @"backwardAnimateView" : _backwardProgressAnimateView, |
| @"backwardAnimateLabel" : _backwardProgressAnimateLabel, |
| @"indeterminateView" : _indeterminateProgressView, |
| @"indeterminateLabel" : _indeterminateProgressLabel, |
| }; |
| NSDictionary *metrics = @{ |
| @"t" : @20, |
| @"p" : @0, |
| @"s" : @40, |
| @"h" : @2, |
| }; |
| |
| NSArray *verticalConstraints = [NSLayoutConstraint |
| constraintsWithVisualFormat:@"V:|-(t)-" |
| "[stockView(==h)]-(p)-[stockLabel]-(s)-" |
| "[tintedView(==h)]-(p)-[tintedLabel]-(s)-" |
| "[coloredView(==h)]-(p)-[coloredLabel]-(s)-" |
| "[gradientView(==h)]-(p)-[gradientLabel]-(s)-" |
| "[backwardResetView(==h)]-(p)-[backwardResetLabel]-(s)-" |
| "[backwardAnimateView(==h)]-(p)-[backwardAnimateLabel]-(s)-" |
| "[indeterminateView(==h)]-(p)-[indeterminateLabel]" |
| options:0 |
| metrics:metrics |
| views:views]; |
| [self.view addConstraints:verticalConstraints]; |
| |
| NSMutableArray *horizontalConstraints = [NSMutableArray array]; |
| NSArray *horizontalVisualFormats = @[ |
| @"H:|-(p)-[stockView]-(p)-|", |
| @"H:|-(p)-[tintedView]-(p)-|", |
| @"H:|-(p)-[coloredView]-(p)-|", |
| @"H:|-(p)-[gradientView]-(p)-|", |
| @"H:|-(p)-[backwardResetView]-(p)-|", |
| @"H:|-(p)-[backwardAnimateView]-(p)-|", |
| @"H:|-(p)-[indeterminateView]-(p)-|", |
| @"H:|-(p)-[stockLabel]-(p)-|", |
| @"H:|-(p)-[tintedLabel]-(p)-|", |
| @"H:|-(p)-[coloredLabel]-(p)-|", |
| @"H:|-(p)-[gradientLabel]-(p)-|", |
| @"H:|-(p)-[backwardResetLabel]-(p)-|", |
| @"H:|-(p)-[backwardAnimateLabel]-(p)-|", |
| @"H:|-(p)-[indeterminateLabel]-(p)-|", |
| ]; |
| for (NSString *format in horizontalVisualFormats) { |
| [horizontalConstraints |
| addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:format |
| options:0 |
| metrics:metrics |
| views:views]]; |
| } |
| [self.view addConstraints:horizontalConstraints]; |
| } |
| |
| - (void)didPressAnimateButton:(UIButton *)sender { |
| sender.enabled = NO; |
| [self animateStep1:_stockProgressView]; |
| [self animateStep1:_tintedProgressView]; |
| [self animateStep1:_fullyColoredProgressView]; |
| [self animateStep1:_gradientColoredProgressView]; |
| [self animateBackwardProgressResetViewWithCountdown:4]; |
| [self animateBackwardProgressAnimateViewWithCountdown:4 |
| completion:^(BOOL ignored) { |
| sender.enabled = YES; |
| }]; |
| [self animateIndeterminateProgressBarWithCountdown:1]; |
| } |
| |
| - (void)animateStep1:(MDCProgressView *)progressView { |
| progressView.progress = 0; |
| __weak MDCProgressView *weakProgressView = progressView; |
| [progressView setHidden:NO |
| animated:YES |
| completion:^(BOOL finished) { |
| [self performSelector:@selector(animateStep2:) |
| withObject:weakProgressView |
| afterDelay:MDCProgressViewAnimationDuration]; |
| }]; |
| } |
| |
| - (void)animateStep2:(MDCProgressView *)progressView { |
| [progressView setProgress:0.5 animated:YES completion:nil]; |
| [self performSelector:@selector(animateStep3:) |
| withObject:progressView |
| afterDelay:MDCProgressViewAnimationDuration]; |
| } |
| |
| - (void)animateStep3:(MDCProgressView *)progressView { |
| [progressView setProgress:1 animated:YES completion:nil]; |
| [self performSelector:@selector(animateStep4:) |
| withObject:progressView |
| afterDelay:MDCProgressViewAnimationDuration]; |
| } |
| |
| - (void)animateStep4:(MDCProgressView *)progressView { |
| [progressView setHidden:YES animated:YES completion:nil]; |
| } |
| |
| - (void)animateBackwardProgressResetViewWithCountdown:(NSInteger)remainingCounts { |
| --remainingCounts; |
| __weak ProgressViewExample *weakSelf = self; |
| |
| [_backwardProgressResetView setProgress:1 - _backwardProgressResetView.progress |
| animated:YES |
| completion:nil]; |
| if (remainingCounts > 0) { |
| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, |
| (int64_t)(MDCProgressViewAnimationDuration * NSEC_PER_SEC)), |
| dispatch_get_main_queue(), ^{ |
| [weakSelf animateBackwardProgressResetViewWithCountdown:remainingCounts]; |
| }); |
| } |
| } |
| |
| - (void)animateBackwardProgressAnimateViewWithCountdown:(NSInteger)remainingCounts |
| completion:(void (^)(BOOL))completion { |
| --remainingCounts; |
| __weak ProgressViewExample *weakSelf = self; |
| |
| [_backwardProgressAnimateView setProgress:1 - _backwardProgressAnimateView.progress |
| animated:YES |
| completion:remainingCounts == 0 ? completion : nil]; |
| if (remainingCounts) { |
| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, |
| (int64_t)(MDCProgressViewAnimationDuration * NSEC_PER_SEC)), |
| dispatch_get_main_queue(), ^{ |
| [weakSelf animateBackwardProgressAnimateViewWithCountdown:remainingCounts |
| completion:completion]; |
| }); |
| } |
| } |
| |
| - (void)animateIndeterminateProgressBarWithCountdown:(NSInteger)remainingCounts { |
| __weak ProgressViewExample *weakSelf = self; |
| |
| if (!_indeterminateProgressView.animating) { |
| [_indeterminateProgressView startAnimating]; |
| } |
| |
| if (remainingCounts > 0) { |
| dispatch_after( |
| dispatch_time(DISPATCH_TIME_NOW, |
| (int64_t)(MDCProgressViewIndeterminateAnimationDuration * NSEC_PER_SEC)), |
| dispatch_get_main_queue(), ^{ |
| [weakSelf animateIndeterminateProgressBarWithCountdown:remainingCounts - 1]; |
| }); |
| } else { |
| [_indeterminateProgressView stopAnimating]; |
| } |
| } |
| |
| #pragma mark - CatalogByConvention |
| |
| + (NSDictionary *)catalogMetadata { |
| return @{ |
| @"breadcrumbs" : @[ @"Progress View", @"Progress View" ], |
| @"description" : @"Progress indicators display the length of a process or express an " |
| @"unspecified wait time.", |
| @"primaryDemo" : @YES, |
| @"presentable" : @YES, |
| }; |
| } |
| |
| @end |