

現在、写真を複数選択できるImagePicker機能を作っています。

そこで、取得した写真を`UICollectionView`に表示するところまではできました。

次にやりたいことは以下の画像のように、

  1. 選択された写真に選択された順番に選択番号をつけ、もう一度タップされたら、選択番号が消える。
  2. １、２、３と番号がついたとして、２の番号の選択が消されたら、３が２になる、という実装です。

[![画像の説明をここに入力](https://i.stack.imgur.com/qGuTH.jpg)](https://i.stack.imgur.com/qGuTH.jpg)

`UICollectionViewDelegate`の`didSelectRowAtIndexPath`を使用すればよいのかなと考えましたが、選択された写真に番号をつける実装方法がわかりませんでした。

どのようにすればよいのか、教えてください。


CC BY-SA 3.0
2015-08-30T07:33:54.807
15031
2015-08-30T15:41:14.230
2015-08-30T09:13:17.307
5337
10791
question
ios swift xcode uicollectionview uicollectionviewcell
collectionViewで選択された写真に番号を振りたい


自分ならこう実装するという指針を載せてみます。

まず以下のものを用意します。

  * `UICollectionViewCell`の選択番号を更新するメソッド
  * 選択された`indexPath`を保持する配列

`collectionView(_:didSelectItemAtIndexPath:)`では、選択された`indexPath`を配列に追加します。もし既に追加されている場合は削除します。このとき同時に、`collectionView.visibleCells()`に対して選択番号の更新処理を行います。

選択番号は「配列の何番目にいるか」で決めることができます。Swift1.2であればグローバル関数の`find()`、Swift2.0であれば`CollectionType`のプロトコル拡張である`indexOf()`で求めることができます。

* * *

`collectionView.reloadData()`でも実現可能ですが、セル全体の再リロードが走るのは、恐らく意図した動作ではないと思います。`collectionView.visibleCells()`は現在可視状態にあるセルを取得できますので、それら全てに対して選択番号の更新を行うのが良いです。

* * *

**追記:** コード例（Swift2.0）

[code]

    var selection: [NSIndexPath] = []
    
    override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        // もしselection配列に存在すれば追加、そうでなければ削除
        if let index = selection.indexOf(indexPath) {
            selection.removeAtIndex(index)
        } else {
            selection.append(indexPath)
        }
    
        // 可視状態のセルを全て更新する
        collectionView.visibleCells().map {updateCell($0)}
    
        collectionView.deselectItemAtIndexPath(indexPath, animated: true)
    }
    
    func updateCell(cell: UICollectionViewCell) {
        // indexPathをCellから逆引きする、なければreturn
        guard let indexPath = self.collectionView?.indexPathForCell(cell) else {
            return
        }
        // 選択番号用のUILabelをCellから取得
        let numLabel: UILabel = cell.viewWithTag(NUMBER_LABEL) as! UILabel
        // 配列内にindexPathがあれば選択番号と枠を表示、そうでなければ非表示
        if let index = selection.indexOf(indexPath) {
            cell.contentView.layer.borderColor = UIColor.blueColor().CGColor
            cell.contentView.layer.borderWidth = 4.0
            numLabel.hidden = false
            // 検索結果のインデックス + 1 が選択番号として使える
            numLabel.text = "\(index+1)"
        } else {
            cell.contentView.layer.borderColor = UIColor.clearColor().CGColor
            cell.contentView.layer.borderWidth = 0.0
            numLabel.hidden = true
        }
    }
    
[/code]

* * *

**再追記** :Swift1.2の場合（やや忘れかけ）

[code]

    var selection: [NSIndexPath] = []
    
    override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        if let index = find(selection, indexPath) {
            selection.removeAtIndex(index)
        } else {
            selection.append(indexPath)
        }
    
        // 可視状態のセルを全て更新する（普通にforループでも良いです！）
        collectionView.visibleCells().map({(cell: AnyObject) -> Void in
            self.updateCell(cell as! UICollectionViewCell)
        })
    }
    
    func updateCell(cell: UICollectionViewCell) {
        let numLabel: UILabel = cell.viewWithTag(NUMBER_LABEL) as! UILabel        
        if let indexPath = self.collectionView?.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
            }
        }
    }
    
[/code]


CC BY-SA 3.0
2015-08-30T09:34:51.777
15032
2015-08-30T15:41:14.230
2015-08-30T15:41:14.230
5337
5337
15031
answer