Created
June 11, 2018 17:38
-
-
Save uruly/ddc85f66190abe560692fcabdc52e233 to your computer and use it in GitHub Desktop.
CarouselView - Paging
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// CarouselCell.swift | |
// CardCarousel2 | |
// | |
// Created by Reona Kubo on 2018/06/11. | |
// Copyright © 2018年 Reona Kubo. All rights reserved. | |
// | |
import UIKit | |
class CarouselCell: UICollectionViewCell { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// CarouselView.swift | |
// CardCarousel2 | |
// | |
// Created by Reona Kubo on 2018/06/11. | |
// Copyright © 2018年 Reona Kubo. All rights reserved. | |
// | |
import UIKit | |
class CarouselView: UICollectionView { | |
let cellIdentifier = "carousel" | |
let pageCount = 5 | |
let colors:[UIColor] = [.blue,.yellow,.red,.green,.gray] | |
let isInfinity = true | |
var cellItemsWidth: CGFloat = 0.0 | |
var cellWidth:CGFloat = 200 | |
let windowWidth:CGFloat = UIScreen.main.bounds.width | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
} | |
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) { | |
super.init(frame: frame, collectionViewLayout: layout) | |
self.delegate = self | |
self.dataSource = self | |
self.register(CarouselCell.self, forCellWithReuseIdentifier: cellIdentifier) | |
} | |
convenience init(frame: CGRect) { | |
let layout = PagingPerCellFlowLayout() | |
layout.itemSize = CGSize(width: 200, height: frame.height / 2) | |
layout.scrollDirection = .horizontal | |
//layout.minimumLineSpacing = 0 | |
self.init(frame: frame, collectionViewLayout: layout) | |
// 水平方向のスクロールバーを非表示にする | |
self.showsHorizontalScrollIndicator = false | |
self.backgroundColor = UIColor.white | |
} | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
// 画面内に表示されているセルを取得 | |
let cells = self.visibleCells | |
for cell in cells { | |
// ここでセルのScaleを変更する | |
transformScale(cell: cell) | |
} | |
} | |
// セルのスケールを変更する | |
func transformScale(cell: UICollectionViewCell) { | |
let cellCenter:CGPoint = self.convert(cell.center, to: nil) //セルの中心座標 | |
let screenCenterX:CGFloat = UIScreen.main.bounds.width / 2 //画面の中心座標x | |
let reductionRatio:CGFloat = -0.0005 //縮小率 | |
let maxScale:CGFloat = 1 //最大値 | |
let cellCenterDisX:CGFloat = abs(screenCenterX - cellCenter.x) //中心までの距離 | |
let newScale = reductionRatio * cellCenterDisX + maxScale //新しいスケール | |
cell.transform = CGAffineTransform(scaleX:newScale, y:newScale) | |
} | |
// 初期位置を真ん中にする | |
func scrollToFirstItem() { | |
//self.layoutIfNeeded() | |
if isInfinity { | |
self.scrollToItem(at:IndexPath(row: self.pageCount, section: 0) , at: .centeredHorizontally, animated: false) | |
} | |
} | |
} | |
extension CarouselView: UICollectionViewDelegate { | |
} | |
extension CarouselView: UICollectionViewDataSource { | |
// セクションごとのセル数 | |
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { | |
return isInfinity ? pageCount * 3 : pageCount | |
} | |
// セルの設定 | |
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { | |
let cell:CarouselCell = dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! CarouselCell | |
configureCell(cell: cell, indexPath: indexPath) | |
return cell | |
} | |
func configureCell(cell: CarouselCell,indexPath: IndexPath) { | |
// indexを修正する | |
let fixedIndex = isInfinity ? indexPath.row % pageCount : indexPath.row | |
cell.contentView.backgroundColor = colors[fixedIndex] | |
} | |
} | |
extension CarouselView: UIScrollViewDelegate { | |
func scrollViewDidScroll(_ scrollView: UIScrollView) { | |
if isInfinity { | |
if cellItemsWidth == 0.0 { | |
cellItemsWidth = floor(scrollView.contentSize.width / 3.0) // 表示したい要素群のwidthを計算 | |
} | |
if (scrollView.contentOffset.x <= 0.0) || (scrollView.contentOffset.x > cellItemsWidth * 2.0) { // スクロールした位置がしきい値を超えたら中央に戻す | |
scrollView.contentOffset.x = cellItemsWidth | |
} | |
} | |
} | |
/***** 方法3 ******/ | |
// //速度velocityを持っていてドラッグが終わりそうなとき。最終的な落ち着き先をtargetContentOffsetで指定 | |
// func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { | |
// | |
// targetContentOffset.pointee = targetContentOffsetPoint(scrollView, velocity: velocity) | |
// } | |
// | |
// func targetContentOffsetPoint(_ scrollView: UIScrollView,velocity:CGPoint) -> CGPoint{ | |
// let cellWidth:CGFloat = 200 | |
// let windowWidth:CGFloat = UIScreen.main.bounds.width | |
// var offsetAdjustment:CGFloat = CGFloat(MAXFLOAT) | |
// let horizontalOffest:CGFloat = scrollView.contentOffset.x + ( windowWidth - cellWidth ) / 2 | |
// | |
// let targetRect = CGRect(x:scrollView.contentOffset.x + velocity.x * cellWidth, | |
// y:0, | |
// width:self.bounds.size.width, | |
// height:self.bounds.size.height) | |
// | |
// let array = self.collectionViewLayout.layoutAttributesForElements(in: targetRect) | |
// | |
// for layoutAttributes in array! { | |
// let itemOffset = layoutAttributes.frame.origin.x | |
// if abs(itemOffset - horizontalOffest) < abs(offsetAdjustment) { | |
// offsetAdjustment = itemOffset - horizontalOffest | |
// } | |
// } | |
// return CGPoint(x:scrollView.contentOffset.x + offsetAdjustment, y:scrollView.contentOffset.y) | |
// } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// PagingPerCellFlowLayout.swift | |
// CardCarousel2 | |
// | |
// Created by Reona Kubo on 2018/06/12. | |
// Copyright © 2018年 Reona Kubo. All rights reserved. | |
// | |
import UIKit | |
class PagingPerCellFlowLayout: UICollectionViewFlowLayout { | |
var cellWidth:CGFloat = 200 | |
let windowWidth:CGFloat = UIScreen.main.bounds.width | |
/***** 方法1 ******/ | |
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { | |
var offsetAdjustment:CGFloat = CGFloat(MAXFLOAT) | |
let horizontalOffest:CGFloat = proposedContentOffset.x + ( windowWidth - cellWidth ) / 2 | |
let targetRect = CGRect(x:proposedContentOffset.x, | |
y:0, | |
width:self.collectionView!.bounds.size.width, | |
height:self.collectionView!.bounds.size.height) | |
let array = super.layoutAttributesForElements(in: targetRect) | |
for layoutAttributes in array! { | |
let itemOffset = layoutAttributes.frame.origin.x | |
if abs(itemOffset - horizontalOffest) < abs(offsetAdjustment) { | |
offsetAdjustment = itemOffset - horizontalOffest | |
} | |
} | |
return CGPoint(x:proposedContentOffset.x + offsetAdjustment, y:proposedContentOffset.y) | |
} | |
/***** 方法2 ******/ | |
// override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint | |
// { | |
// if let collectionViewBounds = self.collectionView?.bounds | |
// { | |
// let halfWidthOfVC = collectionViewBounds.size.width * 0.5 | |
// let proposedContentOffsetCenterX = proposedContentOffset.x + halfWidthOfVC | |
// if let attributesForVisibleCells = self.layoutAttributesForElements(in: collectionViewBounds) | |
// { | |
// var candidateAttribute : UICollectionViewLayoutAttributes? | |
// for attributes in attributesForVisibleCells | |
// { | |
// let candAttr : UICollectionViewLayoutAttributes? = candidateAttribute | |
// if candAttr != nil | |
// { | |
// let a = attributes.center.x - proposedContentOffsetCenterX | |
// let b = candAttr!.center.x - proposedContentOffsetCenterX | |
// if fabs(a) < fabs(b) | |
// { | |
// candidateAttribute = attributes | |
// } | |
// } | |
// else | |
// { | |
// candidateAttribute = attributes | |
// continue | |
// } | |
// } | |
// | |
// if candidateAttribute != nil | |
// { | |
// return CGPoint(x: candidateAttribute!.center.x - halfWidthOfVC, y: proposedContentOffset.y); | |
// } | |
// } | |
// } | |
// return CGPoint.zero | |
// } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ViewController.swift | |
// CardCarousel2 | |
// | |
// Created by Reona Kubo on 2018/06/11. | |
// Copyright © 2018年 Reona Kubo. All rights reserved. | |
// | |
import UIKit | |
class ViewController: UIViewController { | |
var carouselView:CarouselView! | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
let width = self.view.frame.width | |
let height = self.view.frame.height | |
carouselView = CarouselView(frame: CGRect(x:0, y:0, width:width, height:height)) | |
carouselView.center = CGPoint(x:width / 2,y: height / 2) | |
self.view.addSubview(carouselView) | |
} | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
carouselView.scrollToFirstItem() | |
} | |
override func didReceiveMemoryWarning() { | |
super.didReceiveMemoryWarning() | |
// Dispose of any resources that can be recreated. | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment