@@ -28,34 +28,121 @@ open class AutoScrollView: UIScrollView {
28
28
}
29
29
didSet {
30
30
if let contentView = contentView {
31
+ contentView. translatesAutoresizingMaskIntoConstraints = false
31
32
addSubview ( contentView)
32
33
updateContentViewConstraints ( )
33
34
}
34
35
}
35
36
}
36
37
fileprivate var contentViewConstraints : [ NSLayoutConstraint ] ?
37
38
39
+ /// This layout guide follows the `contentView` and honors the `horizontallyCompactContentWidth`
40
+ /// and `horizontallyRegularContentWidth` values.
41
+ public var contentViewLayoutGuide = UILayoutGuide ( )
42
+ private var contentViewLayoutGuideConstraints : [ NSLayoutConstraint ] = [ ]
43
+
44
+ /// This setting determines how the content should be laid out in a horizontally compact environment.
45
+ public var horizontallyCompactContentWidth : ContentWidth = . matchScrollViewWidth {
46
+ didSet {
47
+ guard horizontallyCompactContentWidth != oldValue else { return }
48
+
49
+ switch traitCollection. horizontalSizeClass {
50
+ case . compact: updateContentViewConstraints ( )
51
+ case . regular, . unspecified: break // no-op
52
+ @unknown default : break
53
+ }
54
+ }
55
+ }
56
+
57
+ /// This setting determines how the content should be laid out in a horizontally regular environment.
58
+ public var horizontallyRegularContentWidth : ContentWidth = . matchScrollViewWidth {
59
+ didSet {
60
+ guard horizontallyRegularContentWidth != oldValue else { return }
61
+
62
+ switch traitCollection. horizontalSizeClass {
63
+ case . regular: updateContentViewConstraints ( )
64
+ case . compact, . unspecified: break // no-op
65
+ @unknown default : break
66
+ }
67
+ }
68
+ }
69
+
38
70
override open var contentInset : UIEdgeInsets {
39
71
didSet {
40
72
updateContentViewConstraints ( )
41
73
}
42
74
}
43
75
44
76
fileprivate func updateContentViewConstraints( ) {
77
+ let contentViewFollowsReadableWidth : Bool
78
+ switch traitCollection. horizontalSizeClass {
79
+ case . compact:
80
+ switch horizontallyCompactContentWidth {
81
+ case . matchScrollViewWidth:
82
+ contentViewFollowsReadableWidth = false
83
+ case . matchReadableContentGuideWidth:
84
+ contentViewFollowsReadableWidth = true
85
+ }
86
+
87
+ case . regular:
88
+ switch horizontallyRegularContentWidth {
89
+ case . matchScrollViewWidth:
90
+ contentViewFollowsReadableWidth = false
91
+ case . matchReadableContentGuideWidth:
92
+ contentViewFollowsReadableWidth = true
93
+ }
94
+
95
+ case . unspecified:
96
+ return // abort early
97
+
98
+ @unknown default :
99
+ contentViewFollowsReadableWidth = false
100
+ }
101
+
45
102
if let constraints = contentViewConstraints {
46
103
NSLayoutConstraint . deactivate ( constraints)
47
104
}
48
- if let contentView = contentView {
49
- contentViewConstraints = contentView. activateSuperviewHuggingConstraints ( insets: contentInset)
105
+ NSLayoutConstraint . deactivate ( contentViewLayoutGuideConstraints)
106
+
107
+ let newLayoutGuide : UILayoutGuide
108
+ if contentViewFollowsReadableWidth, let contentView = contentView {
109
+ let newConstraints = [
110
+ contentView. leadingAnchor. constraint (
111
+ equalTo: readableContentGuide. leadingAnchor,
112
+ constant: contentInset. left
113
+ ) ,
114
+ contentView. trailingAnchor. constraint (
115
+ equalTo: readableContentGuide. trailingAnchor,
116
+ constant: - contentInset. right
117
+ ) ,
118
+ contentView. topAnchor. constraint ( equalTo: topAnchor, constant: contentInset. top) ,
119
+ contentView. bottomAnchor. constraint ( equalTo: bottomAnchor, constant: - contentInset. bottom) ,
120
+ ]
121
+ NSLayoutConstraint . activate ( newConstraints)
122
+ contentViewConstraints = newConstraints
123
+
124
+ newLayoutGuide = readableContentGuide
50
125
} else {
51
- contentViewConstraints = nil
126
+ contentViewConstraints = contentView? . activateSuperviewHuggingConstraints ( insets: contentInset)
127
+
128
+ newLayoutGuide = frameLayoutGuide
52
129
}
130
+
131
+ contentViewLayoutGuideConstraints = [
132
+ contentViewLayoutGuide. leadingAnchor. constraint ( equalTo: newLayoutGuide. leadingAnchor) ,
133
+ contentViewLayoutGuide. topAnchor. constraint ( equalTo: newLayoutGuide. topAnchor) ,
134
+ contentViewLayoutGuide. trailingAnchor. constraint ( equalTo: newLayoutGuide. trailingAnchor) ,
135
+ contentViewLayoutGuide. bottomAnchor. constraint ( equalTo: newLayoutGuide. bottomAnchor) ,
136
+ ]
137
+ NSLayoutConstraint . activate ( contentViewLayoutGuideConstraints)
53
138
}
54
139
55
140
fileprivate func commonInit( ) {
56
141
let nc = NotificationCenter . default
57
142
nc. addObserver ( self , selector: #selector( AutoScrollView . keyboardWillShow ( _: ) ) , name: UIResponder . keyboardWillShowNotification, object: nil )
58
143
nc. addObserver ( self , selector: #selector( AutoScrollView . keyboardWillHide ( _: ) ) , name: UIResponder . keyboardWillHideNotification, object: nil )
144
+
145
+ addLayoutGuide ( contentViewLayoutGuide)
59
146
}
60
147
61
148
public override init ( frame: CGRect ) {
@@ -77,6 +164,14 @@ open class AutoScrollView: UIScrollView {
77
164
return true
78
165
}
79
166
167
+ open override func traitCollectionDidChange( _ previousTraitCollection: UITraitCollection ? ) {
168
+ guard traitCollection. horizontalSizeClass != previousTraitCollection? . horizontalSizeClass else {
169
+ return
170
+ }
171
+
172
+ updateContentViewConstraints ( )
173
+ }
174
+
80
175
// MARK: Notifications
81
176
82
177
// Implementation based on code from Apple documentation
0 commit comments