develop

UITableView UICollectionView Reorder 본문

iOS

UITableView UICollectionView Reorder

pikachu987 2021. 2. 7. 21:27
반응형

Reorder기능은 셀을 터치한 다음 드래그로 셀의 위치를 바꾸는 기능이다.

 

UITableView Reorder

let tableView: UITableView = {
    let tableView = UITableView()
    return tableView
}()

var array: [UIColor] = [.blue, .red, .brown, .black, .green, .gray, .cyan, .orange, .darkGray, .lightGray, .link, .magenta, .purple, .yellow]

override func viewDidLoad() {
    super.viewDidLoad()
    
    self.view.addSubview(self.tableView)
    self.tableView.frame = self.view.frame
    
    self.tableView.register(TableViewCell.self, forCellReuseIdentifier: TableViewCell.identifier)
    self.tableView.rowHeight = 80
    self.tableView.dataSource = self
    self.tableView.reloadData()
    
    let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressGesture(_:)))
    self.tableView.addGestureRecognizer(longPressGestureRecognizer)
}

@objc func longPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
    switch gestureRecognizer.state {
    case .began:
        
    case .changed:
        
    case .ended, .cancelled, .failed, .possible:
        
    default: break
    }
}

extension ViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.array.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier, for: indexPath) as? TableViewCell else { fatalError() }
        cell.color = self.array[indexPath.row]
        return cell
    }
}

class TableViewCell: UITableViewCell {
    static let identifier = "TableViewCell"
    
    var color: UIColor? {
        didSet {
            self.colorView.backgroundColor = self.color
        }
    }
    
    var isSnapshot: Bool? {
        didSet {
            self.colorView.isHidden = self.isSnapshot ?? false
        }
    }
    
    var colorView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        self.selectionStyle = .none
        self.contentView.addSubview(self.colorView)
        self.contentView.addConstraints([
            NSLayoutConstraint(item: self.contentView, attribute: .leading, relatedBy: .equal, toItem: self.colorView, attribute: .leading, multiplier: 1, constant: -10),
            NSLayoutConstraint(item: self.contentView, attribute: .trailing, relatedBy: .equal, toItem: self.colorView, attribute: .trailing, multiplier: 1, constant: 10),
            NSLayoutConstraint(item: self.contentView, attribute: .top, relatedBy: .equal, toItem: self.colorView, attribute: .top, multiplier: 1, constant: -10),
            NSLayoutConstraint(item: self.contentView, attribute: .bottom, relatedBy: .equal, toItem: self.colorView, attribute: .bottom, multiplier: 1, constant: 10)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

 

간단하게 테이블 뷰를 만들고 셀에 넣을 UIColor 리스트를 만들었다.

그리고 추가적으로 테이블뷰에 UILongPressGestureRecognizer 를 추가하였다.

var gestureView: UIView? {
    return self.view
}

var indexPath: IndexPath?
var touchPoint: CGPoint?
var snapshotView: UIView?
var prevSnapshotPoint: CGPoint?

제스쳐뷰는 Reorder기능이 동작할 뷰이다.

네비게이션이 상위에 있으면 네비게이션의 뷰, 탭이 가장 상위에 있으면 탭의 뷰를 넣는다.

indexPath는 터치, 드래그되고 있는 indexPath를 넣을것이고 touchPoint는 셀에 터치한 포인트를 넣을 것이다.

snapshotView는 터치, 드래그중 셀을 숨김처리 하고 대신 보여줄 뷰이다.

prevSnapshotPoint는 드래그중에 위로 드래그하는지 아래로 드래그하는지 체크할수 있는 좌표값이다.

 

func began(gestureRecognizer: UILongPressGestureRecognizer) {
    let point = gestureRecognizer.location(in: self.tableView)
    guard let indexPath = self.tableView.indexPathForRow(at: point),
        let cell = self.tableView.cellForRow(at: indexPath) else { return }
    
    self.indexPath = indexPath
    
    if self.snapshotView == nil {
        let imageView = UIImageView(image: cell.imageWithView)
        imageView.layer.zPosition = 1024
        self.gestureView?.addSubview(imageView)
        self.snapshotView = imageView
    }
    
    let frame = cell.convert(cell.bounds, to: self.gestureView)
    let scale: CGFloat = 1.05
    let width = frame.size.width * scale
    let height = frame.size.height * scale
    let x = frame.origin.x - (width - frame.size.width)/2
    let y = frame.origin.y - (height - frame.size.height)/2
    
    self.snapshotView?.frame = CGRect(x: x, y: y, width: width, height: height)
    self.prevSnapshotPoint = CGPoint(x: x, y: y)
    
    if self.touchPoint == nil {
        self.touchPoint = gestureRecognizer.location(in: cell)
    }
    (cell as? TableViewCell)?.isSnapshot = true
    print("began: \(indexPath)")
}

extension UIView {
    var imageWithView: UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: self.bounds)
        return renderer.image { rendererContext in
            self.layer.render(in: rendererContext.cgContext)
        }
    }
}

GestureRecognizer로 테이블뷰에서의 좌표를 가저온 다음 좌표를 통해 IndexPath를 가져온다.

그리고 snapshotView를 만들고 셀의 이미지를 넣어준다.

그리고 snapshotView를 사용자가 인지할수 있게 확대를 해준다.

다음 셀의 colorView를 숨겨준다.

 

func changed(gestureRecognizer: UILongPressGestureRecognizer) {
    guard let touchPoint = self.touchPoint else { return }
    guard let prevSnapshotPoint = self.prevSnapshotPoint else { return }
    
    let gestureLocation = gestureRecognizer.location(in: self.gestureView)
    let tableLocation = gestureRecognizer.location(in: self.tableView)
    
    let gestureExactY = gestureLocation.y - touchPoint.y
    let tableExactY = tableLocation.y - touchPoint.y
    let isUp = prevSnapshotPoint.y - gestureExactY > 0
    
    self.prevSnapshotPoint?.y = gestureExactY
    self.snapshotView?.frame.origin.y = gestureExactY
    let height = self.snapshotView?.bounds.height ?? 0
    
    var indexPath: IndexPath?
    
    if isUp {
        if let minIndexPath = self.tableView.indexPathForRow(at: CGPoint(x: 10, y: tableExactY + (height / 3))) {
            indexPath = minIndexPath
        } else if let maxIndexPath = self.tableView.indexPathForRow(at: CGPoint(x: 10, y: tableExactY + height)) {
            indexPath = maxIndexPath
        }
    } else {
        if let minIndexPath = self.tableView.indexPathForRow(at: CGPoint(x: 10, y: tableExactY + (height / 3 * 2))) {
            indexPath = minIndexPath
        } else if let maxIndexPath = self.tableView.indexPathForRow(at: CGPoint(x: 10, y: tableExactY)) {
            indexPath = maxIndexPath
        }
    }
    
    if let beforeIndexPath = self.indexPath, let afterIndexPath = indexPath, beforeIndexPath != afterIndexPath {
        self.array.swapAt(beforeIndexPath.row, afterIndexPath.row)
        self.tableView.moveRow(at: beforeIndexPath, to: afterIndexPath)
        (self.tableView.cellForRow(at: beforeIndexPath) as? TableViewCell)?.isSnapshot = false
        (self.tableView.cellForRow(at: afterIndexPath) as? TableViewCell)?.isSnapshot = true
        print("changed: beforeIndexPath-\(beforeIndexPath), afterIndexPath-\(afterIndexPath)")
        self.indexPath = afterIndexPath
    }
}

좌표를 계산하고 올라가는지 내려가는지를 체크해서 위, 또는 아래의 셀의 3분의 1지점에서 swap를 해준다.

 

func ended(gestureRecognizer: UILongPressGestureRecognizer) {
    if let indexPath = self.indexPath {
        (self.tableView.cellForRow(at: indexPath) as? TableViewCell)?.isSnapshot = false
    }
    self.snapshotView?.removeFromSuperview()
    self.snapshotView = nil
    self.touchPoint = nil
    self.prevSnapshotPoint = nil
    self.indexPath = nil
    print("end")
}

snapshotView를 지우고 숨겼던 셀을 보여준다.

 

UITableView Reorder 전체 코드

class ViewController: UIViewController {
    let tableView: UITableView = {
        let tableView = UITableView()
        return tableView
    }()
    
