Skip to content

Instantly share code, notes, and snippets.

@Shinolr
Created March 12, 2019 03:48
Show Gist options
  • Save Shinolr/bb4deddeff353def6616aa7061e2bfb4 to your computer and use it in GitHub Desktop.
Save Shinolr/bb4deddeff353def6616aa7061e2bfb4 to your computer and use it in GitHub Desktop.
具有分页效果的滚动 card banner
class CardBannerFlowLayout: UICollectionViewFlowLayout {
var padding: CGFloat = 20
var cardSize: CGSize {
return CGSize(width: screen_width - 2 * padding, height: 168)
}
let cardSpacing: CGFloat = 10.0
var initialNonCardLength: CGFloat {
return padding + cardSpacing
}
override func prepare() {
super.prepare()
itemSize = cardSize
scrollDirection = .horizontal
collectionView?.contentInset = UIEdgeInsets(top: 0, left: padding, bottom: 0, right: padding)
minimumLineSpacing = cardSpacing
collectionView?.decelerationRate = .fast
collectionView?.showsHorizontalScrollIndicator = false
collectionView?.backgroundColor = .clear
}
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
var adjustmentOffset = CGFloat.greatestFiniteMagnitude
// 屏幕中点在 collectionView 座标系上的 x 座标
let screenCenter = proposedContentOffset.x + screen_width / 2
// scrollView 滚动自然停止时所显示的区域 frame
let visibleRect = CGRect(x: proposedContentOffset.x, y: 0, width: screen_width, height: collectionView!.bounds.height)
let visibleAttrs = layoutAttributesForElements(in: visibleRect)
visibleAttrs?.forEach {
// 比较屏幕中心点和 item 中心点在 collectionView 座标系上的位置
let attrOffset = $0.center.x - screenCenter
if abs(attrOffset) < abs(adjustmentOffset) {
adjustmentOffset = attrOffset
}
}
let compensate = screen_width - initialNonCardLength // 单个卡片移动距离
if velocity.x > 0 { // 左滑 增加 proposedContentOffset.x
if adjustmentOffset < 0 { // item 中心在屏幕中心左侧
adjustmentOffset += compensate
}
} else if velocity.x < 0 { // 右滑 减少 proposedContentOffset.x
if adjustmentOffset > 0 {
adjustmentOffset -= compensate
}
}
return CGPoint(x: proposedContentOffset.x + adjustmentOffset, y: proposedContentOffset.y)
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment