Skip to content

Instantly share code, notes, and snippets.

@uruly
Created June 13, 2018 21:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uruly/8f9887297bc67cf800ef728cee9d1ddd to your computer and use it in GitHub Desktop.
Save uruly/8f9887297bc67cf800ef728cee9d1ddd to your computer and use it in GitHub Desktop.
CarouselView - Complete
//
// CarouselCell.swift
// CardCarousel2
//
// Created by Reona Kubo on 2018/06/11.
// Copyright © 2018年 Reona Kubo. All rights reserved.
//
import UIKit
class CarouselCell: UICollectionViewCell {
var countLabel:UILabel!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup() {
// セルの縦横を取得する
let width:CGFloat = self.frame.width
let height:CGFloat = self.frame.height
// 適当なmargin
let margin:CGFloat = 15
// 数字ラベルを設置する
countLabel = UILabel()
countLabel.frame = CGRect(x:margin,
y:margin,
width:width - margin * 2,
height:50)
countLabel.textAlignment = .center
countLabel.textColor = UIColor.black
countLabel.font = UIFont.systemFont(ofSize: 22, weight: .bold)
self.contentView.addSubview(countLabel)
// セルの背景色を変える
self.contentView.backgroundColor = UIColor.white
// セルの枠線の太さを変える
self.contentView.layer.borderWidth = 2
// セルを角丸にする
self.contentView.layer.cornerRadius = 50
// セルに影をつける
self.contentView.layer.shadowOffset = CGSize(width: 1,height: 1) // 影の位置
self.contentView.layer.shadowColor = UIColor.gray.cgColor // 影の色
self.contentView.layer.shadowOpacity = 0.7 // 影の透明度
self.contentView.layer.shadowRadius = 5 // 影の広がり
}
}
//
// 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.layer.borderColor = colors[fixedIndex].cgColor
// countLabelにIndexをつける
cell.countLabel.text = String(fixedIndex + 1)
print(cell.contentView.layer.shadowOffset)
}
}
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)
// }
}
//
// 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
// }
}
//
// 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