IOS Implementation Step Progress Bar Function Example Code

Time:2019-5-29

Preface

In development, we often need to use progress bars in many scenarios, such as downloading files or uploading files. This article mainly introduces to you is a step progress bar effect, step progress bar effect reference.

Similar controls are not provided in iOS UIKit framework. We can use UIProgressView, UIView, UILabel combination to achieve step progress bar effect.

  • UIProgressView – Implementing horizontal progress bar effect;
  • UIView – Cut UIView into a circle to achieve the effect of index nodes;
  • UILabel – The prompt text below each node.

Source code

The step progress bar is encapsulated into an HQLStepView class, which is a subclass of UIView.

HQLStepView.h file

#import <UIKit/UIKit.h>

@interface HQLStepView : UIView

// Specify initialization method
- (instancetype)initWithFrame:(CGRect)frame titlesArray:(NSArray *)titlesArray stepIndex:(NSUInteger)stepIndex;

// Setting up the current step
- (void)setStepIndex:(NSUInteger)stepIndex animation:(BOOL)animation;

@end

HQLStepView.m file

#import "HQLStepView.h"

// Step-by-step theme color
#define TINT_COLOR [UIColor colorWithRed:35/255.f green:135/255.f blue:255/255.f alpha:1]

@interface HQLStepView ()

@property (nonatomic, copy) NSArray *titlesArray;
@property (nonatomic, assign) NSUInteger stepIndex;

@property (nonatomic, strong) UIProgressView *progressView;
@property (nonatomic, strong) NSMutableArray *circleViewArray;
@property (nonatomic, strong) NSMutableArray *titleLabelArray;
@property (nonatomic, strong) UILabel *indicatorLabel;

@end

@implementation HQLStepView

#pragma mark - Init

- (instancetype)initWithFrame:(CGRect)frame titlesArray:(NSArray *)titlesArray stepIndex:(NSUInteger)stepIndex {
 self = [super initWithFrame:frame];
 if (self) {
 _titlesArray = [titlesArray copy];
 _stepIndex = stepIndex;

 // progress bar
 [self addSubview:self.progressView];
 
 for (NSString *title in _titlesArray) {
  
  // circle
  UIView *circle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 13, 13)];
  circle.backgroundColor = [UIColor lightGrayColor];
  circle.layer.cornerRadius = 13.0f / 2;
  [self addSubview:circle];
  [self.circleViewArray addObject:circle];
  
  // Title
  UILabel *label = [[UILabel alloc] init];
  label.text = title;
  label.font = [UIFont systemFontOfSize:14];
  label.textAlignment = NSTextAlignmentCenter;
  [self addSubview:label];
  [self.titleLabelArray addObject:label];
 }
 
 // Current Index Number
 [self addSubview:self.indicatorLabel];
 }
 return self;
}

// Layout Update Page Elements
- (void)layoutSubviews {
 NSInteger perWidth = self.frame.size.width / self.titlesArray.count;
 
 // progress bar
 self.progressView.frame = CGRectMake(0, 0, self.frame.size.width - perWidth, 1);
 self.progressView.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 4);
 
 CGFloat startX = self.progressView.frame.origin.x;
 for (int i = 0; i < self.titlesArray.count; i++) {
 // circle
 UIView *cycle = self.circleViewArray[i];
 if (cycle) {
  cycle.center = CGPointMake(i * perWidth + startX, self.progressView.center.y);
 }
 
 // Title
 UILabel *label = self.titleLabelArray[i];
 if (label) {
  label.frame = CGRectMake(perWidth * i, self.frame.size.height / 2, self.frame.size.width / self.titlesArray.count, self.frame.size.height / 2 );
 }
 }
 self.stepIndex = self.stepIndex;
}

#pragma mark - Custom Accessors

- (UIProgressView *)progressView {
 if (!_progressView) {
 _progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
 _progressView.progressTintColor = TINT_COLOR;
 _progressView.progress = self.stepIndex / ((self.titlesArray.count - 1) * 1.0);
 }
 return _progressView;
}

- (UILabel *)indicatorLabel {
 if (!_indicatorLabel) {
 _indicatorLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 23, 23)];
 _indicatorLabel.textColor = TINT_COLOR;
 _indicatorLabel.textAlignment = NSTextAlignmentCenter;
 _indicatorLabel.backgroundColor = [UIColor whiteColor];
 _indicatorLabel.layer.cornerRadius = 23.0f / 2;
 _indicatorLabel.layer.borderColor = [TINT_COLOR CGColor];
 _indicatorLabel.layer.borderWidth = 1;
 _indicatorLabel.layer.masksToBounds = YES;
 }
 return _indicatorLabel;
}

- (NSMutableArray *)circleViewArray {
 if (!_circleViewArray) {
 _circleViewArray = [[NSMutableArray alloc] initWithCapacity:self.titlesArray.count];
 }
 return _circleViewArray;
}

- (NSMutableArray *)titleLabelArray {
 if (!_titleLabelArray) {
 _titleLabelArray = [[NSMutableArray alloc] initWithCapacity:self.titlesArray.count];
 }
 return _titleLabelArray;
}

// Set current progress index, update circular picture, text color, current index number
- (void)setStepIndex:(NSUInteger)stepIndex {
 for (int i = 0; i < self.titlesArray.count; i++) {
 UIView *cycle = self.circleViewArray[i];
 UILabel *label = self.titleLabelArray[i];
 if (stepIndex >= i) {
  cycle.backgroundColor = TINT_COLOR;
  label.textColor = TINT_COLOR;
 } else {
  cycle.backgroundColor = [UIColor lightGrayColor];
  label.textColor = [UIColor lightGrayColor];
 }
 }
}

#pragma mark - Public

- (void)setStepIndex:(NSUInteger)stepIndex animation:(BOOL)animation {
 if (stepIndex < self.titlesArray.count) {
 // Update color
 self.stepIndex = stepIndex;
 // Setting progress bar
 [self.progressView setProgress:stepIndex / ((self.titlesArray.count - 1) * 1.0) animated:animation];
 // Set the current index number
 self.indicatorLabel.text = [NSString stringWithFormat:@"%lu", stepIndex + 1];
 self.indicatorLabel.center = ((UIView *)[self.circleViewArray objectAtIndex:stepIndex]).center;
 }
}

@end

Interface calls:

- (void)viewDidLoad {
 [super viewDidLoad];
 
 // initialization
 _ hqlStepView = [[HQLStepView alloc] initWithFrame: CGRectMake (0, 200, self. view. frame. size. width, 60) titles Array:@ [@ First Step,@ Second Step,@ Third Step], step Index: 0];
 [self.view addSubview:_hqlStepView];
}

- (void)viewDidAppear:(BOOL)animated {
 [super viewDidAppear:animated];
 
 // Set the current step, step index = array index
 [_hqlStepView setStepIndex:0 animation:YES];
}

Effect:

Because the height of the horizontal progress bar implemented by UIProgressView defaults to 1, setting frame is invalid. Its height can be increased by affine transformation.

Third-party framework

  • GitHub: ISTimeline ⭐️900
  • GitHub: TimelineTableViewCell ⭐️800

Reference resources:

  • IOS custom step progress bar
  • XFStepProgress

Conclusion:

Above is the whole content of this article. I hope that the content of this article has a certain reference value for everyone’s study or work. If you have any questions, you can leave a message and exchange it. Thank you for your support to developpaer.