Skip to content

Commit c4d9207

Browse files
add tap gesture recognizer to sections (#38)
1 parent e8b383b commit c4d9207

19 files changed

+216
-124
lines changed

Example/LanguageExample/LanguageExample.storyboard

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3-
<device id="retina6_1" orientation="portrait">
4-
<adaptation id="fullscreen"/>
5-
</device>
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+
<device id="retina6_1" orientation="portrait" appearance="light"/>
64
<dependencies>
75
<deployment identifier="iOS"/>
8-
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
6+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
97
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
108
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
119
</dependencies>
@@ -46,6 +44,7 @@
4644
</userDefinedRuntimeAttributes>
4745
<connections>
4846
<outlet property="dataSource" destination="0wb-Cb-WUL" id="uad-jp-Zwy"/>
47+
<outlet property="delegate" destination="0wb-Cb-WUL" id="SS4-fz-to2"/>
4948
</connections>
5049
</view>
5150
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Aqx-CJ-eFd" customClass="LanguageExampleProgressView" customModule="MultiProgressViewExample" customModuleProvider="target">
@@ -73,6 +72,7 @@
7372
</userDefinedRuntimeAttributes>
7473
<connections>
7574
<outlet property="dataSource" destination="0wb-Cb-WUL" id="oxv-8k-Fp4"/>
75+
<outlet property="delegate" destination="0wb-Cb-WUL" id="gMg-bN-CTQ"/>
7676
</connections>
7777
</view>
7878
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="CWo-Hk-zOo" customClass="LanguageExampleProgressView" customModule="MultiProgressViewExample" customModuleProvider="target">
@@ -100,6 +100,7 @@
100100
</userDefinedRuntimeAttributes>
101101
<connections>
102102
<outlet property="dataSource" destination="0wb-Cb-WUL" id="Fk9-lG-EyR"/>
103+
<outlet property="delegate" destination="0wb-Cb-WUL" id="WJC-E7-xgA"/>
103104
</connections>
104105
</view>
105106
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yei-zF-C21" customClass="LanguageExampleProgressView" customModule="MultiProgressViewExample" customModuleProvider="target">
@@ -127,6 +128,7 @@
127128
</userDefinedRuntimeAttributes>
128129
<connections>
129130
<outlet property="dataSource" destination="0wb-Cb-WUL" id="mmq-QZ-Qva"/>
131+
<outlet property="delegate" destination="0wb-Cb-WUL" id="MHC-iU-0sI"/>
130132
</connections>
131133
</view>
132134
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TJ5-4x-gVc" customClass="LanguageExampleProgressView" customModule="MultiProgressViewExample" customModuleProvider="target">
@@ -154,6 +156,7 @@
154156
</userDefinedRuntimeAttributes>
155157
<connections>
156158
<outlet property="dataSource" destination="0wb-Cb-WUL" id="tIM-3R-UK6"/>
159+
<outlet property="delegate" destination="0wb-Cb-WUL" id="5kH-zF-2Nw"/>
157160
</connections>
158161
</view>
159162
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Languages" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="s77-Sh-QnM">

Example/LanguageExample/LanguageExampleViewController.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class LanguageExampleViewController: UIViewController {
7676
}
7777
}
7878

79-
//MARK: - Data Source
79+
//MARK: - MultiProgressViewDataSource
8080

8181
extension LanguageExampleViewController: MultiProgressViewDataSource {
8282
func numberOfSections(in progressView: MultiProgressView) -> Int {
@@ -98,3 +98,17 @@ extension LanguageExampleViewController: MultiProgressViewDataSource {
9898
return sectionView
9999
}
100100
}
101+
102+
// MARK: - MultiProgressViewDelegate
103+
104+
extension LanguageExampleViewController: MultiProgressViewDelegate {
105+
106+
func progressView(_ progressView: MultiProgressView, didTapSectionAt index: Int) {
107+
for (progressViewIndex, view) in progressViews.enumerated() {
108+
if view === progressView {
109+
print("Tapped progressView \(progressViewIndex) at section \(index)")
110+
break
111+
}
112+
}
113+
}
114+
}

Example/StorageExample/StorageExampleViewController.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class StorageExampleViewController: UIViewController {
108108
paddingRight: padding,
109109
height: progressViewHeight)
110110
progressView.dataSource = self
111+
progressView.delegate = self
111112
}
112113

113114
private func setupStackView() {
@@ -190,7 +191,7 @@ class StorageExampleViewController: UIViewController {
190191
}
191192
}
192193

193-
//MARK: - Data Source
194+
//MARK: - MultiProgressViewDataSource
194195

