1.卡片效果
卡片效果使用的事 collocationView
实现的,主要在于对UICollectionViewFlowLayout
里面方法的重写。
class LNCollectionViewLaout: UICollectionViewFlowLayout {
public var scaleFactor:CGFloat = 0.4
public var itemSpacing:CGFloat = 20.0
//MARK:- 这个方法每次layout发生改变就会调用一次
override func prepare() {
scrollDirection = .horizontal
minimumLineSpacing = itemSpacing
// sectionInset = UIEdgeInsets.init(top: 150, left: itemSize.width/2, bottom: 150, right: itemSize.width/2)
super.prepare()
}
//MARK:- 返回true frame发生变化是就允许重新布局。内部就会z重新调用prepare和layoutAttributesForElementsInRect
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
//MARK:- 用来计算出rect这个范围内所有的cell的UICollectionViewLayoutAttributes对象循环便利每个attribute对象m,然后修改frame,再返回给系统
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let cellAttributes = super.layoutAttributesForElements(in: rect) ?? []
let scaleFactor:CGFloat = self.scaleFactor/1000
//找到当前位置的中心点
let centerX = (collectionView?.contentOffset.x ?? 0) + (collectionView?.bounds.size.width ?? 0)/2
for attribute in cellAttributes {
let cell_centerX = attribute.center.x
//计算两中心的距离
let distance = abs(cell_centerX - centerX)
//距离越大缩放比例就越小,越小就越大,如果cell的中心点与中心重合,那就是最大点1
let scale:CGFloat = 1/(1+distance*scaleFactor)
attribute.transform3D = CATransform3DMakeScale(1.0, scale, 1.0)
}
return cellAttributes
}
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
let visibleX = proposedContentOffset.x
let visibleY = proposedContentOffset.y
let visibleWidth = collectionView?.width ?? 0
let visibleHeight = collectionView?.height ?? 0
//可视区域
let targetRect = CGRect.init(x: visibleX, y: visibleY, width: visibleWidth, height: visibleHeight)
//中心点的值
let centerX = proposedContentOffset.x + (collectionView?.bounds.size.width ?? 0)/2
//获取可视区域内的attributes对象
let attrArr = super.layoutAttributesForElements(in: targetRect)!
//如果第0个属性距离最小
var min_attr = attrArr[0]
for attributes in attrArr {
if (abs(attributes.center.x-centerX) < abs(min_attr.center.x-centerX)) {
min_attr = attributes
}
}
//计算出距离中心点 最小的那个cell 和整体中心点的偏移
let ofsetX = min_attr.center.x - centerX
// print("ddddddd\(proposedContentOffset)")
return CGPoint(x: proposedContentOffset.x+ofsetX, y: proposedContentOffset.y)
}
}
使用的时候直接用自定义的这个 layout
,然后调整一下 itemSize
,就可以达到效果。
获得当前屏幕显示的下标:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let index = ((collectionView?.contentOffset.x ?? 0) - layout.sectionInset.left)/(layout.itemSize.width+layout.minimumLineSpacing)
//对index四舍五入,当大于0.5的时候,就证明下一个cell的大部分都已经在屏幕中了,小于0.5还是自己。然后记录值,避免多次调用。
if Int(index.rounded()) != lastIndex {
lastIndex = Int(index.rounded())
//下标已改变,可以做处理。
let cell = collectionView.cellForItem(at: IndexPath.init(row: Int(index.rounded()), section: 0))
self.collectionView.backgroundColor = cell?.backgroundColor
}
print("当前\(lastIndex)")
}
cell点击居中的问题
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) else { return }
let centerX = collectionView.contentOffset.x + collectionView.width/2
//本来是要大于0也就是不在正中心就要判断不是当前选中下标,但是多次试验之后发现有很多次都不是整好等于0,所以就判断1
if abs(cell.centerX - centerX) > 1 {
collectionView.scrollToItem(at: indexPath, at: UICollectionView.ScrollPosition.centeredHorizontally, animated: true)
}
}
2.转场动画
转场动画直接用的三方 Hero
。
pod 'Hero'
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated: true)
guard let cell = collectionView.cellForItem(at: indexPath) else { return }
//id可以一个页面的多个view共用一个,但是会造成预期之外的效果。比如页面返回时,其他设置了这个id的视图也会跟着这个view开始动画。
let heroId = "LNCardViewController_CardCell_\(indexPath.row)"
cell.hero.id = heroId
let showVc = ShowViewController()
//打开效果
showVc.hero.isEnabled = true
showVc.contentView.backgroundColor = cell.backgroundColor
///需要变化动画的view,于前面的cell设置同样的id
showVc.contentView.hero.id = heroId
showVc.modalPresentationStyle = .fullScreen
present(showVc, animated: true, completion: nil)
}
}
网友评论