    var array: [UIColor] = [.blue, .red, .brown, .black, .green, .gray, .cyan, .orange, .darkGray, .lightGray, .link, .magenta, .purple, .yellow]
    
    var gestureView: UIView? {
        return self.view
    }
    
    var indexPath: IndexPath?
    var touchPoint: CGPoint?
    var snapshotView: UIView?
    var prevSnapshotPoint: CGPoint?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.addSubview(self.tableView)
        self.tableView.frame = self.view.frame
        
        self.tableView.register(TableViewCell.self, forCellReuseIdentifier: TableViewCell.identifier)
        self.tableView.rowHeight = 80
        self.tableView.dataSource = self
        self.tableView.reloadData()
        
        let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressGesture(_:)))
        self.tableView.addGestureRecognizer(longPressGestureRecognizer)
    }
    
    @objc func longPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
        switch gestureRecognizer.state {
        case .began:
            self.began(gestureRecognizer: gestureRecognizer)
        case .changed:
            self.changed(gestureRecognizer: gestureRecognizer)
        case .ended, .cancelled, .failed, .possible:
            self.ended(gestureRecognizer: gestureRecognizer)
        default: break
        }
    }
    
    func began(gestureRecognizer: UILongPressGestureRecognizer) {
        let point = gestureRecognizer.location(in: self.tableView)
        guard let indexPath = self.tableView.indexPathForRow(at: point),
            let cell = self.tableView.cellForRow(at: indexPath) else { return }
        
        self.indexPath = indexPath
        
        if self.snapshotView == nil {
            let imageView = UIImageView(image: cell.imageWithView)
            imageView.layer.zPosition = 1024
            self.gestureView?.addSubview(imageView)
            self.snapshotView = imageView
        }
        
        let frame = cell.convert(cell.bounds, to: self.gestureView)
        let scale: CGFloat = 1.05
        let width = frame.size.width * scale
        let height = frame.size.height * scale
        let x = frame.origin.x - (width - frame.size.width)/2
        let y = frame.origin.y - (height - frame.size.height)/2
        
        self.snapshotView?.frame = CGRect(x: x, y: y, width: width, height: height)
        self.prevSnapshotPoint = CGPoint(x: x, y: y)
        
        if self.touchPoint == nil {
            self.touchPoint = gestureRecognizer.location(in: cell)
        }
        (cell as? TableViewCell)?.isSnapshot = true
        print("began: \(indexPath)")
    }
    
    func changed(gestureRecognizer: UILongPressGestureRecognizer) {
        guard let touchPoint = self.touchPoint else { return }
        guard let prevSnapshotPoint = self.prevSnapshotPoint else { return }
        
        let gestureLocation = gestureRecognizer.location(in: self.gestureView)
        let tableLocation = gestureRecognizer.location(in: self.tableView)
        
        let gestureExactY = gestureLocation.y - touchPoint.y
        let tableExactY = tableLocation.y - touchPoint.y
        let isUp = prevSnapshotPoint.y - gestureExactY > 0
        
        self.prevSnapshotPoint?.y = gestureExactY
        self.snapshotView?.frame.origin.y = gestureExactY
        let height = self.snapshotView?.bounds.height ?? 0
        
        var indexPath: IndexPath?
        
        if isUp {
            if let minIndexPath = self.tableView.indexPathForRow(at: CGPoint(x: 10, y: tableExactY + (height / 3))) {
                indexPath = minIndexPath
            } else if let maxIndexPath = self.tableView.indexPathForRow(at: CGPoint(x: 10, y: tableExactY + height)) {
                indexPath = maxIndexPath
            }
        } else {
            if let minIndexPath = self.tableView.indexPathForRow(at: CGPoint(x: 10, y: tableExactY + (height / 3 * 2))) {
                indexPath = minIndexPath
            } else if let maxIndexPath = self.tableView.indexPathForRow(at: CGPoint(x: 10, y: tableExactY)) {
                indexPath = maxIndexPath
            }
        }
        
        if let beforeIndexPath = self.indexPath, let afterIndexPath = indexPath, beforeIndexPath != afterIndexPath {
            self.array.swapAt(beforeIndexPath.row, afterIndexPath.row)
            self.tableView.moveRow(at: beforeIndexPath, to: afterIndexPath)
            (self.tableView.cellForRow(at: beforeIndexPath) as? TableViewCell)?.isSnapshot = false
            (self.tableView.cellForRow(at: afterIndexPath) as? TableViewCell)?.isSnapshot = true
            print("changed: beforeIndexPath-\(beforeIndexPath), afterIndexPath-\(afterIndexPath)")
            self.indexPath = afterIndexPath
        }
    }
    
    func ended(gestureRecognizer: UILongPressGestureRecognizer) {
        if let indexPath = self.indexPath {
            (self.tableView.cellForRow(at: indexPath) as? TableViewCell)?.isSnapshot = false
        }
        self.snapshotView?.removeFromSuperview()
        self.snapshotView = nil
        self.touchPoint = nil
        self.prevSnapshotPoint = nil
        self.indexPath = nil
        print("end")
    }
}

