새소식

iOS/UIKit

[UIKit] Drag & Drop CollectionView Cells (코드베이스)

  • -

[참고영상]

https://youtu.be/VrW_6EixIVQ


[학습 목표]

 

Drag & Drop 기능을 이용하여서 CollectionView의 위치를 옮겨 보자!


[구현 방법]

1. 이동을 하고 옮겨지는 CollectionView를 우선 만들어보자.

import UIKit

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    private var collectionView: UICollectionView?

    var colors: [UIColor] = [
        .link,
        .systemGreen,
        .systemBlue,
        .red,
        .systemOrange,
        .black,
        .systemPurple,
        .systemYellow,
        .systemPink
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.itemSize = CGSize(width: view.frame.size.width / 3.2, height: view.frame.size.width / 3.2)
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
        collectionView?.delegate = self
        collectionView?.dataSource = self
        collectionView?.backgroundColor = .white
        view.addSubview(collectionView!)

    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView?.frame = view.bounds
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return colors.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        cell.backgroundColor = colors[indexPath.row]
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemat indexPath: IndexPath)->CGSize {
        return CGSize(width: view.frame.size.width / 3.2, height: view.frame.size.width / 3.2)
    }
}

코드베이스를 이용한 collectionView 구현이다.

실행을 할 시에는 제스처는 통하지 않는 단순한 cell들이 구현된다.

 

2. Gesture를 이제 입력시켜주자!

@objc func handleLongPressGesture( _ gesture: UILongPressGestureRecognizer){
    guard let collectionView = collectionView else{
        return
    }

    switch gesture.state {
    case .began:
        guard let targetIndexPath = collectionView.indexPathForItem(at: gesture.location(in: collectionView)) else{
            return
        }
        collectionView.beginInteractiveMovementForItem(at: targetIndexPath)
    case .changed:
        collectionView.updateInteractiveMovementTargetPosition(gesture.location(in: collectionView))
    case .ended:
        collectionView.endInteractiveMovement()
    default:
        collectionView.cancelInteractiveMovement()
    }
}

길게 눌렸을시 반응이 오는 handleLongPressGesture를 만들자.

해당 함수를 이용해서 시작할때와 중간 과정, 끝났을때와 취소했을때의 상태를 조절할 수가 있다.

 

3. 이동했을때 다른 셀들이 재배열을 하게 만드는 함수들을 만들자.

 func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
    return true
}

func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    let item = colors.remove(at: sourceIndexPath.row)
    colors.insert(item, at: destinationIndexPath.row)
}

item이라는 변수를 이용해서 우리들은 cell의 위치를 바꾸는 과정을 만들 수가 있다.

 

4. viewDidLoad 안에 넣어서 실행이 되게 해주자.

let gesture = UILongPressGestureRecognizer(target: self,
                                           action: #selector(handleLongPressGesture(_ :)))
collectionView?.addGestureRecognizer(gesture)

여태까지 만들었던 함수들을 사용하기 위해서 위의 두가지 구절을 viewDidLoad 안에 넣어주면 실행이 된다.


[전체 코드]

import UIKit

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    private var collectionView: UICollectionView?

    var colors: [UIColor] = [
        .link,
        .systemGreen,
        .systemBlue,
        .red,
        .systemOrange,
        .black,
        .systemPurple,
        .systemYellow,
        .systemPink
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.itemSize = CGSize(width: view.frame.size.width / 3.2, height: view.frame.size.width / 3.2)
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
        collectionView?.delegate = self
        collectionView?.dataSource = self
        collectionView?.backgroundColor = .white
        view.addSubview(collectionView!)

        
        let gesture = UILongPressGestureRecognizer(target: self,
                                                   action: #selector(handleLongPressGesture(_ :)))
        collectionView?.addGestureRecognizer(gesture)
    }
    
    @objc func handleLongPressGesture( _ gesture: UILongPressGestureRecognizer){
            guard let collectionView = collectionView else{
                return
            }
    
            switch gesture.state {
            case .began:
                guard let targetIndexPath = collectionView.indexPathForItem(at: gesture.location(in: collectionView)) else{
                    return
                }
                collectionView.beginInteractiveMovementForItem(at: targetIndexPath)
            case .changed:
                collectionView.updateInteractiveMovementTargetPosition(gesture.location(in: collectionView))
            case .ended:
                collectionView.endInteractiveMovement()
            default:
                collectionView.cancelInteractiveMovement()
            }
        }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView?.frame = view.bounds
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return colors.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        cell.backgroundColor = colors[indexPath.row]
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemat indexPath: IndexPath)->CGSize {
        return CGSize(width: view.frame.size.width / 3.2, height: view.frame.size.width / 3.2)
    }
    
    func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
            return true
        }
    
        func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
            let item = colors.remove(at: sourceIndexPath.row)
            colors.insert(item, at: destinationIndexPath.row)
        }
}

 

전반적으로 어려운 코드는 아니지만 생소한 부분이 많았다. 코드 베이스를 이용한 구현에 아직 익숙하지 않으니 익숙해질때까지 복습하자.

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.