195196
extension StorageExampleViewController: MultiProgressViewDataSource {
196197
public func numberOfSections(in progressBar: MultiProgressView) -> Int {
@@ -203,3 +204,12 @@ extension StorageExampleViewController: MultiProgressViewDataSource {
203204
return bar
204205
}
205206
}
207+
208+
// MARK: - MultiProgressViewDelegate
209+
210+
extension StorageExampleViewController: MultiProgressViewDelegate {
211+
212+
func progressView(_ progressView: MultiProgressView, didTapSectionAt index: Int) {
213+
print("Tapped section \(index)")
214+
}
215+
}

MultiProgressView.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
/* Begin PBXBuildFile section */
1010
0F33B13D1BCF84BE40120FC5 /* Pods_MultiProgressViewTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E594A8658F530A5575039A4 /* Pods_MultiProgressViewTests.framework */; };
1111
AD0BF7FC2273C0DE0081722E /* CodingLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0BF7FB2273C0DE0081722E /* CodingLanguage.swift */; };
12+
AD20667B238F5DAE00CAA61D /* MockProgressViewSectionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD20667A238F5DAE00CAA61D /* MockProgressViewSectionDelegate.swift */; };
13+
AD20667D238F5EEB00CAA61D /* TestableTapGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD20667C238F5EEB00CAA61D /* TestableTapGestureRecognizer.swift */; };
14+
AD20667F238F8CC200CAA61D /* MockProgressViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD20667E238F8CC200CAA61D /* MockProgressViewDelegate.swift */; };
1215
AD3B3270225146B9006E0F14 /* MultiProgressView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD501273224B0E1600370157 /* MultiProgressView.framework */; };
1316
AD3B329B22514B4E006E0F14 /* MockLayoutProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD3B329122514B4E006E0F14 /* MockLayoutProvider.swift */; };
1417
AD3B329C22514B4E006E0F14 /* MockMultiProgressViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD3B329222514B4E006E0F14 /* MockMultiProgressViewDataSource.swift */; };
@@ -75,6 +78,9 @@
7578
4E594A8658F530A5575039A4 /* Pods_MultiProgressViewTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MultiProgressViewTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7679
7D3DCEE1FF2C5A9C79322BC2 /* Pods-MultiProgressViewTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MultiProgressViewTests.release.xcconfig"; path = "Target Support Files/Pods-MultiProgressViewTests/Pods-MultiProgressViewTests.release.xcconfig"; sourceTree = "<group>"; };
7780
AD0BF7FB2273C0DE0081722E /* CodingLanguage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodingLanguage.swift; sourceTree = "<group>"; };
81+
AD20667A238F5DAE00CAA61D /* MockProgressViewSectionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProgressViewSectionDelegate.swift; sourceTree = "<group>"; };
82+
AD20667C238F5EEB00CAA61D /* TestableTapGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableTapGestureRecognizer.swift; sourceTree = "<group>"; };
83+
AD20667E238F8CC200CAA61D /* MockProgressViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProgressViewDelegate.swift; sourceTree = "<group>"; };
7884
AD3B326B225146B9006E0F14 /* MultiProgressViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MultiProgressViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
7985
AD3B32882251488A006E0F14 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/iOS/Nimble.framework; sourceTree = "<group>"; };
8086
AD3B32892251488A006E0F14 /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/iOS/Quick.framework; sourceTree = "<group>"; };
@@ -168,6 +174,8 @@
168174
children = (
169175
AD3B329122514B4E006E0F14 /* MockLayoutProvider.swift */,
170176
AD3B329222514B4E006E0F14 /* MockMultiProgressViewDataSource.swift */,
177+
AD20667E238F8CC200CAA61D /* MockProgressViewDelegate.swift */,
178+
AD20667A238F5DAE00CAA61D /* MockProgressViewSectionDelegate.swift */,
171179
);
172180
path = Mocks;
173181
sourceTree = "<group>";
@@ -187,6 +195,7 @@
187195
children = (
188196
AD3B329922514B4E006E0F14 /* TestableProgressViewSection.swift */,
189197
AD3B329A22514B4E006E0F14 /* TestableMultiProgressView.swift */,
198+
AD20667C238F5EEB00CAA61D /* TestableTapGestureRecognizer.swift */,
190199
);
191200
path = Testables;
192201
sourceTree = "<group>";
@@ -529,10 +538,13 @@
529538
isa = PBXSourcesBuildPhase;
530539
buildActionMask = 2147483647;
531540
files = (
541+
AD20667F238F8CC200CAA61D /* MockProgressViewDelegate.swift in Sources */,
532542
AD3B329E22514B4E006E0F14 /* ProgressViewSectionSpec.swift in Sources */,
533543
AD3B329C22514B4E006E0F14 /* MockMultiProgressViewDataSource.swift in Sources */,
544+
AD20667B238F5DAE00CAA61D /* MockProgressViewSectionDelegate.swift in Sources */,
534545
AD3B329D22514B4E006E0F14 /* MultiProgressViewSpec.swift in Sources */,
535546
AD3B329B22514B4E006E0F14 /* MockLayoutProvider.swift in Sources */,
547+
AD20667D238F5EEB00CAA61D /* TestableTapGestureRecognizer.swift in Sources */,
536548
AD3B329F22514B4E006E0F14 /* LayoutProviderSpec.swift in Sources */,
537549
AD3B32A222514B4E006E0F14 /* TestableMultiProgressView.swift in Sources */,
538550
AD3B32A122514B4E006E0F14 /* TestableProgressViewSection.swift in Sources */,

Sources/MultiProgressView/AlignmentType.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
//
2-
// AlignmentType.swift
3-
// MultiProgressView
4-
//
5-
// Created by Mac Gallagher on 6/19/18.
6-
// Copyright © 2018 Mac Gallagher. All rights reserved.
7-
//
8-
91
public enum AlignmentType {
102
case left
113
case topLeft

Sources/MultiProgressView/LayoutProvider.swift

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
//
2-
// LayoutProvider.swift
3-
// MultiProgressView
4-
//
5-
// Created by Mac Gallagher on 3/5/19.
6-
// Copyright © 2019 Mac Gallagher. All rights reserved.
7-
//
8-
91
import UIKit
102

113
protocol LayoutProvidable {
@@ -81,9 +73,9 @@ struct LayoutProvider: LayoutProvidable {
8173
let size = CGSize(width: width, height: trackBounds.height)
8274

8375
var origin: CGPoint = trackBounds.origin
84-
for index in 0..<progressView.progressViewSections.count {
76+
for (bar, index) in progressView.progressViewSections {
8577
if index < section {
86-
origin.x += progressView.progressViewSections[index].frame.width
78+
origin.x += bar.frame.width
8779
}
8880
}
8981

Sources/MultiProgressView/LineCapType.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
//
2-
// LineCapType.swift
3-
// MultiProgressView
4-
//
5-
// Created by Mac Gallagher on 12/25/18.
6-
// Copyright © 2018 Mac Gallagher. All rights reserved.
7-
//
8-
91
public enum LineCapType {
102
case round
113
case butt

Sources/MultiProgressView/MultiProgressView.swift

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
//
2-
// MultiProgressView.swift
3-
// MultiProgressView
4-
//
5-
// Created by Mac Gallagher on 6/15/18.
6-
// Copyright © 2018 Mac Gallagher. All rights reserved.
7-
//
8-
91
import UIKit
102

113
@objc public protocol MultiProgressViewDataSource: class {
@@ -14,6 +6,10 @@ import UIKit
146
viewForSection section: Int) -> ProgressViewSection
157
}
168

9+
@objc public protocol MultiProgressViewDelegate: class {
10+
@objc optional func progressView(_ progressView: MultiProgressView, didTapSectionAt index: Int)
11+
}
12+
1713
@IBDesignable
1814
open class MultiProgressView: UIView {
1915

@@ -23,6 +19,8 @@ open class MultiProgressView: UIView {
2319
}
2420
}
2521

22+
@IBOutlet public weak var delegate: MultiProgressViewDelegate?
23+
2624
@IBInspectable public var cornerRadius: CGFloat = 0 {
2725
didSet {
2826
updateCornerRadius()
@@ -107,7 +105,9 @@ open class MultiProgressView: UIView {
107105
return view
108106
}()
109107

110-
var progressViewSections: [ProgressViewSection] = []
108+
/// A map containing the sections of the progress view.
109+
/// The key is the section and the value is the section's index in the progress view.
110+
var progressViewSections: [ProgressViewSection: Int] = [:]
111111

112112
private var numberOfSections: Int = 0
113113
private var currentProgress: [Float] = []
@@ -158,7 +158,7 @@ open class MultiProgressView: UIView {
158158
}
159159

160160
private func layoutSections() {
161-
for (index, section) in progressViewSections.enumerated() {
161+
for (section, index) in progressViewSections {
162162
section.frame = layoutProvider.sectionFrame(self, index)
163163
track.bringSubviewToFront(section)
164164
}
@@ -175,7 +175,7 @@ open class MultiProgressView: UIView {
175175
guard let dataSource = dataSource else { return }
176176
numberOfSections = dataSource.numberOfSections(in: self)
177177

178-
progressViewSections.forEach { $0.removeFromSuperview() }
178+
progressViewSections.keys.forEach { $0.removeFromSuperview() }
179179
progressViewSections.removeAll()
180180
currentProgress.removeAll()
181181

@@ -187,7 +187,8 @@ open class MultiProgressView: UIView {
187187
private func configureSection(withDataSource dataSource: MultiProgressViewDataSource,
188188
_ section: Int) {
189189
let bar = dataSource.progressView(self, viewForSection: section)
190-
progressViewSections.insert(bar, at: section)
190+
bar.delegate = self
191+
progressViewSections[bar] = section
191192
track.addSubview(bar)
192193
currentProgress.insert(0, at: section)
193194
}
@@ -224,3 +225,14 @@ open class MultiProgressView: UIView {
224225
}
225226
}
226227
}
228+
229+
// MARK: - ProgressViewSectionDelegate
230+
231+
extension MultiProgressView: ProgressViewSectionDelegate {
232+
233+
func didTapSection(_ section: ProgressViewSection) {
234+
if let index = progressViewSections[section] {
235+
delegate?.progressView?(self, didTapSectionAt: index)
236+
}
237+
}
238+
}

Sources/MultiProgressView/ProgressViewSection.swift

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
//
2-
// ProgressViewSection.swift
3-
// MultiProgressView
4-
//
5-
// Created by Mac Gallagher on 6/15/18.
6-
// Copyright © 2018 Mac Gallagher. All rights reserved.
7-
//
8-
91
import UIKit
102

3+
protocol ProgressViewSectionDelegate: class {
4+
func didTapSection(_ section: ProgressViewSection)
5+
}
6+
117
open class ProgressViewSection: UIView {
128

139
public var titleLabel: UILabel {
@@ -32,6 +28,15 @@ open class ProgressViewSection: UIView {
3228
return sectionImageView
3329
}
3430

31+
var tapGestureRecognizer: UITapGestureRecognizer {
32+
return tapRecognizer
33+
}
34+
35+
private lazy var tapRecognizer = UITapGestureRecognizer(target: self,
36+
action: #selector(didTap))
37+
38+
weak var delegate: ProgressViewSectionDelegate?
39+
3540
private var sectionImageView: UIImageView = UIImageView()
3641

3742
private var layoutProvider: LayoutProvidable.Type = LayoutProvider.self
@@ -58,6 +63,13 @@ open class ProgressViewSection: UIView {
5863
layer.masksToBounds = true
5964
addSubview(sectionImageView)
6065
addSubview(sectionTitleLabel)
66+
addGestureRecognizer(tapGestureRecognizer)
67+
}
68+
69+
// MARK: - Tap handler
70+
71+
@objc func didTap() {
72+
delegate?.didTapSection(self)
6173
}
6274

6375
// MARK: - Layout

Tests/MultiProgressViewTests/Mocks/MockLayoutProvider.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
//
2-
// MockLayoutProvider.swift
3-
// MultiProgressViewTests
4-
//
5-
// Created by Mac Gallagher on 3/6/19.
6-
// Copyright © 2019 Mac Gallagher. All rights reserved.
7-
//
8-
91
@testable import MultiProgressView
102

113
struct MockLayoutProvider: LayoutProvidable {

Tests/MultiProgressViewTests/Mocks/MockMultiProgressViewDataSource.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
//
2-
// MockMultiProgressViewDataSource.swift
3-
// MultiProgressViewTests
4-
//
5-
// Created by Mac Gallagher on 3/1/19.
6-
// Copyright © 2019 Mac Gallagher. All rights reserved.
7-
//
8-
91
import MultiProgressView
102

113
class MockMultiProgressViewDataSource: MultiProgressViewDataSource {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@testable import MultiProgressView
2+
3+
class MockMultiProgressViewDelegate: MultiProgressViewDelegate {
4+
5+
var didTapSectionAtCalled: Bool = false
6+
var didTapSectionIndex: Int?
7+
8+
func progressView(_ progressView: MultiProgressView, didTapSectionAt index: Int) {
9+
didTapSectionAtCalled = true
10+
didTapSectionIndex = index
11+
}
12+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@testable import MultiProgressView
2+
3+
class MockProgressViewSectionDelegate: ProgressViewSectionDelegate {
4+
5+
var didTapSectionCalled: Bool = false
6+
func didTapSection(_ section: ProgressViewSection) {
7+
didTapSectionCalled = true
8+
}
9+
}

0 commit comments

Comments
 (0)