extension ViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.array.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier, for: indexPath) as? TableViewCell else { fatalError() }
        cell.color = self.array[indexPath.row]
        return cell
    }
}

class TableViewCell: UITableViewCell {
    static let identifier = "TableViewCell"
    
    var color: UIColor? {
        didSet {
            self.colorView.backgroundColor = self.color
        }
    }
    
    var isSnapshot: Bool? {
        didSet {
            self.colorView.isHidden = self.isSnapshot ?? false
        }
    }
    
    var colorView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        self.selectionStyle = .none
        self.contentView.addSubview(self.colorView)
        self.contentView.addConstraints([
            NSLayoutConstraint(item: self.contentView, attribute: .leading, relatedBy: .equal, toItem: self.colorView, attribute: .leading, multiplier: 1, constant: -10),
            NSLayoutConstraint(item: self.contentView, attribute: .trailing, relatedBy: .equal, toItem: self.colorView, attribute: .trailing, multiplier: 1, constant: 10),
            NSLayoutConstraint(item: self.contentView, attribute: .top, relatedBy: .equal, toItem: self.colorView, attribute: .top, multiplier: 1, constant: -10),
            NSLayoutConstraint(item: self.contentView, attribute: .bottom, relatedBy: .equal, toItem: self.colorView, attribute: .bottom, multiplier: 1, constant: 10)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension UIView {
    var imageWithView: UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: self.bounds)
        return renderer.image { rendererContext in
            self.layer.render(in: rendererContext.cgContext)
        }
    }
}

 

UICollectionView Reorder

UICollectionView의 Reorder는 UITableView의 Reorder과 크게 다른점이 없다.

UICollectionView의 메서드 이름들이 달라진다.

그리고 UICollectionView는 Y좌표 뿐만 아니라 X좌표도 변하게 된다.

X좌표를 추가적으로 계산해서 구현해준다.

let minY = isUp ? viewExactPoint.y + (height / 3) : viewExactPoint.y + (height / 3 * 2)
let maxY = isUp ? viewExactPoint.y + height : viewExactPoint.y
let minX = isLeft ? viewExactPoint.x + (width / 3) : viewExactPoint.x + (width / 3 * 2)
let maxX = isLeft ? viewExactPoint.x + width : viewExactPoint.x

if let minIndexPath = self.collectionView.indexPathForItem(at: CGPoint(x: minX, y: minY)) {
    indexPath = minIndexPath
} else if let maxIndexPath = self.collectionView.indexPathForItem(at: CGPoint(x: maxX, y: maxY)) {
    indexPath = maxIndexPath
}

그리고 moveItem 또는 moveRow와 array의 swap함수가 로직적으로 다르다.

테이블뷰에서는 moveRow와 array의 swap이 한칸한칸 바뀌는 거라 동일하게 작동하지만

콜렉션뷰에서는 y좌표를 움직일때 moveItem 은 동일 x좌표에 있는 셀들의 index가 변하게 된다.

let beforeItem = self.array.remove(at: beforeIndexPath.row)
self.array.insert(beforeItem, at: afterIndexPath.row)
self.collectionView.moveItem(at: beforeIndexPath, to: afterIndexPath)
(self.collectionView.cellForItem(at: beforeIndexPath) as? CollectionViewCell)?.isSnapshot = false
(self.collectionView.cellForItem(at: afterIndexPath) as? CollectionViewCell)?.isSnapshot = true
print("changed: beforeIndexPath-\(beforeIndexPath), afterIndexPath-\(afterIndexPath)")
self.indexPath = afterIndexPath

이 두가지 외에는 UITableView와 UICollectionView의 기본적인 메서드, 변수명만 변한다.

 

UICollectionView Reorder 전체 코드

class ViewController: UIViewController {
    let collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: (UIScreen.main.bounds.width/3) - 20, height: 80)
        layout.minimumLineSpacing = 10
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.backgroundColor = .white
        return collectionView
    }()
    
    var array: [UIColor] = [.blue, .red, .brown, .black, .green, .gray, .cyan, .orange, .darkGray, .lightGray, .link, .magenta, .purple, .yellow, UIColor(white: 99/255, alpha: 1), UIColor(white: 44/255, alpha: 1), UIColor(white: 124/255, alpha: 1), UIColor(white: 180/255, alpha: 1)]
    
    var gestureView: UIView? {
        return self.view
    }
    
    var indexPath: IndexPath?
    var touchPoint: CGPoint?
    var snapshotView: UIView?
    var prevSnapshotPoint: CGPoint?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.addSubview(self.collectionView)
        self.collectionView.frame = self.view.frame
        
        self.collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: CollectionViewCell.identifier)
        self.collectionView.dataSource = self
        self.collectionView.reloadData()
        
        let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressGesture(_:)))
        self.collectionView.addGestureRecognizer(longPressGestureRecognizer)
    }
    
    @objc func longPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
        switch gestureRecognizer.state {
        case .began:
            self.began(gestureRecognizer: gestureRecognizer)
        case .changed:
            self.changed(gestureRecognizer: gestureRecognizer)
        case .ended, .cancelled, .failed, .possible:
            self.ended(gestureRecognizer: gestureRecognizer)
        default: break
        }
    }
    
    func began(gestureRecognizer: UILongPressGestureRecognizer) {
        let point = gestureRecognizer.location(in: self.collectionView)
        guard let indexPath = self.collectionView.indexPathForItem(at: point),
            let cell = self.collectionView.cellForItem(at: indexPath) else { return }

        self.indexPath = indexPath

        if self.snapshotView == nil {
            let imageView = UIImageView(image: cell.imageWithView)
            imageView.layer.zPosition = 1024
            self.gestureView?.addSubview(imageView)
            self.snapshotView = imageView
        }

        let frame = cell.convert(cell.bounds, to: self.gestureView)
        let scale: CGFloat = 1.05
        let width = frame.size.width * scale
        let height = frame.size.height * scale
        let x = frame.origin.x - (width - frame.size.width)/2
        let y = frame.origin.y - (height - frame.size.height)/2

        self.snapshotView?.frame = CGRect(x: x, y: y, width: width, height: height)
        self.prevSnapshotPoint = CGPoint(x: x, y: y)

        if self.touchPoint == nil {
            self.touchPoint = gestureRecognizer.location(in: cell)
        }
        (cell as? CollectionViewCell)?.isSnapshot = true
        print("began: \(indexPath)")
    }

    func changed(gestureRecognizer: UILongPressGestureRecognizer) {
        guard let touchPoint = self.touchPoint else { return }
        guard let prevSnapshotPoint = self.prevSnapshotPoint else { return }

        let gestureLocation = gestureRecognizer.location(in: self.gestureView)
        let viewLocation = gestureRecognizer.location(in: self.collectionView)

        let gestureExactPoint = CGPoint(x: gestureLocation.x - touchPoint.x, y: gestureLocation.y - touchPoint.y)
        let viewExactPoint = CGPoint(x: viewLocation.x - touchPoint.x, y: viewLocation.y - touchPoint.y)
        let isUp = prevSnapshotPoint.y - gestureExactPoint.y > 0
        let isLeft = prevSnapshotPoint.x - gestureExactPoint.x > 0
        
        self.prevSnapshotPoint?.x = gestureExactPoint.x
        self.prevSnapshotPoint?.y = gestureExactPoint.y
        self.snapshotView?.frame.origin.x = gestureExactPoint.x
        self.snapshotView?.frame.origin.y = gestureExactPoint.y
        
        let width = self.snapshotView?.bounds.width ?? 0
        let height = self.snapshotView?.bounds.height ?? 0

        var indexPath: IndexPath?
        
        let minY = isUp ? viewExactPoint.y + (height / 3) : viewExactPoint.y + (height / 3 * 2)
        let maxY = isUp ? viewExactPoint.y + height : viewExactPoint.y
        let minX = isLeft ? viewExactPoint.x + (width / 3) : viewExactPoint.x + (width / 3 * 2)
        let maxX = isLeft ? viewExactPoint.x + width : viewExactPoint.x
        
        if let minIndexPath = self.collectionView.indexPathForItem(at: CGPoint(x: minX, y: minY)) {
            indexPath = minIndexPath
        } else if let maxIndexPath = self.collectionView.indexPathForItem(at: CGPoint(x: maxX, y: maxY)) {
            indexPath = maxIndexPath
        }

        if let beforeIndexPath = self.indexPath, let afterIndexPath = indexPath, beforeIndexPath != afterIndexPath {
            let beforeItem = self.array.remove(at: beforeIndexPath.row)
            self.array.insert(beforeItem, at: afterIndexPath.row)
            self.collectionView.moveItem(at: beforeIndexPath, to: afterIndexPath)
            (self.collectionView.cellForItem(at: beforeIndexPath) as? CollectionViewCell)?.isSnapshot = false
            (self.collectionView.cellForItem(at: afterIndexPath) as? CollectionViewCell)?.isSnapshot = true
            print("changed: beforeIndexPath-\(beforeIndexPath), afterIndexPath-\(afterIndexPath)")
            self.indexPath = afterIndexPath
        }
    }

    func ended(gestureRecognizer: UILongPressGestureRecognizer) {
        if let indexPath = self.indexPath {
            (self.collectionView.cellForItem(at: indexPath) as? CollectionViewCell)?.isSnapshot = false
        }
        self.snapshotView?.removeFromSuperview()
        self.snapshotView = nil
        self.touchPoint = nil
        self.prevSnapshotPoint = nil
        self.indexPath = nil
        print("end")
    }
}

