Skip to content

Commit

Permalink
Add content inset support via layout margins
Browse files Browse the repository at this point in the history
  • Loading branch information
bryankeller committed Jul 28, 2020
1 parent 2ef5fce commit b3f05a6
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 9 deletions.
8 changes: 5 additions & 3 deletions Sources/Internal/FrameProvider.swift
Expand Up @@ -13,8 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import CoreGraphics
import Foundation
import UIKit

/// Provides frame and size information about all core layout items. The calendar is laid out lazily, starting with an initial known layout
/// frame (like the frame of an initially visible month header). All subsequent layout calculations are done by laying out items adjacent to
Expand All @@ -26,17 +25,19 @@ final class FrameProvider {
init(
content: CalendarViewContent,
size: CGSize,
layoutMargins: NSDirectionalEdgeInsets,
scale: CGFloat,
monthHeaderHeight: CGFloat)
{
self.content = content
self.size = size
self.layoutMargins = layoutMargins
self.scale = scale
self.monthHeaderHeight = monthHeaderHeight

switch content.monthsLayout {
case .vertical:
monthWidth = size.width
monthWidth = size.width - layoutMargins.leading - layoutMargins.trailing
case .horizontal(let _monthWidth):
monthWidth = _monthWidth
}
Expand All @@ -53,6 +54,7 @@ final class FrameProvider {
// MARK: Internal

let size: CGSize
let layoutMargins: NSDirectionalEdgeInsets
let scale: CGFloat
let daySize: CGSize

Expand Down
15 changes: 11 additions & 4 deletions Sources/Internal/VisibleItemsProvider.swift
Expand Up @@ -26,6 +26,7 @@ final class VisibleItemsProvider {
calendar: Calendar,
content: CalendarViewContent,
size: CGSize,
layoutMargins: NSDirectionalEdgeInsets,
scale: CGFloat,
monthHeaderHeight: CGFloat)
{
Expand All @@ -38,6 +39,7 @@ final class VisibleItemsProvider {
frameProvider = FrameProvider(
content: content,
size: size,
layoutMargins: layoutMargins,
scale: scale,
monthHeaderHeight: monthHeaderHeight)
}
Expand All @@ -50,6 +52,10 @@ final class VisibleItemsProvider {
frameProvider.size
}

var layoutMargins: NSDirectionalEdgeInsets {
frameProvider.layoutMargins
}

var scale: CGFloat {
frameProvider.scale
}
Expand Down Expand Up @@ -701,18 +707,19 @@ final class VisibleItemsProvider {
switch content.monthsLayout {
case .vertical(let options):
minimumScrollOffset = monthFrame.minY -
(options.pinDaysOfWeekToTop ? frameProvider.daySize.height : 0)
(options.pinDaysOfWeekToTop ? frameProvider.daySize.height : 0) -
layoutMargins.top
case .horizontal:
minimumScrollOffset = monthFrame.minX
minimumScrollOffset = monthFrame.minX - layoutMargins.leading
}
}

if month == content.dayRange.upperBound.month {
switch content.monthsLayout {
case .vertical:
maximumScrollOffset = monthFrame.maxY
maximumScrollOffset = monthFrame.maxY + layoutMargins.bottom
case .horizontal:
maximumScrollOffset = monthFrame.maxX
maximumScrollOffset = monthFrame.maxX + layoutMargins.trailing
}
}
}
Expand Down
35 changes: 33 additions & 2 deletions Sources/Public/CalendarView.swift
Expand Up @@ -142,6 +142,28 @@ public final class CalendarView: UIView {
}
}

/// `CalendarView` only supports positive values for `layoutMargins`. Negative values will be changed to `0`.
public override var layoutMargins: UIEdgeInsets {
didSet {
super.layoutMargins = UIEdgeInsets(
top: max(layoutMargins.top, 0),
left: max(layoutMargins.left, 0),
bottom: max(layoutMargins.bottom, 0),
right: max(layoutMargins.right, 0))
}
}

/// `CalendarView` only supports positive values for `directionalLayoutMargins`. Negative values will be changed to `0`.
public override var directionalLayoutMargins: NSDirectionalEdgeInsets {
didSet {
super.directionalLayoutMargins = NSDirectionalEdgeInsets(
top: max(directionalLayoutMargins.top, 0),
leading: max(directionalLayoutMargins.leading, 0),
bottom: max(directionalLayoutMargins.bottom, 0),
trailing: max(directionalLayoutMargins.trailing, 0))
}
}

public override func didMoveToWindow() {
super.didMoveToWindow()

Expand All @@ -150,6 +172,10 @@ public final class CalendarView: UIView {
}
}

public override func layoutMarginsDidChange() {
setNeedsLayout()
}

public override func layoutSubviews() {
super.layoutSubviews()

Expand Down Expand Up @@ -388,6 +414,7 @@ public final class CalendarView: UIView {
if
let existingVisibleItemsProvider = _visibleItemsProvider,
existingVisibleItemsProvider.size == bounds.size,
existingVisibleItemsProvider.layoutMargins == directionalLayoutMargins,
existingVisibleItemsProvider.scale == scale
{
return existingVisibleItemsProvider
Expand All @@ -396,6 +423,7 @@ public final class CalendarView: UIView {
calendar: calendar,
content: content,
size: bounds.size,
layoutMargins: directionalLayoutMargins,
scale: scale,
monthHeaderHeight: monthHeaderHeight())
_visibleItemsProvider = visibleItemsProvider
Expand All @@ -404,9 +432,12 @@ public final class CalendarView: UIView {
}

private var initialMonthHeaderAnchorLayoutItem: LayoutItem {
visibleItemsProvider.anchorMonthHeaderItem(
let offset = CGPoint(
x: scrollView.contentOffset.x + directionalLayoutMargins.leading,
y: scrollView.contentOffset.y + directionalLayoutMargins.top)
return visibleItemsProvider.anchorMonthHeaderItem(
for: content.monthRange.lowerBound,
offset: scrollView.contentOffset,
offset: offset,
scrollPosition: .firstFullyVisiblePosition)
}

Expand Down
4 changes: 4 additions & 0 deletions Tests/FrameProviderTests.swift
Expand Up @@ -39,6 +39,7 @@ final class FrameProviderTests: XCTestCase {
.withVerticalDayMargin(20)
.withHorizontalDayMargin(10),
size: size,
layoutMargins: .zero,
scale: 3,
monthHeaderHeight: monthHeaderHeight)
verticalPinnedDaysOfWeekFrameProvider = FrameProvider(
Expand All @@ -51,6 +52,7 @@ final class FrameProviderTests: XCTestCase {
.withVerticalDayMargin(20)
.withHorizontalDayMargin(10),
size: size,
layoutMargins: .zero,
scale: 3,
monthHeaderHeight: monthHeaderHeight)
verticalPartialMonthFrameProvider = FrameProvider(
Expand All @@ -64,6 +66,7 @@ final class FrameProviderTests: XCTestCase {
.withVerticalDayMargin(20)
.withHorizontalDayMargin(10),
size: size,
layoutMargins: .zero,
scale: 3,
monthHeaderHeight: monthHeaderHeight)
horizontalFrameProvider = FrameProvider(
Expand All @@ -76,6 +79,7 @@ final class FrameProviderTests: XCTestCase {
.withVerticalDayMargin(20)
.withHorizontalDayMargin(10),
size: size,
layoutMargins: .zero,
scale: 3,
monthHeaderHeight: monthHeaderHeight)
}
Expand Down
4 changes: 4 additions & 0 deletions Tests/VisibleItemsProviderTests.swift
Expand Up @@ -1535,6 +1535,7 @@ final class VisibleItemsProviderTests: XCTestCase {
visibleDateRange: dateRange,
monthsLayout: .vertical(options: VerticalMonthsLayoutOptions()))),
size: size,
layoutMargins: .zero,
scale: 2,
monthHeaderHeight: 50)

Expand All @@ -1546,6 +1547,7 @@ final class VisibleItemsProviderTests: XCTestCase {
visibleDateRange: dateRange,
monthsLayout: .vertical(options: VerticalMonthsLayoutOptions(pinDaysOfWeekToTop: true)))),
size: size,
layoutMargins: .zero,
scale: 2,
monthHeaderHeight: 50)

Expand All @@ -1558,6 +1560,7 @@ final class VisibleItemsProviderTests: XCTestCase {
monthsLayout: .vertical(
options: VerticalMonthsLayoutOptions(alwaysShowCompleteBoundaryMonths: false)))),
size: size,
layoutMargins: .zero,
scale: 2,
monthHeaderHeight: 50)

Expand All @@ -1569,6 +1572,7 @@ final class VisibleItemsProviderTests: XCTestCase {
visibleDateRange: dateRange,
monthsLayout: .horizontal(monthWidth: 300))),
size: size,
layoutMargins: .zero,
scale: 2,
monthHeaderHeight: 50)

Expand Down

0 comments on commit b3f05a6

Please sign in to comment.