みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

Swiftについて教えてください

UICollectionviewに読み込んだ画像をタッチして枠線と番号を表示させようと下記のようにしてみたのですが、最後のセルにだけラベルの番号が表示されます。(枠を消したら数字も減ります)各セルにはラベルはきちんと配置されています。それをnumLabel.hidden = trueで消しておいて、セルをタッチした時にnumLabel.hidden = falseで表示させようとし考えています。なぜ最後のセルだけなのでしょうか。教えてください。よろしくお願いします。

import UIKit

class ViewController: UIViewController ,UICollectionViewDataSource, UICollectionViewDelegate{
//画像を格納する配列
var imageArray:[UIImage] = []
//番号ラベル
let numLabel: UILabel = UILabel(frame: CGRectMake(0,0,30,30))
//選択したIndexPath格納する配列
var selection: [NSIndexPath] = []
//コレクションビュー
@ IBOutlet weak var imageCollection:UICollectionView?

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

//配列imageArrayに1~6.pngの画像データを格納
for i in 1...6{
imageArray.append(UIImage(named: "\(i).png")!)
}

}

//コレクションビューのアイテム数を設定
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//戻り値にimageArrayの要素数を設定
return imageArray.count
}
//コレクションビューのセルを設定
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
//繰り返し使用することができるUICollectionViewCellのインスタンスを作成
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! UICollectionViewCell
//セルのなかの画像を表示するImageViewのタグを指定
let imageView = cell.viewWithTag(1) as! UIImageView
//セルの中のImage Viewに配列の中の画像データを表示
imageView.image = imageArray[indexPath.row]

  //ラベルの設定
// 背景を青色にする.
numLabel.backgroundColor = UIColor.blueColor()
// 文字の色を白にする.
numLabel.textColor = UIColor.whiteColor()
//文字サイズ
numLabel.font = UIFont.systemFontOfSize(12);
// Textを中央寄せにする.
numLabel.textAlignment = NSTextAlignment.Center
//ラベルを非表示にする
numLabel.hidden = true
//セルにラベルを配置
cell.addSubview(numLabel)

//設定したセルを戻り値にする
return cell
}

//セルをタップしたとき
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {

let cell = collectionView.cellForItemAtIndexPath(indexPath)!

if let index = find(selection, indexPath) {
selection.removeAtIndex(index)
} else {
selection.append(indexPath)
}

// 可視状態のセルを全て更新する
collectionView.visibleCells().map({(cell: AnyObject) -> Void in
self.updateCell(cell as! UICollectionViewCell)
})
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}


//セルの更新
func updateCell(cell: UICollectionViewCell) {

if let indexPath = self.imageCollection?.indexPathForCell(cell){

if let index = find(selection, indexPath) {
cell.contentView.layer.borderColor = UIColor.blueColor().CGColor
cell.contentView.layer.borderWidth = 4.0
numLabel.hidden = false
numLabel.text = "\(index+1)"
} else {
cell.contentView.layer.borderColor = UIColor.clearColor().CGColor
cell.contentView.layer.borderWidth = 0.0
numLabel.hidden = true
}
}

}

}

投稿日時 - 2016-01-09 00:05:34

QNo.9108345

すぐに回答ほしいです

質問者が選んだベストアンサー

No.1です。
追伸します。

元のソースコードをよく見ると、ラベルだけでなく画像を表示するためにUIImageViewをセルの中で使用していますが、おそらくこちらはstoryboardのセルにUIImageViewを貼り付け、そのUIImageViewのTagに1を設定しているのだと思います。
そして、cellForItemAtIndexPathの中で
let imageView = cell.viewWithTag(1) as! UIImageView
でセルに配置されているimageViewを取得し、imageView.imageに表示したい画像を設定してちゃんと動作しているのだと思います。

今回問題となっているラベルも、これと同じように、storyboardのセルにUILabelを貼り付け、そのUILabelのTagに2を設定し、
cellForItemAtIndexPathの中で
let label = cell.viewWithTag(2) as! UILabel
でセルに配置されているlabelを取得し、label.textに表示したい文字列を設定してもよいと思います。

ただ、タグを使う方法は、今後何か機能追加する時に融通が効きにくい(別の用途でタグが使えなくなる)ので、あまり多用せず、カスタムセルを定義する方法もマスターしておいた方がよいと思います。

ちなみに、No.1で紹介した記事はカスタムセルをxibファイルで定義していますが、xibファイルで定義しなくても、storyboardで定義したセルをカスタムセルにしてもかまいません。具体的な手順は、UICollectionViewでなくUITableViewの例になりますが、
http://development.hatenadiary.com/entry/20131228/1388218348
を参考にするとよいと思います。
UITableViewもUICollectionViewも似たようなものです。

投稿日時 - 2016-01-09 21:41:44

お礼

回答ありがとうございます。さらに詳しいアドバイスで助かりました。教えていただいたようにstoryboardを使ってタグで処理することで枠線と番号がきちんとつきました。ありがとうございました。カスタムセルについても勉強します。

投稿日時 - 2016-01-11 06:38:01

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.1

> なぜ最後のセルだけなのでしょうか。教えてください。

let numLabel: UILabel = UILabel(frame: CGRectMake(0,0,30,30))
で定義しているnumLabelはViewControllerの中で1個しか存在しないからです。

cellForItemAtIndexPathの中で
cell.addSubview(numLabel)
を実行して、全てのセルに対してnumLabelを追加しているつもりなのだと思いますが、
numLabelは1個しかないので、新しいセルにnumLabelをaddSubViewしたら、
以前にaddSubViewしたセルのnumLabelは自動的に取り除かれます。
(numLabelが以前のセルから新しいセルに移動する形になります。)
このため、最後に表示したセルにnumLabelが1個だけ残る形になります。

これを修正するには、cellForItemAtIndexPathの中で毎回新しいラベルを
確保してセルに追加すればよいという考えもありますが、それをやると、
セルを再利用した時に以前に追加したラベルにさらに追加する形になってしまいます。
その対策としてセルを再利用する時に以前に追加したラベルを削除してから
新しいラベルを追加すればうまくいきますが、結局ラベルを毎回作り直すことに
なってしまい、せっかくセルを再利用する形で設計しているのに、再利用の
意味があまりなくなってしまいます。

一般的には、セルに独自のラベルやGUI部品を追加したい場合は
カスタムセルを作ります。
具体的なやり方は
http://qiita.com/k_kuni/items/9916dab83552b77e7751
を参考にすればよいと思います。

カスタムセルの内部にラベルを定義すれば、セルの確保と同時にラベルが
作成され、セルの再利用と同時にラベルも再利用されます。

投稿日時 - 2016-01-09 15:01:17

お礼

回答ありがとうございます。

投稿日時 - 2016-01-11 06:29:42

あなたにオススメの質問