Skip to content

Commit 081b582

Browse files
authored
Introduce StickyHeaderView in UIScrollView (#4)
* 🌲 Update * Add comment
1 parent c8bd643 commit 081b582

6 files changed

Lines changed: 295 additions & 7 deletions

File tree

ScrollEdgeControl-Demo/Book.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,12 @@ let book = Book(title: "MyBook") {
6363
)
6464
}
6565
}
66+
67+
BookNavigationLink(title: "Sticky") {
68+
69+
BookPush(title: "Vertical") {
70+
DemoVerticalStickyHeaderViewController()
71+
}
72+
73+
}
6674
}

ScrollEdgeControl-Demo/Components.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
@testable import ScrollEdgeControl
22
import MondrianLayout
33
import UIKit
4+
import CompositionKit
45

56
enum Components {
67

@@ -61,7 +62,7 @@ enum Components {
6162
// Fallback on earlier versions
6263
}
6364

64-
return MondrianLayout.AnyView.init { _ in
65+
return AnyView.init { _ in
6566
view
6667
.viewBlock
6768
.padding(4)
@@ -74,7 +75,7 @@ enum Components {
7475
button.setTitle(title, for: .normal)
7576
button.onTap(onTap)
7677

77-
return MondrianLayout.AnyView.init { view in
78+
return AnyView.init { view in
7879
VStackBlock {
7980
button
8081
.viewBlock
@@ -100,7 +101,7 @@ enum Components {
100101
decreaseButton.setTitle("-", for: .normal)
101102
decreaseButton.onTap(onDecreased)
102103

103-
return MondrianLayout.AnyView.init { view in
104+
return AnyView.init { view in
104105
VStackBlock {
105106
titleLabel
106107
HStackBlock(spacing: 4) {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import Foundation
2+
import UIKit
3+
import MondrianLayout
4+
import StorybookUI
5+
import StorybookKit
6+
import StackScrollView
7+
import ScrollEdgeControl
8+
import CompositionKit
9+
10+
final class DemoVerticalStickyHeaderViewController: UIViewController {
11+
12+
override func viewDidLoad() {
13+
super.viewDidLoad()
14+
15+
let headerView = HeaderView()
16+
17+
let stickyView = ScrollStickyVerticalHeaderView()
18+
19+
view.backgroundColor = .white
20+
21+
let scrollView = ScrollableContainerView()
22+
stickyView.setContent(headerView)
23+
24+
let contentView = UIView()
25+
contentView.backgroundColor = .systemYellow.withAlphaComponent(0.8)
26+
27+
contentView.mondrian.layout.height(300).activate()
28+
29+
scrollView.setContent(contentView)
30+
scrollView.addSubview(stickyView)
31+
scrollView.alwaysBounceVertical = true
32+
33+
Mondrian.buildSubviews(on: view) {
34+
ZStackBlock(alignment: .attach(.all)) {
35+
scrollView.viewBlock
36+
}
37+
}
38+
39+
}
40+
41+
private final class HeaderView: CodeBasedView, ScrollStickyContentType {
42+
43+
private let label = UILabel()
44+
45+
init() {
46+
47+
super.init(frame: .null)
48+
49+
backgroundColor = .systemBlue.withAlphaComponent(0.8)
50+
// mondrian.layout.height(100).activate()
51+
52+
let button = UIButton(type: .system)
53+
button.setTitle("Update", for: .normal)
54+
button.addTarget(self, action: #selector(updateText), for: .primaryActionTriggered)
55+
56+
label.numberOfLines = 0
57+
58+
Mondrian.buildSubviews(on: self) {
59+
60+
VStackBlock {
61+
StackingSpacer(minLength: 100)
62+
button
63+
label
64+
.viewBlock
65+
.padding(16)
66+
}
67+
}
68+
}
69+
70+
@objc private func updateText() {
71+
label.text = BookGenerator.loremIpsum(length: [10, 50, 100].randomElement()!)
72+
requestUpdateSizing()
73+
}
74+
75+
}
76+
77+
}

ScrollEdgeControl.xcodeproj/project.pbxproj

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
4B66215F27515AD100509356 /* TypedTextAttributes in Frameworks */ = {isa = PBXBuildFile; productRef = 4B66215E27515AD100509356 /* TypedTextAttributes */; };
2424
4B66216227515B1900509356 /* StorybookKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4B66216127515B1900509356 /* StorybookKit */; };
2525
4B66216427515B1900509356 /* StorybookUI in Frameworks */ = {isa = PBXBuildFile; productRef = 4B66216327515B1900509356 /* StorybookUI */; };
26-
4B6ABA2A2796E28600D9BFC6 /* CompositionKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4B6ABA292796E28600D9BFC6 /* CompositionKit */; };
26+
4B98480627F31E8300ED3FA9 /* ScrollStickyVerticalHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98480527F31E8300ED3FA9 /* ScrollStickyVerticalHeaderView.swift */; };
27+
4B98480927F33C5200ED3FA9 /* CompositionKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4B98480827F33C5200ED3FA9 /* CompositionKit */; };
28+
4B98480B27F33CB000ED3FA9 /* DemoVerticalStickyHeaderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98480A27F33CB000ED3FA9 /* DemoVerticalStickyHeaderViewController.swift */; };
2729
4BC42830275157320047A850 /* ScrollEdgeControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC4282F275157320047A850 /* ScrollEdgeControl.swift */; };
2830
4BC42833275157C00047A850 /* Advance in Frameworks */ = {isa = PBXBuildFile; productRef = 4BC42832275157C00047A850 /* Advance */; };
2931
4BC4283B275158240047A850 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC4283A275158240047A850 /* AppDelegate.swift */; };
@@ -68,6 +70,8 @@
6870
4B5E52D627515C900075AE52 /* BookContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookContainerViewController.swift; sourceTree = "<group>"; };
6971
4B5E52DF27515DC30075AE52 /* ScrollEdgeActivityIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollEdgeActivityIndicatorView.swift; sourceTree = "<group>"; };
7072
4B5E52E127515DE30075AE52 /* DonutsIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DonutsIndicatorView.swift; sourceTree = "<group>"; };
73+
4B98480527F31E8300ED3FA9 /* ScrollStickyVerticalHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollStickyVerticalHeaderView.swift; sourceTree = "<group>"; };
74+
4B98480A27F33CB000ED3FA9 /* DemoVerticalStickyHeaderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoVerticalStickyHeaderViewController.swift; sourceTree = "<group>"; };
7175
4BC42825275157080047A850 /* ScrollEdgeControl.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ScrollEdgeControl.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7276
4BC4282F275157320047A850 /* ScrollEdgeControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollEdgeControl.swift; sourceTree = "<group>"; };
7377
4BC42838275158240047A850 /* ScrollEdgeControl-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ScrollEdgeControl-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -82,7 +86,6 @@
8286
isa = PBXFrameworksBuildPhase;
8387
buildActionMask = 2147483647;
8488
files = (
85-
4B6ABA2A2796E28600D9BFC6 /* CompositionKit in Frameworks */,
8689
4BC42833275157C00047A850 /* Advance in Frameworks */,
8790
);
8891
runOnlyForDeploymentPostprocessing = 0;
@@ -97,6 +100,7 @@
97100
4BC42852275158F80047A850 /* RxRelay in Frameworks */,
98101
4B5E52D827515CF20075AE52 /* ScrollEdgeControl.framework in Frameworks */,
99102
4B39D04F2752740100D013F4 /* StackScrollView in Frameworks */,
103+
4B98480927F33C5200ED3FA9 /* CompositionKit in Frameworks */,
100104
4BC42850275158F80047A850 /* RxCocoa in Frameworks */,
101105
4B5E52E527515E0A0075AE52 /* MondrianLayout in Frameworks */,
102106
4B66216427515B1900509356 /* StorybookUI in Frameworks */,
@@ -110,6 +114,7 @@
110114
isa = PBXGroup;
111115
children = (
112116
4BC4282F275157320047A850 /* ScrollEdgeControl.swift */,
117+
4B98480527F31E8300ED3FA9 /* ScrollStickyVerticalHeaderView.swift */,
113118
);
114119
path = Core;
115120
sourceTree = "<group>";
@@ -123,12 +128,20 @@
123128
path = Library;
124129
sourceTree = "<group>";
125130
};
131+
4B98480727F33C5200ED3FA9 /* Frameworks */ = {
132+
isa = PBXGroup;
133+
children = (
134+
);
135+
name = Frameworks;
136+
sourceTree = "<group>";
137+
};
126138
4BC4281B275157080047A850 = {
127139
isa = PBXGroup;
128140
children = (
129141
4BC42827275157080047A850 /* ScrollEdgeControl */,
130142
4BC42839275158240047A850 /* ScrollEdgeControl-Demo */,
131143
4BC42826275157080047A850 /* Products */,
144+
4B98480727F33C5200ED3FA9 /* Frameworks */,
132145
);
133146
sourceTree = "<group>";
134147
};
@@ -156,6 +169,7 @@
156169
4B39D05427528A1900D013F4 /* DebuggingRefreshIndicatorView.swift */,
157170
4B39D0502752745C00D013F4 /* DemoHorizontalViewController.swift */,
158171
4B39D0522752746600D013F4 /* DemoVerticalViewController.swift */,
172+
4B98480A27F33CB000ED3FA9 /* DemoVerticalStickyHeaderViewController.swift */,
159173
4BC4283A275158240047A850 /* AppDelegate.swift */,
160174
4B5E52D427515C830075AE52 /* Book.swift */,
161175
4B5E52D627515C900075AE52 /* BookContainerViewController.swift */,
@@ -197,7 +211,6 @@
197211
name = ScrollEdgeControl;
198212
packageProductDependencies = (
199213
4BC42832275157C00047A850 /* Advance */,
200-
4B6ABA292796E28600D9BFC6 /* CompositionKit */,
201214
);
202215
productName = ScrollEdgeControl;
203216
productReference = 4BC42825275157080047A850 /* ScrollEdgeControl.framework */;
@@ -227,6 +240,7 @@
227240
4B66216327515B1900509356 /* StorybookUI */,
228241
4B5E52E427515E0A0075AE52 /* MondrianLayout */,
229242
4B39D04E2752740100D013F4 /* StackScrollView */,
243+
4B98480827F33C5200ED3FA9 /* CompositionKit */,
230244
);
231245
productName = "ScrollEdgeControl-Demo";
232246
productReference = 4BC42838275158240047A850 /* ScrollEdgeControl-Demo.app */;
@@ -304,6 +318,7 @@
304318
files = (
305319
4BC42830275157320047A850 /* ScrollEdgeControl.swift in Sources */,
306320
4B39D05F2753948300D013F4 /* ScrollEdgeActivityIndicatorView.swift in Sources */,
321+
4B98480627F31E8300ED3FA9 /* ScrollStickyVerticalHeaderView.swift in Sources */,
307322
4B39D05E2753942F00D013F4 /* DonutsIndicatorView.swift in Sources */,
308323
);
309324
runOnlyForDeploymentPostprocessing = 0;
@@ -320,6 +335,7 @@
320335
4B39D05727528ACD00D013F4 /* Components.swift in Sources */,
321336
4B39D0512752745C00D013F4 /* DemoHorizontalViewController.swift in Sources */,
322337
4B39D05527528A1900D013F4 /* DebuggingRefreshIndicatorView.swift in Sources */,
338+
4B98480B27F33CB000ED3FA9 /* DemoVerticalStickyHeaderViewController.swift in Sources */,
323339
);
324340
runOnlyForDeploymentPostprocessing = 0;
325341
};
@@ -692,7 +708,7 @@
692708
package = 4B66216027515B1800509356 /* XCRemoteSwiftPackageReference "Storybook-ios" */;
693709
productName = StorybookUI;
694710
};
695-
4B6ABA292796E28600D9BFC6 /* CompositionKit */ = {
711+
4B98480827F33C5200ED3FA9 /* CompositionKit */ = {
696712
isa = XCSwiftPackageProductDependency;
697713
package = 4B6ABA282796E28600D9BFC6 /* XCRemoteSwiftPackageReference "CompositionKit" */;
698714
productName = CompositionKit;

ScrollEdgeControl.xcodeproj/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@
2222
</BreakpointActionProxy>
2323
</Actions>
2424
<Locations>
25+
<Location
26+
uuid = "C9CE3BF8-7173-4116-B160-3D92C310E179 - ca8a62ba89de0751"
27+
shouldBeEnabled = "Yes"
28+
ignoreCount = "0"
29+
continueAfterRunningActions = "No"
30+
symbolName = "UIKit.UIApplicationMain(Swift.Int32, Swift.Optional&lt;Swift.UnsafeMutablePointer&lt;Swift.UnsafeMutablePointer&lt;Swift.Int8&gt;&gt;&gt;, Swift.Optional&lt;Swift.String&gt;, Swift.Optional&lt;Swift.String&gt;) -&gt; Swift.Int32"
31+
moduleName = "libswiftUIKit.dylib"
32+
usesParentBreakpointCondition = "Yes"
33+
offsetFromSymbolStart = "0">
34+
</Location>
35+
<Location
36+
uuid = "C9CE3BF8-7173-4116-B160-3D92C310E179 - dc2f8c5e001177f0"
37+
shouldBeEnabled = "Yes"
38+
ignoreCount = "0"
39+
continueAfterRunningActions = "No"
40+
symbolName = "UIApplicationMain"
41+
moduleName = "UIKitCore"
42+
usesParentBreakpointCondition = "Yes"
43+
offsetFromSymbolStart = "0">
44+
</Location>
2545
</Locations>
2646
</BreakpointContent>
2747
</BreakpointProxy>

0 commit comments

Comments
 (0)