-
Notifications
You must be signed in to change notification settings - Fork 11
UKProgressBar #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
UKProgressBar #50
Changes from 5 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
e506856
UKProgressBar
VislovIvan 484b972
Documentation
VislovIvan d9b9b81
swiftlint fix
VislovIvan 5bafbbc
renamed layoutNeedsUpdate
VislovIvan 34c6d87
some fix
VislovIvan 99c9756
fix shouldUpdateLayout
VislovIvan ab22fe9
Preview fix
VislovIvan dc192aa
progress extracted
VislovIvan 2779d70
updateBarWidth fix
VislovIvan 3c963fa
intrinsicContentSize fix
VislovIvan ace276a
currentValue renamed to initialValue
VislovIvan 9fcef79
horizontalPadding
VislovIvan 49b8e91
corner radius fix
VislovIvan 76516e9
renaming
VislovIvan faf4e54
style extension for UKProgressBar
VislovIvan 50bdc32
swiftlint fix
VislovIvan 78c07c7
fix layout metod
VislovIvan d921d2a
CAShapeLayer for stripedLayer instead of UIView
VislovIvan 84abff2
fix animation
VislovIvan 5f90099
code style fix
VislovIvan 9a2c02e
some fix
VislovIvan 1a7b716
Merge branch 'SUProgressBar' into UKProgressBar
VislovIvan 058e95a
swiftlint fix
VislovIvan 9d2ba44
Merge branch 'UKProgressBar' of https://github.com/componentskit/Comp…
VislovIvan cb9babd
fix merge conflicts
VislovIvan 0d1b482
move ProgressBar folder into Components
mikhailChelbaev 263a302
improve layout in UKProgressBar
mikhailChelbaev 4e22f5b
fix progress bar preview
mikhailChelbaev c10bc32
improve helpers to calculate corner radius in progress bar
mikhailChelbaev fcc588d
simplify code in progress bar
mikhailChelbaev f8fab4d
improve method's name
mikhailChelbaev 7ae6885
validate min max values in UKProgressBar
mikhailChelbaev 06e613b
change animation style in progress bar to `linear`
mikhailChelbaev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,223 @@ | ||
| import AutoLayout | ||
| import UIKit | ||
|
|
||
| /// A UIKit component that displays a Progress Bar. | ||
| open class UKProgressBar: UIView, UKComponent { | ||
| // MARK: - Properties | ||
|
|
||
| /// A model that defines the appearance properties. | ||
| public var model: ProgressBarVM { | ||
| didSet { | ||
| self.update(oldValue) | ||
| } | ||
| } | ||
|
|
||
| /// The current progress value for the progress bar. | ||
| public var currentValue: CGFloat { | ||
| didSet { | ||
| self.updateBarWidth() | ||
| } | ||
| } | ||
|
|
||
| // MARK: - Subviews | ||
|
|
||
| /// A view representing the part of the progress bar that is not yet filled. | ||
| private let remainingView = UIView() | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// A view representing the filled part of the bar. | ||
| private let filledView = UIView() | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// A view used to display the striped pattern. | ||
| private let stripedView = UIView() | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // MARK: - Layout Constraints | ||
|
|
||
| private var remainingViewConstraints: LayoutConstraints = .init() | ||
| private var filledViewConstraints: LayoutConstraints = .init() | ||
| private var stripedViewConstraints: LayoutConstraints = .init() | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // MARK: - Private Properties | ||
|
|
||
| private var progress: CGFloat { | ||
| let range = self.model.maxValue - self.model.minValue | ||
| guard range > 0 else { return 0 } | ||
| let normalized = (self.currentValue - self.model.minValue) / range | ||
| return max(0, min(1, normalized)) | ||
| } | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // MARK: - Initialization | ||
|
|
||
| /// Initializer. | ||
| /// - Parameters: | ||
| /// - currentValue: The initial progress value. Defaults to `0`. | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// - model: A model that defines the appearance properties. | ||
| public init( | ||
| currentValue: CGFloat = 0, | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| model: ProgressBarVM = .init() | ||
| ) { | ||
| self.currentValue = currentValue | ||
| self.model = model | ||
| super.init(frame: .zero) | ||
|
|
||
| self.setup() | ||
| self.style() | ||
| self.layout() | ||
| } | ||
|
|
||
| public required init?(coder: NSCoder) { | ||
| fatalError("init(coder:) has not been implemented") | ||
| } | ||
|
|
||
| // MARK: - Setup | ||
|
|
||
| private func setup() { | ||
| self.addSubview(self.remainingView) | ||
| self.addSubview(self.filledView) | ||
| self.addSubview(self.stripedView) | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // MARK: - Style | ||
|
|
||
| private func style() { | ||
| switch self.model.style { | ||
| case .light: | ||
| self.remainingView.backgroundColor = self.model.backgroundColor.uiColor | ||
| self.filledView.backgroundColor = self.model.barColor.uiColor | ||
| self.stripedView.backgroundColor = .clear | ||
|
|
||
| case .filled: | ||
| self.remainingView.backgroundColor = self.model.color.main.uiColor | ||
| self.filledView.backgroundColor = self.model.color.contrast.uiColor | ||
| self.stripedView.backgroundColor = .clear | ||
|
|
||
| case .striped: | ||
| self.remainingView.backgroundColor = self.model.color.main.uiColor | ||
| self.filledView.backgroundColor = self.model.color.contrast.uiColor | ||
| self.stripedView.backgroundColor = self.model.color.main.uiColor | ||
| } | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // MARK: - Layout | ||
|
|
||
| private func layout() { | ||
|
||
| self.remainingViewConstraints.deactivateAll() | ||
| self.filledViewConstraints.deactivateAll() | ||
| self.stripedViewConstraints.deactivateAll() | ||
|
|
||
| UIView.performWithoutAnimation { | ||
| switch self.model.style { | ||
| case .light: | ||
| self.remainingViewConstraints = .merged { | ||
| self.remainingView.after(self.filledView, padding: 4) | ||
| self.remainingView.centerVertically() | ||
| self.remainingView.height(self.model.barHeight) | ||
| self.remainingView.width(0) | ||
| } | ||
| self.filledViewConstraints = .merged { | ||
| self.filledView.leading(0) | ||
| self.filledView.centerVertically() | ||
| self.filledView.height(self.model.barHeight) | ||
| self.filledView.width(0) | ||
| } | ||
|
|
||
| case .filled, .striped: | ||
| self.remainingViewConstraints = .merged { | ||
| self.remainingView.horizontally(0) | ||
| self.remainingView.centerVertically() | ||
| self.remainingView.height(self.model.barHeight) | ||
| } | ||
| self.filledViewConstraints = .merged { | ||
| self.filledView.leading(3, to: self.remainingView) | ||
| self.filledView.vertically(3, to: self.remainingView) | ||
| self.filledView.width(0) | ||
| } | ||
|
|
||
| if self.model.style == .striped { | ||
| self.stripedViewConstraints = .merged { | ||
| self.stripedView.horizontally(0) | ||
| self.stripedView.centerVertically() | ||
| self.stripedView.height(self.model.barHeight) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| self.setNeedsLayout() | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // MARK: - Update | ||
|
|
||
| public func update(_ oldModel: ProgressBarVM) { | ||
| guard self.model != oldModel else { return } | ||
|
|
||
| self.style() | ||
|
|
||
| if self.model.shouldUpdateLayout(from: oldModel) { | ||
| self.layout() | ||
| self.invalidateIntrinsicContentSize() | ||
| self.setNeedsLayout() | ||
| } | ||
|
|
||
| self.updateBarWidth() | ||
| } | ||
|
|
||
| private func updateBarWidth() { | ||
| let duration: TimeInterval = 0.3 | ||
|
|
||
| UIView.performWithoutAnimation { | ||
| self.layoutIfNeeded() | ||
| } | ||
|
|
||
| switch self.model.style { | ||
| case .light: | ||
| let totalWidth = self.bounds.width - 4 | ||
| let filledWidth = totalWidth * self.progress | ||
| self.filledViewConstraints.width?.constant = max(0, filledWidth) | ||
| self.remainingViewConstraints.width?.constant = max(0, totalWidth - filledWidth) | ||
|
|
||
| case .filled, .striped: | ||
| let totalWidth = self.bounds.width - 6 | ||
| let filledWidth = totalWidth * self.progress | ||
| self.filledViewConstraints.width?.constant = max(0, filledWidth) | ||
| } | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| UIView.animate(withDuration: duration) { | ||
| self.layoutIfNeeded() | ||
| } | ||
| } | ||
|
|
||
| // MARK: - Style Helpers | ||
|
|
||
| open override func layoutSubviews() { | ||
| super.layoutSubviews() | ||
|
|
||
| switch self.model.style { | ||
| case .light: | ||
| self.remainingView.layer.cornerRadius = self.model.computedCornerRadius | ||
| self.filledView.layer.cornerRadius = self.model.computedCornerRadius | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| case .filled: | ||
| self.remainingView.layer.cornerRadius = self.model.computedCornerRadius | ||
| self.filledView.layer.cornerRadius = self.model.innerCornerRadius | ||
|
|
||
| case .striped: | ||
| self.remainingView.layer.cornerRadius = self.model.computedCornerRadius | ||
| self.filledView.layer.cornerRadius = self.model.innerCornerRadius | ||
| self.stripedView.layer.cornerRadius = self.model.computedCornerRadius | ||
| self.stripedView.clipsToBounds = true | ||
| } | ||
|
|
||
| self.updateBarWidth() | ||
| self.layoutIfNeeded() | ||
|
|
||
| if self.model.style == .striped { | ||
| let shapeLayer = CAShapeLayer() | ||
| shapeLayer.path = self.model.stripesBezierPath(in: self.stripedView.bounds).cgPath | ||
| self.stripedView.layer.mask = shapeLayer | ||
| } | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| open override var intrinsicContentSize: CGSize { | ||
| CGSize(width: UIView.noIntrinsicMetric, height: self.model.barHeight) | ||
| } | ||
VislovIvan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.