blob: 5175e0b13e48e4db861dddd158290469deb32490 [file] [log] [blame] [edit]
// Copyright 2016-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import XCTest
import MaterialComponents.MaterialFlexibleHeader
// Tests verifying contentOffset side effect behavior when changing contentInset.
class ScrollViewContentOffsetSideEffectTests: XCTestCase {
let bounds = CGRect(x: 0, y: 0, width: 320, height: 20)
let inset = CGFloat(6)
let initialOffset = CGPoint(x: 0, y: 0)
// Calculates the estimated contentOffset given the proposed new contentInsets and current value
// of contentOffset + contentSize.
class func estimatedContentOffsetForScrollView(
_ scrollView: UIScrollView,
withNewInsets newInsets: UIEdgeInsets
) -> CGPoint {
let minimumPossibleYOffset = -newInsets.top
let maximumPossibleYOffset =
(scrollView.contentSize.height + newInsets.bottom) - scrollView.bounds.height
let estimatedYOffset =
max(minimumPossibleYOffset, min(maximumPossibleYOffset, scrollView.contentOffset.y))
let minimumPossibleXOffset = -newInsets.left
let maximumPossibleXOffset =
(scrollView.contentSize.width + newInsets.right) - scrollView.bounds.width
let estimatedXOffset =
max(minimumPossibleXOffset, min(maximumPossibleXOffset, scrollView.contentOffset.x))
return CGPoint(x: estimatedXOffset, y: estimatedYOffset)
}
func testEstimationAddingTopInsets() {
let insets = UIEdgeInsets(top: inset, left: 0, bottom: 0, right: 0)
enumerateHeightRangeWithInsets(UIEdgeInsets(), after: insets) { scrollView, contentOffset in
XCTAssertEqual(scrollView.contentOffset, contentOffset)
}
}
func testEstimationRemovingTopInsets() {
let insets = UIEdgeInsets(top: inset, left: 0, bottom: 0, right: 0)
enumerateHeightRangeWithInsets(insets, after: UIEdgeInsets()) { scrollView, contentOffset in
XCTAssertEqual(scrollView.contentOffset, contentOffset)
}
}
func testEstimationAddingBottomInsets() {
let insets = UIEdgeInsets(top: 0, left: 0, bottom: inset, right: 0)
enumerateHeightRangeWithInsets(UIEdgeInsets(), after: insets) { scrollView, contentOffset in
XCTAssertEqual(scrollView.contentOffset, contentOffset)
}
}
func testEstimationRemovingBottomInsets() {
let insets = UIEdgeInsets(top: 0, left: 0, bottom: inset, right: 0)
enumerateHeightRangeWithInsets(insets, after: UIEdgeInsets()) { scrollView, contentOffset in
XCTAssertEqual(scrollView.contentOffset, contentOffset)
}
}
func testEstimationAddingBothInsets() {
let insets = UIEdgeInsets(top: inset, left: 0, bottom: inset, right: 0)
enumerateHeightRangeWithInsets(UIEdgeInsets(), after: insets) { scrollView, contentOffset in
XCTAssertEqual(scrollView.contentOffset, contentOffset)
}
}
func testEstimationRemovingBothInsets() {
let insets = UIEdgeInsets(top: inset, left: 0, bottom: inset, right: 0)
enumerateHeightRangeWithInsets(insets, after: UIEdgeInsets()) { scrollView, contentOffset in
XCTAssertEqual(scrollView.contentOffset, contentOffset)
}
}
func enumerateHeightRangeWithInsets(
_ before: UIEdgeInsets,
after: UIEdgeInsets,
work: (UIScrollView, CGPoint) -> Void
) {
for contentHeight in -1...Int(bounds.height * 3) {
let scrollView = UITableView(frame: bounds)
scrollView.contentInset = before
scrollView.contentOffset = initialOffset
scrollView.contentSize = CGSize(width: 0, height: CGFloat(contentHeight))
let estimatedContentOffset = type(of: self).estimatedContentOffsetForScrollView(
scrollView,
withNewInsets: after
)
scrollView.contentInset = after
work(scrollView, estimatedContentOffset)
}
}
}