Skip to content

Commit

Permalink
feat: support range value limit instead of only limit
Browse files Browse the repository at this point in the history
  • Loading branch information
guoyingtao committed Jun 15, 2023
1 parent 81c44ec commit 8722b6d
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 73 deletions.
35 changes: 9 additions & 26 deletions Example/InchwormExample/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,12 @@ class ViewController: UIViewController {

view.backgroundColor = .black

createHorizontalBilateralTypeSlider()
createHorizontalUnilateralTypeSlider()
createVerticalBilateralTypeSlider()
createHorizontalSlider()
createVerticalSlider()
}

func createHorizontalBilateralTypeSlider() {
var config = Config()
config.sliderValueRangeType = .bilateral
let slider = createSlider(with: config)
slider.translatesAutoresizingMaskIntoConstraints = false

NSLayoutConstraint.activate([
slider.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -100),
slider.heightAnchor.constraint(equalToConstant: 120),
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 40),
slider.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -150)
])
}

func createHorizontalUnilateralTypeSlider() {
var config = Config()
config.sliderValueRangeType = .unilateral

func createHorizontalSlider() {
let config = Config()
let slider = createSlider(with: config)
slider.translatesAutoresizingMaskIntoConstraints = false

Expand All @@ -48,8 +31,8 @@ class ViewController: UIViewController {
slider.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
}

func createVerticalBilateralTypeSlider() {
func createVerticalSlider() {
var config = Config()
config.orientation = .vertical
let slider = createSlider(with: config)
Expand All @@ -65,15 +48,15 @@ class ViewController: UIViewController {
}

func createSlider(with config: Config) -> UIView {
let model1 = ProcessIndicatorModel(limitNumber: 30,
let model1 = ProcessIndicatorModel(valueRange: 0...30,
normalIconImage: UIImage(named: "ic_flash_on")!.tinted(with: UIColor.white)!.cgImage!,
dimmedIconImage: UIImage(named: "ic_flash_on")!.tinted(with: UIColor.gray)!.cgImage!)

let model2 = ProcessIndicatorModel(limitNumber: 40,
let model2 = ProcessIndicatorModel(valueRange: -40...40,
normalIconImage: UIImage(named: "settings")!.tinted(with: UIColor.white)!.cgImage!,
dimmedIconImage: UIImage(named: "settings")!.tinted(with: UIColor.gray)!.cgImage!)

let model3 = ProcessIndicatorModel(limitNumber: 40,
let model3 = ProcessIndicatorModel(valueRange: -50...50,
normalIconImage: UIImage(named: "ic_camera_front")!.tinted(with: UIColor.white)!.cgImage!,
dimmedIconImage: UIImage(named: "ic_camera_front")!.tinted(with: UIColor.gray)!.cgImage!)

Expand Down
32 changes: 17 additions & 15 deletions Inchworm/Source/Inchworm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,21 @@ public struct ProcessIndicatorModel {
var limitNumber = 0
var normalIconImage: CGImage?
var dimmedIconImage: CGImage?
var sliderValueRangeType: SliderValueRangeType = .bilateral

public init(limitNumber: Int, normalIconImage: CGImage?, dimmedIconImage: CGImage?) {
self.limitNumber = limitNumber
public init(valueRange: ClosedRange<Int>, normalIconImage: CGImage?, dimmedIconImage: CGImage?) {
guard abs(valueRange.lowerBound) == abs(valueRange.upperBound) || valueRange.lowerBound == 0 else {
fatalError("InchWorm only supports ranges like [0, 100] or [-100, 100]")
}
self.normalIconImage = normalIconImage
self.dimmedIconImage = dimmedIconImage
self.limitNumber = valueRange.upperBound

if abs(valueRange.lowerBound) == abs(valueRange.upperBound) {
sliderValueRangeType = .bilateral
} else {
sliderValueRangeType = .unilateral
}
}
}

Expand All @@ -27,15 +37,10 @@ public func createSlider(config: Config = Config(),
frame: CGRect,
processIndicatorModels: [ProcessIndicatorModel],
activeIndex: Int) -> Slider {
let board: Slider = Slider(config: config, frame: frame)

processIndicatorModels.forEach {
board.addIndicatorWith(limitNumber: $0.limitNumber, normalIconImage: $0.normalIconImage, dimmedIconImage: $0.dimmedIconImage)
}

board.setActiveIndicatorIndex(activeIndex)

return board
return Slider(config: config,
frame: frame,
processIndicatorModels: processIndicatorModels,
activeIndex: activeIndex)
}

public struct Config {
Expand All @@ -44,11 +49,8 @@ public struct Config {
public var slideRulerSpan: CGFloat = 50
public var spaceBetweenIndicatorAndSlideRule: CGFloat = 10
public var forceAlignCenterFeedback = true
public var sliderValueRangeType: SliderValueRangeType = .bilateral

public init() {

}
public init() {}
}

public enum SliderOrientation: Int {
Expand Down
19 changes: 13 additions & 6 deletions Inchworm/Source/ProcessIndicatorContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,15 @@ class ProcessIndicatorContainer: UIView {
}
}

func addIndicatorWith(limitNumber: Int, normalIconImage: CGImage?, dimmedIconImage: CGImage?) {
let indicatorView = ProcessIndicatorView(frame: CGRect(x: 0, y: 0, width: iconLength, height: iconLength), limitNumber: limitNumber, normalIconImage: normalIconImage, dimmedIconImage: dimmedIconImage)
func addIndicatorWith(limitNumber: Int,
sliderValueRangeType: SliderValueRangeType,
normalIconImage: CGImage?,
dimmedIconImage: CGImage?) {
let indicatorView = ProcessIndicatorView(frame: CGRect(x: 0, y: 0, width: iconLength, height: iconLength),
limitNumber: limitNumber,
sliderValueRangeType: sliderValueRangeType,
normalIconImage: normalIconImage,
dimmedIconImage: dimmedIconImage)
indicatorView.delegate = self
indicatorView.index = progressIndicatorViewList.count

Expand Down Expand Up @@ -166,22 +173,22 @@ extension ProcessIndicatorContainer: UIScrollViewDelegate {

guard let processIndicatorView = getActiveIndicator() else { return }
if processIndicatorView.status == .editingSelf {
self.didActive(processIndicatorView.progress)
didActive(processIndicatorView.progress)
}
}
}

extension ProcessIndicatorContainer: ProcessIndicatorViewDelegate {
func didActive(_ processIndicatorView: ProcessIndicatorView) {
setActiveIndicatorIndex(processIndicatorView.index, animated: true)
self.didActive(processIndicatorView.progress)
didActive(processIndicatorView.progress)
}

func didTempReset(_ processIndicatorView: ProcessIndicatorView) {
self.didTempReset()
didTempReset()
}

func didRemoveTempReset(_ processIndicatorView: ProcessIndicatorView) {
self.didRemoveTempReset(processIndicatorView.progress)
didRemoveTempReset(processIndicatorView.progress)
}
}
8 changes: 7 additions & 1 deletion Inchworm/Source/ProcessIndicatorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class ProcessIndicatorView: UIView {
let minusTrackColorValue = UIColor(displayP3Red: 84.0 / 255.0, green: 84.0 / 255.0, blue: 84.0 / 255.0, alpha: 1)

var limitNumber = 30
var sliderValueRangeType: SliderValueRangeType = .bilateral
var normalIconImage: CGImage?
var dimmedIconImage: CGImage?
var index = 0
Expand Down Expand Up @@ -71,10 +72,15 @@ class ProcessIndicatorView: UIView {
}
}

init(frame: CGRect, limitNumber: Int = 30, normalIconImage: CGImage? = nil, dimmedIconImage: CGImage? = nil) {
init(frame: CGRect,
limitNumber: Int = 30,
sliderValueRangeType: SliderValueRangeType = .bilateral,
normalIconImage: CGImage? = nil,
dimmedIconImage: CGImage? = nil) {
super.init(frame: frame)

self.limitNumber = limitNumber
self.sliderValueRangeType = sliderValueRangeType
self.normalIconImage = normalIconImage
self.dimmedIconImage = dimmedIconImage

Expand Down
22 changes: 12 additions & 10 deletions Inchworm/Source/SlideRuler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class SlideRuler: UIView {
let scrollRulerView = UIScrollView()
let dotWidth: CGFloat = 6
var sliderOffsetRatio: CGFloat = 0.5
var positionInfoProvider: SlideRulerPositionHelper
var positionInfoProvider: SlideRulerPositionHelper = BilateralTypeSlideRulerPositionHelper()

let scaleBarLayer: CAReplicatorLayer = {
var r = CAReplicatorLayer()
Expand All @@ -49,25 +49,26 @@ class SlideRuler: UIView {
}

init(frame: CGRect, sliderValueRangeType: SliderValueRangeType) {
super.init(frame: frame)
self.setPositionProvider(by: sliderValueRangeType)
setupUI()
}

required init?(coder: NSCoder) {
fatalError()
}

func setPositionProvider(by sliderValueRangeType: SliderValueRangeType) {
switch sliderValueRangeType {
case .bilateral:
self.positionInfoProvider = BilateralTypeSlideRulerPositionHelper()
case .unilateral:
self.positionInfoProvider = UnilateralTypeSlideRulerPositionHelper()
}

super.init(frame: frame)
self.positionInfoProvider.slideRuler = self
setupUI()
}

required init?(coder: NSCoder) {
fatalError()
}

private func setupUI() {
sliderOffsetRatio = positionInfoProvider.getInitialOffsetRatio()

setupSlider()
makeRuler()
makeCentralDot()
Expand All @@ -81,6 +82,7 @@ class SlideRuler: UIView {
}

public func setUIFrames() {
sliderOffsetRatio = positionInfoProvider.getInitialOffsetRatio()
scrollRulerView.frame = bounds

offsetValue = sliderOffsetRatio * scrollRulerView.frame.width
Expand Down
54 changes: 39 additions & 15 deletions Inchworm/Source/Slider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public protocol SliderDelegate {
}

public class Slider: UIView {

public var delegate: SliderDelegate?

var indicatorContainer: ProcessIndicatorContainer!
Expand All @@ -23,7 +23,7 @@ public class Slider: UIView {
- When orientation is horizontal, indicatorContainer is on the top, sliderRuler is on the bottom.
- When orientation is vertical, indicatorContainer is on the left, sliderRuler is on the right.
*/
*/
var baseContainer = UIView()

var config: Config!
Expand All @@ -34,12 +34,24 @@ public class Slider: UIView {
var containerVerticalWidthConstraint: NSLayoutConstraint!
var containerVerticalHeightConstraint: NSLayoutConstraint!

init(config: Config = Config(), frame: CGRect) {
init(config: Config = Config(),
frame: CGRect,
processIndicatorModels: [ProcessIndicatorModel],
activeIndex: Int) {
super.init(frame: frame)

self.config = config

createIndicatorContainer()

processIndicatorModels.forEach {
addIndicatorWith(limitNumber: $0.limitNumber,
sliderValueRangeType: $0.sliderValueRangeType,
normalIconImage: $0.normalIconImage,
dimmedIconImage: $0.dimmedIconImage)
}

setActiveIndicatorIndex(activeIndex)
createSlideRuler()

baseContainer.frame = bounds
Expand Down Expand Up @@ -76,12 +88,15 @@ public class Slider: UIView {
}

func createSlideRuler() {
let sliderFrame = CGRect(x: 0, y: baseContainer.frame.height / 2, width: baseContainer.frame.width, height: baseContainer.frame.height - config.slideRulerSpan)
slideRuler = SlideRuler(frame: sliderFrame, sliderValueRangeType: config.sliderValueRangeType)
let sliderFrame = CGRect(x: 0, y: baseContainer.frame.height / 2, width: baseContainer.frame.width, height: baseContainer.frame.height - config.slideRulerSpan)
let activeIndex = indicatorContainer.activeIndicatorIndex
let indicator = indicatorContainer.progressIndicatorViewList[activeIndex]

slideRuler = SlideRuler(frame: sliderFrame, sliderValueRangeType: indicator.sliderValueRangeType)
slideRuler.delegate = self
slideRuler.forceAlignCenterFeedback = config.forceAlignCenterFeedback
}

func initialAutolayoutConstraint() {
baseContainer.translatesAutoresizingMaskIntoConstraints = false
indicatorContainer.translatesAutoresizingMaskIntoConstraints = false
Expand All @@ -96,7 +111,7 @@ public class Slider: UIView {
NSLayoutConstraint.activate([
baseContainer.centerXAnchor.constraint(equalTo: centerXAnchor),
baseContainer.centerYAnchor.constraint(equalTo: centerYAnchor),

indicatorContainer.leadingAnchor.constraint(equalTo: baseContainer.leadingAnchor),
indicatorContainer.trailingAnchor.constraint(equalTo: baseContainer.trailingAnchor),
indicatorContainer.topAnchor.constraint(equalTo: baseContainer.topAnchor),
Expand All @@ -121,35 +136,44 @@ public class Slider: UIView {
containerHorizontalWidthConstraint,
containerHoritontalHeightConstraint
])

baseContainer.transform = .identity
} else {
NSLayoutConstraint.deactivate([
containerHorizontalWidthConstraint,
containerHoritontalHeightConstraint
])

NSLayoutConstraint.activate([
containerVerticalWidthConstraint,
containerVerticalHeightConstraint
])

baseContainer.transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 2)
}
}

func addIndicatorWith(limitNumber: Int, normalIconImage: CGImage?, dimmedIconImage: CGImage?) {
indicatorContainer.addIndicatorWith(limitNumber: limitNumber, normalIconImage: normalIconImage, dimmedIconImage: dimmedIconImage)
func addIndicatorWith(limitNumber: Int,
sliderValueRangeType: SliderValueRangeType,
normalIconImage: CGImage?,
dimmedIconImage: CGImage?) {
indicatorContainer.addIndicatorWith(limitNumber: limitNumber,
sliderValueRangeType: sliderValueRangeType,
normalIconImage: normalIconImage,
dimmedIconImage: dimmedIconImage)
}

func setActiveIndicatorIndex(_ index: Int = 0) {
indicatorContainer.setActiveIndicatorIndex(index)
}

func setSlideRulerBy(progress: Float) {
slideRuler.handleRemoveTempResetWith(progress: progress)

let activeIndex = indicatorContainer.activeIndicatorIndex
let indicator = indicatorContainer.progressIndicatorViewList[activeIndex]
slideRuler.setPositionProvider(by: indicator.sliderValueRangeType)
slideRuler.setUIFrames()
slideRuler.handleRemoveTempResetWith(progress: progress)

delegate?.didGetOffsetRatio(self, activeIndicatorIndex: activeIndex, offsetRatio: progress)
}
}
Expand Down

0 comments on commit 8722b6d

Please sign in to comment.