我需要应用类似底部工作表的动画,其中“收集视图”单元格在关闭时彼此重叠,而在打开底部工作表时则打开宽度。我已经使用“分页视图”和“分页”实现了底部工作表,但是需要应用动画,当底部工作表关闭时,该动画仅显示当前单元格和其后的单元格。
这是我的底片类,以及一些我想要实现的图像:
class ScrollableBottomSheetViewController: UIViewController {
@IBOutlet var pageControl: UIPageControl!
@IBOutlet var collection: UICollectionView!
@IBOutlet var headerView: UIView!
let fullView: CGFloat = 0//50
var partialView: CGFloat {
return UIScreen.main.bounds.height - 50
}
let collectionMargin = CGFloat(32)
let itemSpacing = CGFloat(10)
let itemHeight = CGFloat(333)
var itemWidth = CGFloat(0)
var currentItem = 5
override func viewDidLoad() {
super.viewDidLoad()
self.definesPresentationContext = true
self.collection.delegate = self
self.collection.dataSource = self
self.collection.register(UINib(nibName:"AdsCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "default")
let gesture = UIPanGestureRecognizer.init(target: self, action: #selector(ScrollableBottomSheetViewController.panGesture))
gesture.delegate = self
view.addGestureRecognizer(gesture)
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
//CGFloat(219) //
itemWidth = UIScreen.main.bounds.width - collectionMargin * 2.0
print(itemWidth)
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width: itemWidth, height: itemHeight)
layout.headerReferenceSize = CGSize(width: collectionMargin, height: 0)
layout.footerReferenceSize = CGSize(width: collectionMargin, height: 0)
layout.minimumLineSpacing = itemSpacing
layout.scrollDirection = .horizontal
collection!.collectionViewLayout = layout
collection?.decelerationRate = UIScrollViewDecelerationRateFast
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let pageWidth = Float(itemWidth + itemSpacing)
let targetXContentOffset = Float(targetContentOffset.pointee.x)
let contentWidth = Float(collection!.contentSize.width )
var newPage = Float(self.pageControl.currentPage)
if velocity.x == 0 {
newPage = floor( (targetXContentOffset - Float(pageWidth) / 2) / Float(pageWidth)) + 1.0
} else {
newPage = Float(velocity.x > 0 ? self.pageControl.currentPage + 1 : self.pageControl.currentPage - 1)
if newPage < 0 {
newPage = 0
}
if (newPage > contentWidth / pageWidth) {
newPage = ceil(contentWidth / pageWidth) - 1.0
}
}
self.pageControl.currentPage = Int(newPage)
let point = CGPoint (x: CGFloat(newPage * pageWidth) + itemSpacing, y: targetContentOffset.pointee.y)
targetContentOffset.pointee = point
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
prepareBackgroundView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 0.6, animations: { [weak self] in
let frame = self?.view.frame
let yComponent = self?.partialView
self?.view.frame = CGRect(x: 0, y: yComponent!, width: frame!.width, height: frame!.height)// - 100)
})
}
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: self.view)
let velocity = recognizer.velocity(in: self.view)
let y = self.view.frame.minY
if (y + translation.y >= fullView) && (y + translation.y <= partialView) {
self.view.frame = CGRect(x: 0, y: y + translation.y, width: view.frame.width, height: view.frame.height)
recognizer.setTranslation(CGPoint.zero, in: self.view)
}
if recognizer.state == .ended {
var duration = velocity.y < 0 ? Double((y - fullView) / -velocity.y) : Double((partialView - y) / velocity.y)
duration = duration > 1.3 ? 1 : duration
UIView.animate(withDuration: duration, delay: 0.0, options: [.allowUserInteraction], animations: {
if velocity.y >= 0 {
self.view.frame = CGRect(x: 0, y: self.partialView, width: self.view.frame.width, height: self.view.frame.height)
} else {
self.view.frame = CGRect(x: 0, y: self.fullView, width: self.view.frame.width, height: self.view.frame.height)
}
}, completion: { [weak self] _ in
if velocity.y < 0 {
self?.collection.isScrollEnabled = true
}
})
}
}
func prepareBackgroundView() {
let blurEffect = UIBlurEffect.init(style: .dark)
let visualEffect = UIVisualEffectView.init(effect: blurEffect)
let bluredView = UIVisualEffectView.init(effect: blurEffect)
bluredView.contentView.addSubview(visualEffect)
visualEffect.frame = UIScreen.main.bounds
bluredView.frame = UIScreen.main.bounds
view.insertSubview(bluredView, at: 0)
}
}
extension ScrollableBottomSheetViewController : UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "default", for: indexPath)
return cell
}
}
extension ScrollableBottomSheetViewController: UIGestureRecognizerDelegate {
// Solution
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
let gesture = (gestureRecognizer as! UIPanGestureRecognizer)
let direction = gesture.velocity(in: view).y
let y = view.frame.minY
if (y == fullView && collection.contentOffset.x == 0 && direction > 0) || (y == partialView) {
collection.isScrollEnabled = false
} else {
collection.isScrollEnabled = true
}
return false
}
}