どもも。
UICollectionViewを用いてiPhoneのデフォルト写真アプリのようなものを作成しています。イメージビューアーっていうのかなそんな感じのやつです。
やりたいこととしては、UICollectionView上のUIImageViewの拡大となります。
こんな感じ。
ちなみにこの拡大だけで2日くらい行き詰まってました(´・ω・`)
UICollectionViewはUIScrollViewのサブクラス!
UICollectionViewはUIScrollViewのサブクラスになります。
UIScrollViewなら
どうにかこれを使いたいのですが、viewForZooming(in:)がそもそも呼ばれない。原因がわからず色々プロジェクト外で試行錯誤してたんですが、ようやく解決方法がわかったので紹介していきます。
UICollectionViewを設置しよう
適当にコレクションビューを設置します。
この辺は普通に設置するだけでおkです。
まずはデリゲートを書いておきます。
class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource{
/* ~~ */
}
設置します。
class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource{
private var myCollectionView:UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let width = self.view.frame.width
//レイアウト
let imageLayout = UICollectionViewFlowLayout()
imageLayout.itemSize = CGSize(width:width,height:width * 4 / 3)
//スクロールの向き
imageLayout.scrollDirection = .horizontal
imageLayout.minimumLineSpacing = 0
imageLayout.minimumInteritemSpacing = 0
imageLayout.sectionInset = UIEdgeInsetsMake(0,0,0,0)
//コレクションビュー
myCollectionView = UICollectionView(frame: CGRect(x:0,y:49,width:width,height:width * 4 / 3), collectionViewLayout: imageLayout)
//デリゲートをつける
myCollectionView.delegate = self
myCollectionView.dataSource = self
//カスタムセルを指定
myCollectionView.register(SingleViewCell.self, forCellWithReuseIdentifier: "singleCell")
//スクロールバーを表示するかどうか
myCollectionView.showsHorizontalScrollIndicator = false
myCollectionView.showsVerticalScrollIndicator = false
myCollectionView.backgroundColor = UIColor.gray
//ページングをするかどうか
myCollectionView.isPagingEnabled = true
self.view.addSubview(myCollectionView)
}
/********************* CollectionView *********************/
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("タップ")
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//セルの設定
let cell:SingleViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "singleCell", for: indexPath) as! SingleViewCell
let image = UIImage(named:"picture.jpg")
cell.imageView.image = image
return cell
}
}
適当に同じ画像を10枚横スクロールで表示しています。
カスタムセルを作ろう
UICollectionViewCellのサブクラスを作成します。
File > New > File
Source > Cocoa Touch Class > Next
Sublclass of:をUICollectionViewCellにして作成
この中にScrollViewを設置して、さらにその上にImageViewを置きます。
import UIKit
class SingleViewCell: UICollectionViewCell,UIScrollViewDelegate {
public var imageView:UIImageView!
public var scrollView:UIScrollView!
required init(coder aDecoder:NSCoder){
super.init(coder: aDecoder)!
}
override init(frame:CGRect){
super.init(frame:frame)
//スクロールビューを設置
scrollView = UIScrollView()
scrollView.frame = CGRect(x:0,y:0,width:self.frame.width,height:self.frame.height)
//デリゲートを設定
scrollView.delegate = self
//最大・最小の大きさを決める
scrollView.maximumZoomScale = 4.0
scrollView.minimumZoomScale = 1.0
self.contentView.addSubview(scrollView)
//imageViewを生成
imageView = UIImageView()
imageView.frame = CGRect(x:0,y:0,width:self.frame.width,height:self.frame.height)
//scrollViewにのせる
scrollView.addSubview(imageView)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
//実際に拡大したいscrollViewのサブビューを返す
return self.imageView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
print("zoomおわり")
}
func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
print("zoomはじまり")
}
}
これで無事拡大ができます。
ダブルタップでの拡大を記事の最後に付け足しました。
失敗ポイント
躓いた原因はいくつかあります(´・ω・`)
・UICollectionViewがUIScrollViewのサブクラスだということで、自動的にviewForZooming(in:)が呼ばれると思っていた。
・UIScrollViewを設置してデリゲートをつけると、自動的にviewForZooming(in:)が呼ばれると思っていた。
・そもそもUICollectionView上のスクロールビューを拡大しても意味がないことに気がついていなかった。
などなど。
まず
//最大・最小の大きさを決める
scrollView.maximumZoomScale = 4.0
scrollView.minimumZoomScale = 1.0
このzoomに関する設定をしていなかったから呼ばれなかったわけです。
setZoomScale(scale:animated:)だとかzoom(to:animated:)だとかを書いてもviewForZooming(in:)は呼ばれていました。
この辺がないと呼ばれない。ここに気づくまでが時間かかりました・・・疲れてたのかな・・・・ 気づいてからはすぐでした。
そしてUICollectionView上のスクロールビューを拡大しようとしていたので、枠だけが大きくなって画像が大きくならないという。すぐに気づいたけどね・・・?
ちなみに、UICollectionViewを使っている場合はUIScrollViewDelegateではなくUICollectionViewDelegateを使ってください。ちゃんとscrollviewのも含まれているよ(`・ω・´)
あとは色々UIGestureRecognizerを用いてピンチしようとしたのですが、色々競合しちゃったのかうまくいきませんでした。そしてごちゃごちゃしてるし煩雑です。
ダブルタップで拡大機能もつけようと思っているので、またすぐ記事書くかもです〜。
ほぼ写しただけで済んでしまったので、ダブルタップで拡大を追加したコード載せておきます。
参考はこちら「画像をダブルタップとピンチイン・ピンチアウトで拡大・縮小する」
変なところにひっかかってなかったらこの記事だけで実装できてたな・・・(´・ω・`)
import UIKit
class SingleViewCell: UICollectionViewCell,UIScrollViewDelegate {
public var imageView:UIImageView!
public var scrollView:UIScrollView!
required init(coder aDecoder:NSCoder){
super.init(coder: aDecoder)!
}
override init(frame:CGRect){
super.init(frame:frame)
//スクロールビューを設置
scrollView = UIScrollView()
scrollView.frame = CGRect(x:0,y:0,width:self.frame.width,height:self.frame.height)
//デリゲートを設定
scrollView.delegate = self
//最大・最小の大きさを決める
scrollView.maximumZoomScale = 4.0
scrollView.minimumZoomScale = 1.0
self.contentView.addSubview(scrollView)
//imageViewを生成
imageView = UIImageView()
imageView.frame = CGRect(x:0,y:0,width:self.frame.width,height:self.frame.height)
scrollView.addSubview(imageView)
let doubleTap = UITapGestureRecognizer(target:self,action:#selector(SingleViewCell.doubleTap(gesture:)))
doubleTap.numberOfTapsRequired = 2
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(doubleTap)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return self.imageView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
print("zoomおわり")
}
func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
print("zoomするよ")
}
// ダブルタップ
func doubleTap(gesture: UITapGestureRecognizer) -> Void {
// if ( self.scrollView.zoomScale < self.scrollView.maximumZoomScale ) {
if ( self.scrollView.zoomScale < 3 ) {
let newScale:CGFloat = self.scrollView.zoomScale * 3
let zoomRect:CGRect = self.zoomRectForScale(scale: newScale, center: gesture.location(in: gesture.view))
self.scrollView.zoom(to: zoomRect, animated: true)
} else {
self.scrollView.setZoomScale(1.0, animated: true)
}
}
// 領域
func zoomRectForScale(scale:CGFloat, center: CGPoint) -> CGRect{
var zoomRect: CGRect = CGRect()
zoomRect.size.height = self.scrollView.frame.size.height / scale
zoomRect.size.width = self.scrollView.frame.size.width / scale
zoomRect.origin.x = center.x - zoomRect.size.width / 2.0
zoomRect.origin.y = center.y - zoomRect.size.height / 2.0
return zoomRect
}
}
ではでは。
どうでもいいけど一番最初のUICollectionViewはUIScrollViewのサブクラスっていうとこ、いらなくない・・・?
参考リンク
Additional Notes追記
gistに↑age↑ヾ(`・ω・´)ノ シャキーン
Swift4に対応したものをGistにあげておきました〜。
ついでに最近のコードの書き方に変えておきました。 今の方が見やすいと信じている。
コメントはありません。
現在コメントフォームは工事中です。