extension ViewController: UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.array.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.identifier, for: indexPath) as? CollectionViewCell else { fatalError() }
        cell.color = self.array[indexPath.row]
        return cell
    }
}

class CollectionViewCell: UICollectionViewCell {
    static let identifier = "CollectionViewCell"
    
    var color: UIColor? {
        didSet {
            self.colorView.backgroundColor = self.color
        }
    }
    
    var isSnapshot: Bool? {
        didSet {
            self.colorView.isHidden = self.isSnapshot ?? false
        }
    }
    
    var colorView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.contentView.addSubview(self.colorView)
        self.contentView.addConstraints([
            NSLayoutConstraint(item: self.contentView, attribute: .leading, relatedBy: .equal, toItem: self.colorView, attribute: .leading, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: self.contentView, attribute: .trailing, relatedBy: .equal, toItem: self.colorView, attribute: .trailing, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: self.contentView, attribute: .top, relatedBy: .equal, toItem: self.colorView, attribute: .top, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: self.contentView, attribute: .bottom, relatedBy: .equal, toItem: self.colorView, attribute: .bottom, multiplier: 1, constant: 0)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension UIView {
    var imageWithView: UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: self.bounds)
        return renderer.image { rendererContext in
            self.layer.render(in: rendererContext.cgContext)
        }
    }
}
반응형

'iOS' 카테고리의 다른 글

==과 ===의 차이, closure의 ===  (0) 2021.06.22
iOS에서 srt, smi 파일 한글 깨지는 문제  (0) 2021.03.01
GCD  (0) 2021.02.06
OperationQueue  (0) 2021.02.05
Thread  (0) 2021.02.04
Comments